All Products
Search
Document Center

Container Service for Kubernetes:Enable rapid multi-zone auto scaling

Last Updated:Sep 14, 2026

Distributing workloads evenly across multiple zones is a core strategy for building a high-availability architecture. As your workload increases, a multi-zone balanced scheduling policy automatically scales out instances across zones to meet cluster capacity demands.

Prerequisites

You have created at least one vSwitch in each zone where you want to scale out instances. For more information, see Create and manage vSwitches. After creation, you can select the corresponding vSwitch when you create and manage node pools.

Background

The cluster autoscaler can determine if a service can be deployed on a scaling group and send a scale-out request to a specified ESS scaling group to create new instances. However, a problem arises when you configure vSwitches from multiple zones within a single ESS scaling group. When workload pods cannot be scheduled due to insufficient cluster resources, ACK triggers the ESS scaling group to scale out. But without a mechanism to associate the scale-out request with a specific zone, the ESS scaling group does not know which zone needs more capacity. This can cause new instances to be concentrated in a single zone instead of being distributed across multiple zones, failing to meet the demand for concurrent, multi-zone scaling.

image

To address this, ACK provides the ack-autoscaling-placeholder component. Using a small amount of reserved resources, this component transforms generic multi-zone auto scaling into targeted, concurrent scaling of specific node pools. For more information, see Achieve Container Scaling in Seconds Using ack-autoscaling-placeholder. Here's how it works:

  1. Create a separate node pool for each zone and apply a unique zone label to each node pool.

  2. Use the ack-autoscaling-placeholder component to create placeholder pods in each zone by using a nodeSelector that targets the zone-specific labels. By default, these placeholder pods have a low-priority PriorityClass, giving them a lower priority than your application pods.

  3. When a high-priority workload pod becomes pending, it preempts a placeholder pod in one of the zones. The preempted placeholder pod, which has a zone-specific nodeSelector, then becomes pending. This signals the cluster autoscaler to scale out a new node specifically in that zone, transforming a general scaling need into a targeted request.

The following example uses two zones to illustrate how to achieve concurrent scaling across multiple zones.

image
  1. The ack-autoscaling-placeholder component acts as a bridge between your applications and the cluster autoscaler by creating a placeholder pod in each zone. The scheduling priority of these placeholder pods is lower than your application pods.

  2. When an application pod becomes pending, it immediately preempts a placeholder pod and runs on an existing node in one of the zones. The preempted placeholder pod then enters the Pending state.

  3. Because each placeholder pod is configured with a zone-specific nodeSelector, the cluster autoscaler knows exactly which zone to scale, enabling concurrent scaling in the correct zones.

Step 1: Create node pools and add labels

  1. Log on to the ACK console. In the left navigation pane, click Clusters.

  2. On the Clusters page, click the name of your target cluster. In the navigation pane on the left, choose Nodes > Node Pools.

  3. Click Create Node Pool and configure the parameters as prompted.

    This example creates a node pool named auto-zone-I with auto scaling enabled in zone I. The following table describes the key parameters. For more information, see Create and manage node pools.

    Parameter

    Description

    Node Pool Name

    auto-zone-I

    Scaling Mode

    Select Auto to enable auto scaling.

    vSwitch

    Select the vSwitch for zone I.

    Node Labels

    Set the Key to available_zone and the Value to i.

    In the node pool list, the node pool is successfully created when its status changes to Active.

  4. Repeat these steps for each zone where you want to enable auto scaling.

    After creation, you can see the node pools for each zone (for example, auto-zone-I, auto-zone-K, and auto-zone-H) in the node pool list. You can select different instance types as needed (such as ecs.hfc7.xlarge, ecs.c7.xlarge, or ecs.s6-c1m2.xlarge). The billing method is pay-as-you-go, and the status of each node pool is Active with auto scaling enabled.

