Skip to content

Commit abb27a3

Browse files
Add maxInstances alongside maxSleepingInstances in LauncherConfig v1alpha1 (llm-d-incubation#487)
Stage A of the staged rename of MaxSleepingInstances -> MaxInstances (see llm-d-incubation#471). Purely additive within v1alpha1: existing clients that set maxSleepingInstances (including zero) continue to work unchanged. - LauncherConfigSpec: add MaxInstances (optional, min 0). Relax MaxSleepingInstances to optional with min 0 and rewrite its doc to state the observable +1 semantics without naming an enforcing component. Deprecate MaxSleepingInstances in favor of MaxInstances. - Add a CRD-level CEL rule forbidding only the ambiguous case where both fields are positive. - dual-pods controller: add effectiveMaxInstances(lc) returning MaxInstances when positive, else MaxSleepingInstances+1. Both callsites in inference-server.go now pass effectiveMaxInstances(lc)-1. Numeric behavior is unchanged when only maxSleepingInstances is set. - Regenerate CRD manifest and applyconfiguration. Resolves llm-d-incubation#482. Signed-off-by: Mike Spreitzer <mspreitz@us.ibm.com>
1 parent a8111c6 commit abb27a3

4 files changed

Lines changed: 55 additions & 8 deletions

File tree

api/fma/v1alpha1/launcherconfig_types.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,28 @@ type EmbeddedPodTemplateSpec struct {
4545
}
4646

4747
// LauncherConfigSpec defines the configuration to manage the nominal server-providing pod definition.
48+
// At most one of `maxSleepingInstances` and `maxInstances` may be positive; setting both to positive
49+
// values is rejected. Either may be zero or omitted.
50+
// +kubebuilder:validation:XValidation:rule="!(has(self.maxInstances) && has(self.maxSleepingInstances) && self.maxInstances > 0 && self.maxSleepingInstances > 0)",message="maxInstances and maxSleepingInstances must not both be positive"
4851
type LauncherConfigSpec struct {
4952
// PodTemplate defines the pod specification for the server-providing pod.
5053
// +optional
5154
PodTemplate EmbeddedPodTemplateSpec `json:"podTemplate,omitempty"`
5255

53-
// MaxSleepingInstances is the maximum number of sleeping inference engine instances allowed per launcher pod.
54-
// +kubebuilder:validation:Required
56+
// MaxSleepingInstances caps the number of sleeping inference-engine instances per launcher pod
57+
// when an awake instance is also present. When no instance is awake, one additional sleeping
58+
// instance is permitted — i.e., a launcher pod can hold up to `MaxSleepingInstances + 1`
59+
// instances in total.
60+
// Deprecated: use MaxInstances, which simply caps the total number of instances per launcher pod.
61+
// +optional
62+
// +kubebuilder:validation:Minimum=0
5563
MaxSleepingInstances int32 `json:"maxSleepingInstances,omitempty"`
64+
65+
// MaxInstances caps the total number of inference-engine instances per launcher pod.
66+
// A value of zero means unset.
67+
// +optional
68+
// +kubebuilder:validation:Minimum=0
69+
MaxInstances int32 `json:"maxInstances,omitempty"`
5670
}
5771

5872
// LauncherConfigStatus represents the current status

config/crd/fma.llm-d.ai_launcherconfigs.yaml

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,22 @@ spec:
4343
spec:
4444
description: Spec defines the desired state of the LauncherConfig.
4545
properties:
46+
maxInstances:
47+
description: |-
48+
MaxInstances caps the total number of inference-engine instances per launcher pod.
49+
A value of zero means unset.
50+
format: int32
51+
minimum: 0
52+
type: integer
4653
maxSleepingInstances:
47-
description: MaxSleepingInstances is the maximum number of sleeping
48-
inference engine instances allowed per launcher pod.
54+
description: |-
55+
MaxSleepingInstances caps the number of sleeping inference-engine instances per launcher pod
56+
when an awake instance is also present. When no instance is awake, one additional sleeping
57+
instance is permitted — i.e., a launcher pod can hold up to `MaxSleepingInstances + 1`
58+
instances in total.
59+
Deprecated: use MaxInstances, which simply caps the total number of instances per launcher pod.
4960
format: int32
61+
minimum: 0
5062
type: integer
5163
podTemplate:
5264
description: PodTemplate defines the pod specification for the server-providing
@@ -8473,9 +8485,11 @@ spec:
84738485
- containers
84748486
type: object
84758487
type: object
8476-
required:
8477-
- maxSleepingInstances
84788488
type: object
8489+
x-kubernetes-validations:
8490+
- message: maxInstances and maxSleepingInstances must not both be positive
8491+
rule: '!(has(self.maxInstances) && has(self.maxSleepingInstances) &&
8492+
self.maxInstances > 0 && self.maxSleepingInstances > 0)'
84798493
status:
84808494
description: Status represents the observed status of the LauncherConfig.
84818495
properties:

pkg/controller/dual-pods/inference-server.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,7 @@ func (item infSvrItem) process(urCtx context.Context, ctl *controller, nodeDat *
626626
// then those with capacity for new instances.
627627
// Note that multiple vLLM instances could exist in one launcher Pod, but at most one instance could be awake at a time.
628628

629-
launcherPod, hasSleepingInstance, someNotReady, err := ctl.selectBestLauncherPod(ctx, launcherPodAnys, iscHash, desiredPort, int(lc.Spec.MaxSleepingInstances), nodeDat)
629+
launcherPod, hasSleepingInstance, someNotReady, err := ctl.selectBestLauncherPod(ctx, launcherPodAnys, iscHash, desiredPort, effectiveMaxInstances(lc)-1, nodeDat)
630630
if err != nil {
631631
return err, true
632632
}
@@ -648,7 +648,7 @@ func (item infSvrItem) process(urCtx context.Context, ctl *controller, nodeDat *
648648
// Remains: Zero matching launcher Pods, or the matching launcher Pod cannot host more instances to fulfill the request.
649649

650650
// TODO(waltforme): enforceSleeperBudget should be revised for launcher-based server-providing Pods
651-
err, retry := ctl.enforceSleeperBudget(ctx, serverDat, requestingPod, int(lc.Spec.MaxSleepingInstances))
651+
err, retry := ctl.enforceSleeperBudget(ctx, serverDat, requestingPod, effectiveMaxInstances(lc)-1)
652652
if err != nil || retry {
653653
return err, retry
654654
}
@@ -796,6 +796,16 @@ func (ctl *controller) selectBestLauncherPod(
796796
return nil, false, false, nil
797797
}
798798

799+
// effectiveMaxInstances returns the cap on the total number of inference-engine instances
800+
// per launcher pod. If MaxInstances is positive, it is used directly; otherwise the legacy
801+
// MaxSleepingInstances semantics apply and the cap is MaxSleepingInstances + 1.
802+
func effectiveMaxInstances(lc *fmav1alpha1.LauncherConfig) int {
803+
if lc.Spec.MaxInstances > 0 {
804+
return int(lc.Spec.MaxInstances)
805+
}
806+
return int(lc.Spec.MaxSleepingInstances) + 1
807+
}
808+
799809
// configInferenceServer computes the VllmConfig.
800810
// `isc` and `gpuUUIDs` are deeply immutable.
801811
// The result is deeply immutable.

pkg/generated/applyconfiguration/fma/v1alpha1/launcherconfigspec.go

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)