Add config exmaples to README for resource reservations on node level

Fixes: #373
This commit is contained in:
gyptazy
2025-12-23 15:24:02 +01:00
parent 2ce3d73262
commit 89ad425243
6 changed files with 23 additions and 33 deletions

View File

@@ -0,0 +1,2 @@
added:
- Add resource reservation support for PVE nodes (@Chipmonk2). [#373]

4
.gitignore vendored
View File

@@ -5,7 +5,3 @@ build/
dist/ dist/
*.egg-info/ *.egg-info/
proxlb_dev.yaml proxlb_dev.yaml
log.log
proxlb/log.log
proxlb.yaml
proxlb_reservation.yaml

View File

@@ -290,6 +290,7 @@ The following options can be set in the configuration file `proxlb.yaml`:
| | method | | memory | `Str` | The balancing method that should be used. [values: `memory` (default), `cpu`, `disk`]| | | method | | memory | `Str` | The balancing method that should be used. [values: `memory` (default), `cpu`, `disk`]|
| | mode | | used | `Str` | The balancing mode that should be used. [values: `used` (default), `assigned`, `psi` (pressure)] | | | mode | | used | `Str` | The balancing mode that should be used. [values: `used` (default), `assigned`, `psi` (pressure)] |
| | balance_larger_guests_first | | False | `Bool` | Option to prefer larger/smaller guests first | | | balance_larger_guests_first | | False | `Bool` | Option to prefer larger/smaller guests first |
| | node_resource_reserve | | { default: { memory: 4 }, { node01: { memory: 6 }} } | `Dict` | A dict of pool names and their type for creating affinity/anti-affinity rules |
| | psi | | { nodes: { memory: { pressure_full: 0.20, pressure_some: 0.20, pressure_spikes: 1.00 }}} | `Dict` | A dict of PSI based thresholds for nodes and guests | | | psi | | { nodes: { memory: { pressure_full: 0.20, pressure_some: 0.20, pressure_spikes: 1.00 }}} | `Dict` | A dict of PSI based thresholds for nodes and guests |
| | pools | | pools: { dev: { type: affinity }, de-nbg01-db: { type: anti-affinity }} | `Dict` | A dict of pool names and their type for creating affinity/anti-affinity rules | | | pools | | pools: { dev: { type: affinity }, de-nbg01-db: { type: anti-affinity }} | `Dict` | A dict of pool names and their type for creating affinity/anti-affinity rules |
| `service` | | | | | | | `service` | | | | | |
@@ -338,6 +339,11 @@ balancing:
method: memory method: memory
mode: used mode: used
balance_larger_guests_first: False balance_larger_guests_first: False
node_resource_reserve:
defaults:
memory: 4
node01:
memory: 6
# # PSI thresholds only apply when using mode 'psi' # # PSI thresholds only apply when using mode 'psi'
# # PSI based balancing is currently in beta and req. PVE >= 9 # # PSI based balancing is currently in beta and req. PVE >= 9
# psi: # psi:
@@ -530,7 +536,7 @@ Connect with us in our dedicated chat room for immediate support and live intera
| Support Channel | Link | | Support Channel | Link |
|------|:------:| |------|:------:|
| Matrix | [#proxlb:gyptazy.com](https://matrix.to/#/#proxlb:gyptazy.com) | | Matrix | [#proxlb:gyptazy.com](https://matrix.to/#/#proxlb:gyptazy.com) |
| Discord | [Discord](https://discord.gg/JemGu7WbfQ) | | Discord | [Discord](https://discord.gg/JemGu7WbfQ) |
| GitHub Community | [GitHub Community](https://github.com/gyptazy/ProxLB/discussions/) | GitHub Community | [GitHub Community](https://github.com/gyptazy/ProxLB/discussions/)
| GitHub | [ProxLB GitHub](https://github.com/gyptazy/ProxLB/issues) | | GitHub | [ProxLB GitHub](https://github.com/gyptazy/ProxLB/issues) |

View File

@@ -33,6 +33,11 @@ balancing:
method: memory # 'memory' | 'cpu' | 'disk' method: memory # 'memory' | 'cpu' | 'disk'
mode: used # 'assigned' | 'used' | 'psi' mode: used # 'assigned' | 'used' | 'psi'
balance_larger_guests_first: False # Option to prioritize balancing of larger or smaller guests first balance_larger_guests_first: False # Option to prioritize balancing of larger or smaller guests first
node_resource_reserve: # Optional: Define resource reservations for nodes (in GB)
defaults: # Default reservation values applying to all nodes (unless explicitly overridden)
memory: 4 # Default: 4 GB memory reserved per node
node01: # Specific node reservation override for node 'node01'
memory: 6 # Specific: 6 GB memory reserved for node 'node01'
# # PSI thresholds only apply when using mode 'psi' # # PSI thresholds only apply when using mode 'psi'
# psi: # psi:
# nodes: # nodes:
@@ -69,15 +74,6 @@ balancing:
pin: # Define a pinning og guests to specific node(s) pin: # Define a pinning og guests to specific node(s)
- virt66 - virt66
- virt77 - virt77
# reserve some ressource for proxmox and / or other application on the nodes
node_resource_reserve:
# defaults - cpu in %, memory in GB, disk in %
defaults:
cpu: 10
memory: 4
disk: 20
node1:
memory: 4
service: service:
daemon: True daemon: True

View File

@@ -256,7 +256,6 @@ class Nodes:
logger.debug("Finished: get_node_pve_version.") logger.debug("Finished: get_node_pve_version.")
return version["version"] return version["version"]
@staticmethod @staticmethod
def apply_resource_reservation(node_name, proxlb_config: Dict[str, Any], node_data: Dict[str, Any]) -> None: def apply_resource_reservation(node_name, proxlb_config: Dict[str, Any], node_data: Dict[str, Any]) -> None:
""" """
@@ -264,24 +263,19 @@ class Nodes:
Checks for a node specific config first, then if there is any configured default and if neither then nothing is reserved. Checks for a node specific config first, then if there is any configured default and if neither then nothing is reserved.
Reservations are applied by directly modifying the data gathered from the nodes. Reservations are applied by directly modifying the data gathered from the nodes.
Args: Args:
node_name: (str) the name of the node node_name: (str) the name of the node
proxlb_config (Dict[str, Any]): A dictionary containing the ProxLB configuration. proxlb_config (Dict[str, Any]): A dictionary containing the ProxLB configuration.
node_data: (Dict[str, Any]): Dict containing the current nodes data node_data: (Dict[str, Any]): Dict containing the current nodes data
Returns: none Returns: none
""" """
logger.debug(f"Starting: Resource reservation") logger.debug(f"Starting: apply_resource_reservation")
logger.debug(f"Processing resource reservation for node {node_name}")
# load the balancing section from the config dict, will create an empty dict if there isnt anything
balancing_cfg = proxlb_config.get("balancing", {}) balancing_cfg = proxlb_config.get("balancing", {})
# get the reservation dict from the previously loaded dict , will create an empty dict if there isnt anything reserve_cfg = balancing_cfg.get("node_resource_reserve", {})
reserve_cfg = balancing_cfg.get("node_resource_reserve", {})
# try to get the reserved memory for the node
reserved_memory_gb_node = reserve_cfg.get(node_name, {}).get("memory") reserved_memory_gb_node = reserve_cfg.get(node_name, {}).get("memory")
# try to load the default reserved memory - will set to 0 if there isn't anything
reserved_memory_gb_default = reserve_cfg.get("defaults", {}).get("memory", 0) reserved_memory_gb_default = reserve_cfg.get("defaults", {}).get("memory", 0)
# make sure the reservation is a numeric value - check for both, default and node specific # Make sure the reservation is a numeric value - check for both, default and node specific
if not isinstance(reserved_memory_gb_default, (int, float)): if not isinstance(reserved_memory_gb_default, (int, float)):
if reserved_memory_gb_default is not None: if reserved_memory_gb_default is not None:
logger.info("Invalid default memory reservation: Found a string while expecting a numeric value - skipping default reservation") logger.info("Invalid default memory reservation: Found a string while expecting a numeric value - skipping default reservation")
@@ -292,16 +286,16 @@ class Nodes:
logger.info(f"Invalid memory reservation: Found a string while expecting a numeric value - applying current default of {reserved_memory_gb_default} Bytes") logger.info(f"Invalid memory reservation: Found a string while expecting a numeric value - applying current default of {reserved_memory_gb_default} Bytes")
reserved_memory_gb_node = reserved_memory_gb_default reserved_memory_gb_node = reserved_memory_gb_default
# make sure the reservation is positive # Make sure the reservation is positive
if reserved_memory_gb_node < 0: if reserved_memory_gb_node < 0:
logger.info(f"{nodes['nodes'][node['node']]['name']}: Invalid assigned memory reservation, applying defaults") logger.info(f"{nodes['nodes'][node['node']]['name']}: Invalid assigned memory reservation, applying defaults")
reserved_memory_gb_node = reserved_memory_gb_default reserved_memory_gb_node = reserved_memory_gb_default
# convert the reservation from GB to Bytes, get the current nodes physical memory # Convert the reservation from GB to Bytes, get the current nodes physical memory
reserved_memory_node = int(round(reserved_memory_gb_node * 1024 ** 3)) reserved_memory_node = int(round(reserved_memory_gb_node * 1024 ** 3))
total_mem = node_data.get("memory_total") total_mem = node_data.get("memory_total")
# check if the reservation doesnt exceed the nodes total memory # Check if the reservation doesnt exceed the nodes total memory
if reserved_memory_node > total_mem: if reserved_memory_node > total_mem:
logger.debug(f"Reservation of {reserved_memory_node} Bytes exceeds available memory of {total_mem} Bytes- skipping reservation") logger.debug(f"Reservation of {reserved_memory_node} Bytes exceeds available memory of {total_mem} Bytes- skipping reservation")
reserved_memory_node = 0 reserved_memory_node = 0
@@ -310,7 +304,4 @@ class Nodes:
logger.debug(f"Reserved Memory: {reserved_memory_gb_node} GB ({reserved_memory_node} Bytes)") logger.debug(f"Reserved Memory: {reserved_memory_gb_node} GB ({reserved_memory_node} Bytes)")
node_data["memory_total"] -= reserved_memory_node node_data["memory_total"] -= reserved_memory_node
Helper.update_node_resource_percentages(node_data) Helper.update_node_resource_percentages(node_data)
logger.debug(f"Finished: apply_resource_reservation")
logger.debug(f"End: Resource reservation")
return

View File

@@ -362,4 +362,3 @@ class Helper:
logger.debug(f"node data: {node_data}") logger.debug(f"node data: {node_data}")
logger.debug(f"End: Update resource percentages") logger.debug(f"End: Update resource percentages")
return return