UnitedDeployment is an OpenKruise custom resource that manages multiple homogeneous workloads as a single object by grouping them into units called Subsets. Instead of maintaining separate YAML files for each Deployment or StatefulSet, define one UnitedDeployment with a Subset per target group — the controller handles scheduling, updates, and replica distribution across all subsets.
Combined with Horizontal Pod Autoscaler (HPA), UnitedDeployment enables ordered scaling across mixed compute resources: pods scale up from cheapest to most expensive and scale down in reverse, optimizing costs automatically.
For the full API reference, see the UnitedDeployment documentation on the OpenKruise website.
Supported workload types
UnitedDeployment supports StatefulSet, Advanced StatefulSet, CloneSet, and Deployment. For details, see Use OpenKruise to deploy cloud-native applications.
Prerequisites
Before you begin, ensure that you have:
-
The ack-kruise add-on installed. For more information, see Manage add-ons
-
The ACK Virtual Node add-on, which comes pre-installed with ECI. For more information, see Manage add-ons
-
A kubectl client connected to the ACK cluster. For more information, see Get a cluster kubeconfig and connect to the cluster using kubectl
Use cases
This topic covers three common scenarios:
-
Ordered scaling with mixed resources — Use HPA to scale pods across subscription ECS instances, spot instances, and ECIs in priority order.
-
Cross-zone deployment — Distribute pods across multiple availability zones for high availability.
-
ECS and ECI colocation — Prioritize Elastic Compute Service (ECS) instances for scheduling and overflow to ECIs during traffic spikes.
Scenario 1: Use UnitedDeployment with HPA for ordered scaling
OpenKruise 1.5.0 is required. For more information, see OpenKruise release notes.
When a cluster has multiple node types, configure one Subset per resource type in the UnitedDeployment YAML. Use the maxReplicas field to cap the number of pods on each subset. When HPA triggers scaling, the controller fills subsets in the order listed — scaling up from the first subset to the last, and scaling down in reverse.
To integrate HPA, set scaleTargetRef in the HPA spec to target UnitedDeployment (not the underlying Deployment).
Scaling rules:
-
Scale-up: subsets are filled in the order listed in
topology.subsets. -
Scale-down: pods are removed in reverse order (last subset first).
This example configures a cluster with two node pools: Node Pool A (subscription ECS instances) and Node Pool B (spot instances). The scheduling priority is: subscription ECS instance > spot instance > ECI. When nodes of a higher-priority type are unavailable, the controller falls back to the next type.
-
Create
test.yamlwith the following content. The file defines aUnitedDeploymentusing adeploymentTemplate. Three subsets are configured:-
subset-a: 1 replica on Node Pool A (subscription ECS instances), selected by node pool ID label. -
subset-b: 1 replica on Node Pool B (spot instances), selected by node pool ID label. -
subset-c: 3 replicas on ECI virtual nodes, selected bytype=virtual-kubeletlabel and toleration.
apiVersion: apps.kruise.io/v1alpha1 kind: UnitedDeployment metadata: name: ud-nginx spec: replicas: 6 revisionHistoryLimit: 10 selector: matchLabels: app: ud-nginx template: deploymentTemplate: metadata: labels: app: ud-nginx spec: selector: matchLabels: app: ud-nginx template: metadata: labels: app: ud-nginx spec: containers: - image: alibaba-cloud-linux-3-registry.cn-hangzhou.cr.aliyuncs.com/alinux3/nginx_optimized:20240221-1.20.1-2.3.0 name: nginx topology: subsets: - name: subset-a nodeSelectorTerm: matchExpressions: - key: alibabacloud.com/nodepool-id operator: In values: - np92019eec42004d878fcdc990fcb9**** # Replace with the ID of Node Pool A. replicas: 1 - name: subset-b nodeSelectorTerm: matchExpressions: - key: alibabacloud.com/nodepool-id operator: In values: - np011de1f2de3d48bd8a92a015fc5c**** # Replace with the ID of Node Pool B. replicas: 1 - name: subset-c nodeSelectorTerm: matchExpressions: - key: type operator: In values: - virtual-kubelet tolerations: - key: virtual-kubelet.io/provider operator: Exists replicas: 3 updateStrategy: manualUpdate: partitions: subset-a: 0 subset-b: 0 subset-c: 0 type: Manual -
-
Deploy the
UnitedDeployment:kubectl apply -f test.yamlExpected output:
uniteddeployment.apps.kruise.io/ud-nginx created -
Verify that pods are running on the correct nodes:
kubectl get pod -o wideExpected output:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES ud-nginx-subset-a-7lbtd-5b5bd77549-5bw6l 1/1 Running 0 73s 192.XX.XX.126 cn-hangzhou.10.XX.XX.131 <none> <none> ud-nginx-subset-b-nvvfw-5c9bcd6766-lv6sp 1/1 Running 0 73s 192.XX.XX.239 cn-hangzhou.10.XX.XX.132 <none> <none> ud-nginx-subset-c-m78fd-7796b66fd8-7p52j 1/1 Running 0 73s 192.XX.XX.130 virtual-kubelet-cn-hangzhou-h <none> <none> ud-nginx-subset-c-m78fd-7796b66fd8-fd7f7 1/1 Running 0 73s 192.XX.XX.129 virtual-kubelet-cn-hangzhou-h <none> <none> ud-nginx-subset-c-m78fd-7796b66fd8-mn4qb 1/1 Running 0 73s 192.XX.XX.131 virtual-kubelet-cn-hangzhou-h <none> <none>Pods are distributed across all three subsets as defined in the topology.
Scenario 2: Deploy applications across availability zones
Deploying across availability zones protects applications from zone-level failures. Label each node with its zone, then configure one Subset per zone using label selectors. The controller schedules each subset's pods to the matching zone.
-
Label each node with its zone. The following commands add zone labels to three nodes in different availability zones:
kubectl label node cn-beijing.10.XX.XX.131 node=zone-a node/cn-beijing.10.80.20.131 labeled # Adds node=zone-a to node 10.XX.XX.131. kubectl label node cn-beijing.10.XX.XX.132 node=zone-b node/cn-beijing.10.80.20.132 labeled # Adds node=zone-b to node 10.XX.XX.132. kubectl label node cn-beijing.10.XX.XX.133 node=zone-c node/cn-beijing.10.80.20.133 labeled # Adds node=zone-c to node 10.XX.XX.133. -
Create
test.yamlwith the following content. The file defines aUnitedDeploymentusing astatefulSetTemplate. Thesubsetssection maps each zone to a subset:-
subset-a: 1 replica on the node labelednode=zone-a. -
subset-b: 50% of total replicas on the node labelednode=zone-b. -
subset-c: remaining replicas (no explicit count) on the node labelednode=zone-c.
apiVersion: apps.kruise.io/v1alpha1 kind: UnitedDeployment metadata: name: sample-ud spec: replicas: 6 revisionHistoryLimit: 10 selector: matchLabels: app: sample template: statefulSetTemplate: metadata: labels: app: sample spec: selector: matchLabels: app: sample template: metadata: labels: app: sample spec: containers: - image: alibaba-cloud-linux-3-registry.cn-hangzhou.cr.aliyuncs.com/alinux3/nginx_optimized:20240221-1.20.1-2.3.0 name: nginx topology: subsets: - name: subset-a nodeSelectorTerm: matchExpressions: - key: node operator: In values: - zone-a replicas: 1 - name: subset-b nodeSelectorTerm: matchExpressions: - key: node operator: In values: - zone-b replicas: 50% - name: subset-c nodeSelectorTerm: matchExpressions: - key: node operator: In values: - zone-c updateStrategy: manualUpdate: partitions: subset-a: 0 subset-b: 0 subset-c: 0 type: Manual -
-
Deploy the
UnitedDeployment:kubectl apply -f test.yamlExpected output:
uniteddeployment.apps.kruise.io/sample-ud created -
Verify that pods and StatefulSets are created across all three zones:
kubectl get podExpected output:
NAME READY STATUS RESTARTS AGE sample-ud-subset-a-cplwg-0 1/1 Running 0 6m5s sample-ud-subset-b-rj7kt-0 1/1 Running 0 6m4s sample-ud-subset-b-rj7kt-1 1/1 Running 0 5m49s sample-ud-subset-b-rj7kt-2 1/1 Running 0 5m43s sample-ud-subset-c-g6jvx-0 1/1 Running 0 6m5s sample-ud-subset-c-g6jvx-1 1/1 Running 0 5m51skubectl get statefulsetExpected output:
NAME READY AGE sample-ud-subset-a-cplwg 1/1 7m34s sample-ud-subset-b-rj7kt 3/3 7m34s sample-ud-subset-c-g6jvx 2/2 7m34sPods and StatefulSets are running on nodes in Zone A, Zone B, and Zone C.
Scenario 3: Colocate applications on ECS instances and ECIs
During traffic spikes, you need both resource availability and cost control. UnitedDeployment handles this by prioritizing ECS instances for scheduling and automatically overflowing to ECIs when ECS capacity is exhausted. On scale-in, the controller removes ECI pods before ECS pods.
The following example configures a UnitedDeployment with two subsets: one for ECS instances (capped at 4 replicas) and one for ECIs (unlimited). An HPA scales the total replica count between 4 and 10 based on CPU utilization.
Scheduling behavior:
-
When total replicas are 4 or fewer: all pods run on ECS instances.
-
When total replicas are between 4 and 10: excess pods run on ECIs.
-
On scale-in: ECI pods are removed before ECS pods.
-
Create
test.yamlwith the following content. The file defines aUnitedDeploymentwith adeploymentTemplateand two subsets, followed by an HPA targeting theUnitedDeployment:-
ecssubset:maxReplicas: 4— absorbs up to 4 pods. -
ecisubset:maxReplicas: null— absorbs any remaining pods. -
HPA: targets the
UnitedDeploymentdirectly, withminReplicas: 4andmaxReplicas: 10.
apiVersion: apps.kruise.io/v1alpha1 kind: UnitedDeployment metadata: name: ud-nginx spec: replicas: 6 selector: matchLabels: app: sample template: # statefulSetTemplate or advancedStatefulSetTemplate or cloneSetTemplate or deploymentTemplate deploymentTemplate: metadata: labels: app: sample spec: selector: matchLabels: app: sample template: metadata: labels: app: sample spec: containers: - image: alibaba-cloud-linux-3-registry.cn-hangzhou.cr.aliyuncs.com/alinux3/nginx_optimized:20240221-1.20.1-2.3.0 name: nginx resources: requests: cpu: "500m" topology: subsets: - name: ecs maxReplicas: 4 - name: eci maxReplicas: null --- apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: united-deployment-hpa spec: scaleTargetRef: apiVersion: apps.kruise.io/v1alpha1 kind: UnitedDeployment name: ud-nginx # Replace with the name of the UnitedDeployment. minReplicas: 4 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 50 -
-
Deploy the
UnitedDeploymentand HPA:kubectl apply -f test.yamlExpected output:
horizontalpodautoscaler.autoscaling/united-deployment-hpa created -
Verify the pod distribution:
kubectl get pod -o wideExpected output:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES ud-nginx-eci-dxfbz-864bdb77b-2d4t9 1/1 Running 0 3m9s 192.XX.XX.129 cn-hangzhou.192.XX.XX.120 <none> <none> ud-nginx-eci-dxfbz-864bdb77b-zppfh 1/1 Running 0 3m9s 192.XX.XX.11 cn-hangzhou.192.XX.XX.251 <none> <none> ud-nginx-ecs-5lm7r-868c4ccd5d-5mlgh 1/1 Running 0 3m9s 192.XX.XX.4 cn-hangzhou.192.XX.XX.251 <none> <none> ud-nginx-ecs-5lm7r-868c4ccd5d-6bdkz 1/1 Running 0 3m9s 192.XX.XX.145 cn-hangzhou.192.XX.XX.32 <none> <none> ud-nginx-ecs-5lm7r-868c4ccd5d-dnsfl 1/1 Running 0 3m9s 192.XX.XX.150 cn-hangzhou.192.XX.XX.20 <none> <none> ud-nginx-ecs-5lm7r-868c4ccd5d-mrzwc 1/1 Running 0 3m9s 192.XX.XX.128 cn-hangzhou.192.XX.XX.120 <none> <none>The first 4 replicas are on ECS instances; the remaining 2 are on ECIs.
-
After HPA triggers a scale-in, verify that ECI pods are removed first:
kubectl get pod -o wideExpected output:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES ud-nginx-ecs-5lm7r-868c4ccd5d-5mlgh 1/1 Running 0 8m14s 192.168.8.4 cn-hangzhou.192.168.8.251 <none> <none> ud-nginx-ecs-5lm7r-868c4ccd5d-6bdkz 1/1 Running 0 8m14s 192.168.6.145 cn-hangzhou.192.168.6.32 <none> <none> ud-nginx-ecs-5lm7r-868c4ccd5d-dnsfl 1/1 Running 0 8m14s 192.168.6.150 cn-hangzhou.192.168.6.20 <none> <none> ud-nginx-ecs-5lm7r-868c4ccd5d-mrzwc 1/1 Running 0 8m14s 192.168.5.128 cn-hangzhou.192.168.5.120 <none> <none>The replica count scaled from 6 to 4. Both ECI pods are removed; all 4 remaining pods run on ECS instances.
What's next
-
To add nodes across zones during scale-out, see Implement rapid scaling across multiple zones.
-
For automatic node scaling when cluster capacity cannot meet pod scheduling requirements, see Node scaling.