All Products
Search
Document Center

Container Service for Kubernetes:Implement workload scaling based on the UnitedDeployment controller

Last Updated:Mar 26, 2026

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:

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

Important

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).

image

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.

  1. Create test.yaml with the following content. The file defines a UnitedDeployment using a deploymentTemplate. 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 by type=virtual-kubelet label 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
  2. Deploy the UnitedDeployment:

    kubectl apply -f test.yaml

    Expected output:

    uniteddeployment.apps.kruise.io/ud-nginx created
  3. Verify that pods are running on the correct nodes:

    kubectl get pod -o wide

    Expected 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.

image
  1. 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.
  2. Create test.yaml with the following content. The file defines a UnitedDeployment using a statefulSetTemplate. The subsets section maps each zone to a subset:

    • subset-a: 1 replica on the node labeled node=zone-a.

    • subset-b: 50% of total replicas on the node labeled node=zone-b.

    • subset-c: remaining replicas (no explicit count) on the node labeled node=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
  3. Deploy the UnitedDeployment:

    kubectl apply -f test.yaml

    Expected output:

    uniteddeployment.apps.kruise.io/sample-ud created
  4. Verify that pods and StatefulSets are created across all three zones:

    kubectl get pod

    Expected 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          5m51s
    kubectl get statefulset

    Expected 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     7m34s

    Pods 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.

image

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.

  1. Create test.yaml with the following content. The file defines a UnitedDeployment with a deploymentTemplate and two subsets, followed by an HPA targeting the UnitedDeployment:

    • ecs subset: maxReplicas: 4 — absorbs up to 4 pods.

    • eci subset: maxReplicas: null — absorbs any remaining pods.

    • HPA: targets the UnitedDeployment directly, with minReplicas: 4 and maxReplicas: 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
  2. Deploy the UnitedDeployment and HPA:

    kubectl apply -f test.yaml

    Expected output:

    horizontalpodautoscaler.autoscaling/united-deployment-hpa created
  3. Verify the pod distribution:

    kubectl get pod -o wide

    Expected 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.

  4. After HPA triggers a scale-in, verify that ECI pods are removed first:

    kubectl get pod -o wide

    Expected 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