apiVersion: v1 kind: ConfigMap # This ConfigMap defines saturation-based scaling thresholds for model variants. # Saturation scaling is enabled by default and uses KV cache utilization and queue length # metrics to determine when replicas are saturated and when to scale up. # # Configuration structure: # - 'default' entry: Global default thresholds applied to all variants # - Override entries: Per-model/namespace custom thresholds (must include model_id and namespace) # # Threshold definitions: # - kvCacheThreshold: Replica saturated if KV cache utilization >= threshold (0.0-1.0) # - queueLengthThreshold: Replica saturated if queue length >= threshold (integer) # - kvSpareTrigger: Scale-up signal if avg spare KV capacity < trigger (0.0-1.0) # - queueSpareTrigger: Scale-up signal if avg spare queue capacity < trigger (integer) # metadata: name: wva-saturation-scaling-config namespace: workload-variant-autoscaler-system labels: app.kubernetes.io/name: workload-variant-autoscaler app.kubernetes.io/managed-by: kustomize data: # Global defaults applied to all variants unless overridden. # # The `analyzers` section selects the V2 (token/capacity-based) saturation # analyzer — the default since v0.9.0. Remove the `analyzers` section (and the # V2-only thresholds) to opt out to the legacy V1 (percentage-based) analyzer. # See docs/developer-guide/saturation-scaling-config.md. # # Each analyzer accepts the ScalingPolicy plugin envelope (proposal #1245): # analyzers: # - type: saturation # plugin type; `name:` still works as an alias # parameters: { scaleUpThreshold: 0.90 } default: | analyzers: - name: saturation score: 1.0 # V2-only thresholds: scaleUpThreshold: 0.85 scaleDownBoundary: 0.70 # Shared by V1 and V2: kvCacheThreshold: 0.80 queueLengthThreshold: 5 # V1-only (ignored by V2): kvSpareTrigger: 0.1 queueSpareTrigger: 3 # Enable GPU limiter to constrain scaling based on available cluster resources # When true, scale-up decisions are limited by available GPU capacity enableLimiter: false # Enable priority-weighted rescale: under GPU contention the V2 optimizer # redistributes the whole budget by priority x demand, reclaiming from # lower-priority models so higher-priority work can run. Off by default. # Budget-scope flag (read only from this `default` entry): the value here # governs the cluster budget; a namespace-local config's `default` governs # that namespace's quota budget. Has no effect without a same-scope GPU budget. enableRescale: false # Per-model overrides inherit the default's analyzer selection (V2) via # field-level merge, so they only need the thresholds they change. Under V2, # kvCacheThreshold/queueLengthThreshold apply; kvSpareTrigger/queueSpareTrigger # are V1-only and are ignored (they take effect only if the default is opted # back to V1 by removing its `analyzers:` section). # An override entry's DATA KEY must be "{modelID}#{namespace}" — the engine looks # up overrides by that key; the inner model_id/namespace fields are informational. # Example per-model override for granite model in lab namespace # Uncomment and customize as needed # "ibm/granite-13b#lab-namespace": | # model_id: ibm/granite-13b # namespace: lab-namespace # kvCacheThreshold: 0.75 # queueLengthThreshold: 10 # Example per-model override for llama model in production namespace # Shows partial override (only some fields specified, rest inherit from default) # Uses the plugin envelope for the analyzer and an inline scale-to-zero setting # (which overrides the wva-model-scale-to-zero-config ConfigMap for this model). # "meta/llama-70b#production": | # model_id: meta/llama-70b # namespace: production # priority: 2.0 # scaleToZero: { enabled: false } # analyzers: # - type: saturation # parameters: { scaleUpThreshold: 0.90 } # Cluster GPU limiter — the sole source that selects the limiter, applied live # (no restart) and honored ONLY on the `default` entry above (a cluster-budget # scope, like enableRescale). A limiters list selects a SINGLE mode: a quota # entry wins over any gpu-inventory entry, so add ONE of the forms below to the # `default` entry. With no limiters: declared, the physical-inventory limiter is # used. # # # (a) physical-capacity limiter: # limiters: # - type: gpu-inventory # # # (b) operator-declared quota limiter: # limiters: # - type: quota # name: cluster-h100 # scope: cluster # quotas: { H100: 32 }