Step 2: Deploy the placeholder component and Deployments

  1. In the left navigation pane, choose Marketplace > Application market.

  2. Search for ack-autoscaling-placeholder, click the component card, and then click Deploy.

  3. Select a Cluster and Namespace, click Next, select a Chart Version, edit the Parameter, and then click OK.

    After the application is created, navigate to the Applications > Helm page. The status of the application is Deployed.

  4. In the left navigation pane of the cluster management page, choose Application > Helm.

  5. On the Helm page, find ack-autoscaling-placeholder-default and click Update in the Actions column.

  6. In the Update Release panel, update the YAML configuration as shown in the following example and click OK. You must define a placeholder Deployment for each zone.

    This example shows how to create placeholder Deployments in zones I, K, and H.

    deployments:
    - affinity: {}
      annotations: {}
      containers:
      - image: registry-vpc.cn-beijing.aliyuncs.com/acs/pause:3.1
        imagePullPolicy: IfNotPresent
        name: placeholder
        resources:
          requests:
            cpu: 3500m     # CPU request for the placeholder pod.
            memory: 6      # Memory request for the placeholder pod.
      imagePullSecrets: {}
      labels: {}
      name: ack-place-holder-I             # The name of the placeholder Deployment.
      nodeSelector: {"available_zone":"i"}   # The zone label. It must match the label configured for the node pool in Step 1.
      replicaCount: 10                     # The number of pods to create in each scale-out event.
      tolerations: []
    - affinity: {}
      annotations: {}
      containers:
      - image: registry-vpc.cn-beijing.aliyuncs.com/acs/pause:3.1
        imagePullPolicy: IfNotPresent
        name: placeholder
        resources:
          requests:
            cpu: 3500m    # CPU request for the placeholder pod.
            memory: 6     # Memory request for the placeholder pod.
      imagePullSecrets: {}
      labels: {}
      name: ack-place-holder-K            # The name of the placeholder Deployment.
      nodeSelector: {"available_zone":"k"}  # The zone label. It must match the label configured for the node pool in Step 1.
      replicaCount: 10                    # The number of pods to create in each scale-out event.
      tolerations: []
    - affinity: {}
      annotations: {}
      containers:
      - image: registry-vpc.cn-beijing.aliyuncs.com/acs/pause:3.1
        imagePullPolicy: IfNotPresent
        name: placeholder
        resources:
          requests:
            cpu: 3500m   # CPU request for the placeholder pod.
            memory: 6    # Memory request for the placeholder pod.
      imagePullSecrets: {}
      labels: {}
      name: ack-place-holder-H           # The name of the placeholder Deployment.
      nodeSelector: {"available_zone":"h"} # The zone label. It must match the label configured for the node pool in Step 1.
      replicaCount: 10                   # The number of pods to create in each scale-out event.
      tolerations: []
    fullnameOverride: ""
    nameOverride: ""
    podSecurityContext: {}
    priorityClassDefault:
      enabled: true
      name: default-priority-class
      value: -1

    A successful update creates a placeholder Deployment for each zone.

Step 3: Create a workload PriorityClass

  1. Create a file named priorityClass.yaml by using the following YAML template.

    apiVersion: scheduling.k8s.io/v1
    kind: PriorityClass
    metadata:
      name: high-priority
    value: 1000000              # Set a priority value higher than the default priority of the placeholder pods from Step 2.
    globalDefault: false
    description: "This priority class should be used for XYZ service pods only."

    If you do not need to configure a specific PriorityClass for each pod, you can set a global default. Once configured, any pod without a specified priorityClassName automatically uses this priority.

    apiVersion: scheduling.k8s.io/v1
    kind: PriorityClass
    metadata:
      name: global-high-priority
    value: 1                              # Set a priority value higher than the default priority of the placeholder pods from Step 2.
    globalDefault: true
    description: "This priority class should be used for XYZ service pods only."
  2. Create the PriorityClass.

    kubectl apply -f priorityClass.yaml

    Expected output:

    priorityclass.scheduling.k8s.io/high-priority created

Step 4: Create the actual workload

The following example creates a workload in zone I.

  1. Create a file named workload.yaml by using the following YAML template.

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: placeholder-test
      labels:
        app: nginx
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          nodeSelector:                        # Node selector.
            available_zone: "i"
          priorityClassName: high-priority     # The name of the PriorityClass created in Step 3. This field is optional if you have configured a global default.
          containers:
          - name: nginx
            image: anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis/nginx:1.14.1-8.6
            ports:
            - containerPort: 80
            resources:
              requests:
                cpu: '3'                        # Resource requests for the actual workload.
                memory: 5Gi
  2. Deploy the actual workload.

    kubectl apply -f workload.yaml

    Expected output:

    deployment.apps/placeholder-test created

    After the workload is deployed, go to the Workloads > Pods page. You will see that because the workload has a higher PriorityClass, it preempts a placeholder pod and runs on its node. The preempted placeholder pod, in turn, triggers the cluster autoscaler to perform a concurrent scale-out, preparing capacity for future workload scaling.

    On the Nodes > Nodes page, observe that the workload pod now runs on the node previously occupied by a placeholder pod. You can also verify that the cluster has scaled out new worker nodes. For example, you might see two new ecs.c6e.xlarge (4 vCPU, 8 GiB) nodes in a running state, confirming that the cluster autoscaler successfully performed the concurrent scale-out.