Checklist
Motivation
Checklist:
Motivation:
CustomComponentsPattern is the most flexible pattern for heterogeneous,multi-pod-per-replica workloads. It is the right abstraction for topologies such as Router -> Leader -> Worker or Leader/Worker -> Router, where each component has a different startup dependency and needs to discover peer components in the same RoleInstance.
Today users can describe the components, but production inference topologies also need two controller-managed behaviors:
-
Component lifecycle ordering inside one CustomComponentsPattern role.
A component should be created only after its dependencies are ready.For example, a router can wait for leader and worker components before it starts, or a worker can wait for a leader. Scale-down should respect the reverse order or an explicit deleteAfter order.
-
Intra-role service discovery for sibling components.
A component should be able to receive peer component pod FQDNs and allocated port values as environment variables, without hard-coding generated pod names or duplicating controller naming logic in user manifests.
Proposed API:
Use component-level annotations on CustomComponentsPattern components:
Example:
customComponentsPattern:
components:
- name: leader
size: 1
annotations:
rolebasedgroup.workloads.x-k8s.io/port-allocator: |
{"allocations":[{"name":"leader-grpc","env":"LEADER_GRPC_PORT","scope":"RoleScoped"}]}
template:
spec:
containers:
- name: leader
image: anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis/nginx:1.14.1-8.6
- name: worker
size: 2
annotations:
rolebasedgroup.workloads.x-k8s.io/component-depends-on: |
{"startAfter":["leader"]}
rolebasedgroup.workloads.x-k8s.io/component-discovery: |
{
"addressRefs":[{"env":"LEADER_ADDR","component":"leader","index":0}],
"portRefs":[{"env":"LEADER_GRPC_PORT","component":"leader","portName":"leader-grpc"}]
}
template:
spec:
containers:
- name: worker
image: anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis/nginx:1.14.1-8.6
Expected behavior:
- If no
component-depends-on annotation is present, CustomComponentsPattern keeps the existing parallel create/delete behavior.
- On scale-out, a component with
startAfter is created only when every referenced component has ReadyReplicas >= Size.
- On scale-in, delete gates are derived from the reverse of
startAfter and merged with explicit deleteAfter.
- Cycles in startup or deletion dependency graphs are detected and handled safely.
component-discovery injects address and port environment variables into containers and init containers before pod creation.
- Controller-directive annotations should be accepted from component-level
annotations, not only from template.metadata.annotations.
Acceptance criteria:
- Unit tests cover dependency parsing, cycle detection, create gating, delete gating, and malformed annotations.
- Unit tests cover address injection, role-scoped port injection, pod-scoped port injection, unknown components, and missing port values.
- Reconciler tests cover the end-to-end RBG -> RoleInstanceSet -> RoleInstance component annotation flow.
- A single-node example demonstrates a three-component topology with ordered startup and intra-role discovery.
- Documentation clarifies that the feature applies to CustomComponentsPattern only.
Local validation:
The following tests were run successfully in a container without a Kubernetes cluster, using Go 1.24.1:
/usr/local/go/bin/go test ./pkg/component-discovery
/usr/local/go/bin/go test ./pkg/reconciler/roleinstance/sync
/usr/local/go/bin/go test ./pkg/reconciler
/usr/local/go/bin/go test ./api/workloads/v1alpha2
/usr/local/go/bin/go test ./pkg/reconciler/roleinstance/sync -run TestAllNamedComponentsReady -v
/usr/local/go/bin/go test ./pkg/component-discovery -run 'Test(ParseAllComponentDependencies|BuildDeletionGates|InjectComponentDiscovery)' -v
One notable follow-up found during local review:
The RBG construction path merges component-level annotations into the PodTemplate before creating RoleInstance templates, but the RoleInstance scale path checks some controller directives from component.Template.Annotations. If direct RoleInstance usage is intended to be supported, the scale path should also read component.Annotations consistently, or the API documentation should state that RoleInstance is controller-internal.
Related resources:
keps/173-enhanced-custom-components-pattern/README.md
doc/features/patterns.md
examples/basic/rbg/patterns/custom-components-ordered-discovery.yaml
pkg/component-discovery/component_lifecycle.go
pkg/component-discovery/component_discovery.go
pkg/reconciler/roleinstance/sync/instance_scale.go
Related resources
No response
#315
Checklist
Motivation
Checklist:
Motivation:
CustomComponentsPattern is the most flexible pattern for heterogeneous,multi-pod-per-replica workloads. It is the right abstraction for topologies such as Router -> Leader -> Worker or Leader/Worker -> Router, where each component has a different startup dependency and needs to discover peer components in the same RoleInstance.
Today users can describe the components, but production inference topologies also need two controller-managed behaviors:
Component lifecycle ordering inside one CustomComponentsPattern role.
A component should be created only after its dependencies are ready.For example, a router can wait for leader and worker components before it starts, or a worker can wait for a leader. Scale-down should respect the reverse order or an explicit deleteAfter order.
Intra-role service discovery for sibling components.
A component should be able to receive peer component pod FQDNs and allocated port values as environment variables, without hard-coding generated pod names or duplicating controller naming logic in user manifests.
Proposed API:
Use component-level annotations on CustomComponentsPattern components:
rolebasedgroup.workloads.x-k8s.io/component-depends-onstartAfteranddeleteAfterarrays.{"startAfter": ["leader", "worker"]}.rolebasedgroup.workloads.x-k8s.io/component-discoveryaddressRefsandportRefs.addressRefsinject peer pod FQDNs.portRefsinject values allocated byrolebasedgroup.workloads.x-k8s.io/port-allocator.Example:
Expected behavior:
component-depends-onannotation is present, CustomComponentsPattern keeps the existing parallel create/delete behavior.startAfteris created only when every referenced component hasReadyReplicas >= Size.startAfterand merged with explicitdeleteAfter.component-discoveryinjects address and port environment variables into containers and init containers before pod creation.annotations, not only fromtemplate.metadata.annotations.Acceptance criteria:
Local validation:
The following tests were run successfully in a container without a Kubernetes cluster, using Go 1.24.1:
One notable follow-up found during local review:
The RBG construction path merges component-level annotations into the PodTemplate before creating RoleInstance templates, but the RoleInstance scale path checks some controller directives from
component.Template.Annotations. If direct RoleInstance usage is intended to be supported, the scale path should also readcomponent.Annotationsconsistently, or the API documentation should state that RoleInstance is controller-internal.Related resources:
keps/173-enhanced-custom-components-pattern/README.mddoc/features/patterns.mdexamples/basic/rbg/patterns/custom-components-ordered-discovery.yamlpkg/component-discovery/component_lifecycle.gopkg/component-discovery/component_discovery.gopkg/reconciler/roleinstance/sync/instance_scale.goRelated resources
No response
#315