All Products
Search
Document Center

Container Service for Kubernetes:Phased releases with Kruise Rollout (canary and A/B testing)

Last Updated:Mar 26, 2026

Kruise Rollout is an open source progressive delivery framework from the OpenKruise community. It works alongside native Kubernetes workloads (Deployments and StatefulSets) and OpenKruise workloads (CloneSets and Advanced StatefulSets) to deliver canary releases, A/B testing, phased releases, and blue-green deployments that coordinate traffic shifting with instance scaling. Based on Prometheus metrics, Kruise Rollout can also automate batching and pausing during the release process. Kruise Rollout integrates with Helm, Platform as a Service (PaaS), and other deployment tools without requiring changes to your existing workflow.

This topic walks through two use cases:

  • Canary and A/B testing — route a portion of traffic to the new version using Nginx Ingress or MSE Ingress before promoting further

  • Phased release for microservice apps — roll out pods in batches without Ingress, for apps (such as Nacos-based services) where traffic shifting is handled by the microservice framework

The following figure shows the architecture for a phased release using Kruise Rollout.

gray

How it works

Kruise Rollout intercepts workload updates and executes them in configurable steps. Each step specifies how many pods to update (replicas) and how long to pause before proceeding (pause). For Ingress-based deployments, each step also controls the traffic weight (weight) reaching the new version.

Configure a Rollout resource once and apply it to your cluster. For every subsequent deployment update, Kruise Rollout automatically intercepts the change and progresses it through the defined steps. No further changes to the Rollout resource are needed.

Prerequisites

Before you begin, ensure that you have:

  • An ACK managed cluster. For more information, see Create an ACK managed cluster.

    • Cluster version 1.19 or later for A/B testing or canary releases

    • Cluster version 1.16 or later for phased releases

  • kubectl-kruise installed. See kubectl-kruise.

Preparations

Step 1: Install the ack-kruise add-on

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

  2. On the Clusters page, click the name of the target cluster. In the left navigation pane, click Add-ons.

  3. On the Add-ons page, click the Manage Applications tab. In the lower-right corner of the ack-kruise card, click Install.

  4. In the dialog box, confirm the information and click OK.

The ack-kruise add-on version 1.8 or later supports the v1beta1 API. For more information, see API specifications.

Step 2: Deploy the sample application

The following steps deploy an echoserver service using a Deployment and expose it through an Ingress. This sample application is used in both use cases.

  1. Create a file named echoserver.yaml with the following content.

    Expand to view the YAML content

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: echoserver
      labels:
        app: echoserver
    spec:
      replicas: 6
      selector:
        matchLabels:
          app: echoserver
      template:
        metadata:
          labels:
            app: echoserver
        spec:
          containers:
          - name: echoserver
            image: openkruise-registry.cn-shanghai.cr.aliyuncs.com/openkruise/demo:1.10.2
            imagePullPolicy: IfNotPresent
            ports:
            - containerPort: 8080
            env:
            - name: NODE_NAME
              value: version1
            - name: PORT
              value: '8080'
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: POD_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
            - name: POD_IP
              valueFrom:
                fieldRef:
                  fieldPath: status.podIP
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: echoserver
      labels:
        app: echoserver
    spec:
      ports:
      - port: 80
        targetPort: 8080
        protocol: TCP
        name: http
      selector:
        app: echoserver
  2. Apply the configuration.

    kubectl apply -f echoserver.yaml

Use case 1: Canary release and A/B testing with Ingress

This use case shows how to configure Kruise Rollout for canary releases and A/B testing using Nginx Ingress or MSE Ingress. The trafficRoutings field in the Rollout resource connects the rollout to the Service and Ingress, enabling Kruise Rollout to manage traffic weights at each step. Each release is defined as a Rollout resource with three steps:

Strategy Step 1 Step 2 Step 3
Canary 20% traffic weight, 1 pod, manual pause 50% weight, 50% pods, 60s auto-pause 100% (full release)
A/B testing Route User-Agent: Android traffic to new version, 1 pod, manual pause 50% pods, 60s auto-pause 100% pods

Step 1: Install the Ingress controller and create an Ingress

Select your Ingress type and follow the corresponding instructions.

Nginx Ingress

  1. Install the Nginx Ingress Controller.

  2. Create a file named echoserver-ingress.yaml with the following content.

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: echoserver
    spec:
      ingressClassName: nginx
      rules:
      - http:
          paths:
          - backend:
              service:
                name: echoserver
                port:
                  number: 80
            path: /apis/echo
            pathType: Exact
  3. Apply the Ingress.

    kubectl apply -f echoserver-ingress.yaml

MSE Ingress

  1. Install the MSE Ingress Controller and create an MseIngressConfig and an IngressClass. For more information, see Access container services through an MSE Ingress.

  2. Create a file named echoserver-ingress.yaml with the following content.

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: echoserver
    spec:
      # You must set ingressClassName to mse.
      ingressClassName: mse
      rules:
        - http:
            paths:
              - backend:
                  service:
                    name: echoserver
                    port:
                      number: 80
                path: /apis/echo
                pathType: Exact
  3. Apply the Ingress.

    kubectl apply -f echoserver-ingress.yaml

Step 2: Verify access to the application

  1. Retrieve the external IP address or hostname. Nginx Ingress:

    export EXTERNAL_IP=$(kubectl get ingress echoserver -o jsonpath="{.status.loadBalancer.ingress[0].ip}")

    MSE Ingress:

    export EXTERNAL_IP=$(kubectl get ingress echoserver -o jsonpath="{.status.loadBalancer.ingress[0].hostname}")
  2. Test access.

    curl http://${EXTERNAL_IP}/apis/echo

    Expected output:

    Hostname: echoserver-75d49c475c-ls2bs
    
    Pod Information:
        node name:    version1
        pod name:    echoserver-75d49c475c-ls2bs
        pod namespace:    default
    
    Server values:
        server_version=nginx: 1.13.3 - lua: 10008
    ...

Step 3: Define the Rollout resource

Create a file named rollout.yaml using the strategy that matches your use case. The trafficRoutings field links the Rollout to the echoserver Service and Ingress so that Kruise Rollout can shift traffic at each step.

Canary

apiVersion: rollouts.kruise.io/v1alpha1
kind: Rollout
metadata:
  name: rollouts-demo
spec:
  objectRef:
    workloadRef:
      apiVersion: apps/v1
      kind: Deployment
      name: echoserver
  strategy:
    canary:
      steps:
      # Step 1: Route 20% of traffic to the new version (1 pod). Pause until manually approved.
      - weight: 20
        replicas: 1
        pause: {}
      # Step 2: Increase to 50% traffic and 50% pods. Auto-proceed after 60 seconds.
      - weight: 50
        replicas: 50%
        pause: {duration: 60}  # unit: seconds
      # Step 3: Full release.
      - weight: 100
        replicas: 100%
        pause: {duration: 60}  # unit: seconds
      trafficRoutings:
      - service: echoserver
        ingress:
          name: echoserver

A/B testing

apiVersion: rollouts.kruise.io/v1alpha1
kind: Rollout
metadata:
  name: rollouts-demo
spec:
  objectRef:
    workloadRef:
      apiVersion: apps/v1
      kind: Deployment
      name: echoserver
  strategy:
    canary:
      steps:
      # Step 1: Route Android traffic to the new version (1 pod). Pause until manually approved.
      - matches:
          - headers:
              - type: Exact
                name: User-Agent
                value: Android
        pause: {}
        replicas: 1
      # Step 2: 50% of pods, still matching Android traffic. Auto-proceed after 60 seconds.
      - matches:
          - headers:
              - type: Exact
                name: User-Agent
                value: Android
        pause: {duration: 60}  # unit: seconds
        replicas: 50%
      # Step 3: Full release.
      - matches:
          - headers:
              - type: Exact
                name: User-Agent
                value: Android
        pause: {duration: 60}  # unit: seconds
        replicas: 100%
      trafficRoutings:
        - service: echoserver
          ingress:
            name: echoserver

Apply the Rollout resource and verify it is healthy.

kubectl apply -f rollout.yaml
kubectl get rollout

Expected output:

NAME            STATUS    CANARY_STEP   CANARY_STATE   MESSAGE                            AGE
rollouts-demo   Healthy   3             Completed      workload deployment is completed   7s

STATUS=Healthy confirms the Rollout resource is ready.

Step 4: Trigger the upgrade

Kruise Rollout activates automatically when the Deployment spec changes. Update the image version in echoserver.yaml to trigger a release.

# echoserver.yaml (relevant section)
spec:
  containers:
  - name: echoserver
    image: openkruise-registry.cn-shanghai.cr.aliyuncs.com/openkruise/demo:1.10.3
    env:
    - name: NODE_NAME
      value: version2  # Optional: helps identify the new version in verification output

Apply the updated Deployment. You can also use tools such as Helm and Vela to apply the Deployment configuration.

kubectl apply -f echoserver.yaml

Check the rollout status.

kubectl get rollouts rollouts-demo -n default

Expected output:

NAME            STATUS        CANARY_STEP   CANARY_STATE   MESSAGE                                                                         AGE
rollouts-demo   Progressing   1             StepPaused     Rollout is in step(1/3), and you need manually confirm to enter the next step   41m

The status fields show:

Field Value Meaning
STATUS Progressing Canary release is in progress
CANARY_STEP 1 Currently in step 1 of 3
CANARY_STATE StepPaused Step 1 is complete; waiting for manual approval

Step 5: Verify traffic distribution and proceed

Canary

  1. Access the service 10 times and observe the node name in the output.

    for i in {1..10}; do curl -s http://${EXTERNAL_IP}/apis/echo | grep 'node name'; sleep 1; done

    Expected output (approximately 8 requests to version1, 2 to version2):

            node name:      version1
            node name:      version1
            node name:      version2
            node name:      version1
            node name:      version2
            node name:      version1
            node name:      version1
            node name:      version1
            node name:      version1
            node name:      version1

    The 8:2 ratio matches the 20% weight configured in step 1.

  2. Approve step 1 to proceed to step 2.

    kubectl-kruise rollout approve rollouts/rollouts-demo -n default
  3. Monitor the rollout as it progresses through steps 2 and 3.

    kubectl get rollouts rollouts-demo -n default -w

    The rollout automatically advances through step 2 (50% weight, 60s pause) and step 3 (100%, 60s pause). The rollout is complete when STATUS=Healthy and CANARY_STATE=Completed.

A/B testing

  1. Send requests with and without the User-Agent: Android header.

    curl -s http://${EXTERNAL_IP}/apis/echo | grep 'Pod Information:' -A 3
    curl -sH "User-Agent: Android" http://${EXTERNAL_IP}/apis/echo | grep 'Pod Information:' -A 3

    Expected output:

    Pod Information:
            node name:      version1
            pod name:       echoserver-69598f9458-7c66v
            pod namespace:  default
    Pod Information:
            node name:      version2
            pod name:       echoserver-fvhzg-687b4b56-qbhc8
            pod namespace:  default

    The request without the header reaches version1; the Android request reaches version2. The header-based routing rule is working.

  2. Approve step 1 to proceed to step 2.

    kubectl-kruise rollout approve rollouts/rollouts-demo -n default
  3. Monitor the rollout until it completes.

    kubectl get rollouts rollouts-demo -n default -w

    The rollout automatically advances through step 2 and step 3. The rollout is complete when STATUS=Healthy and CANARY_STATE=Completed.

Roll back if the new version is abnormal

If the new version behaves unexpectedly at any step, restore the previous Deployment configuration and reapply. No changes to the Rollout resource are required.

# echoserver.yaml (rollback version)
spec:
  containers:
  - name: echoserver
    image: openkruise-registry.cn-shanghai.cr.aliyuncs.com/openkruise/demo:1.10.2
    env:
    - name: NODE_NAME
      value: version1
kubectl apply -f echoserver.yaml

Use case 2: Phased release for microservice apps

Apps built on microservice frameworks such as Nacos handle traffic shifting internally and do not require Ingress or Service-level traffic routing. For these apps, use Kruise Rollout's partition-based phased release, which rolls out pods in batches without the trafficRoutings field.

Because traffic shifting is managed by the microservice framework itself, this use case does not demonstrate traffic distribution verification. It shows only how to progress through rollout batches.

Step 1: Define and deploy the Rollout resource

The following Rollout uses the partition rolling style and releases pods in three batches: 1 pod, then 50%, then 100%. The trafficRoutings field is omitted because the microservice framework manages traffic routing.

# Save as rollout.yaml
apiVersion: rollouts.kruise.io/v1alpha1
kind: Rollout
metadata:
  name: rollouts-demo
  annotations:
    rollouts.kruise.io/rolling-style: partition
spec:
  objectRef:
    workloadRef:
      apiVersion: apps/v1
      kind: Deployment
      name: echoserver
  strategy:
    canary:
      steps:
      # Step 1: Update 1 pod. Pause until manually approved.
      - replicas: 1
        pause: {}
      # Step 2: Update 50% of pods. Auto-proceed after 60 seconds.
      - replicas: 50%
        pause: {duration: 60}  # unit: seconds
      # Step 3: Update all pods.
      - replicas: 100%
        pause: {duration: 60}  # unit: seconds
kubectl apply -f rollout.yaml

Step 2: Trigger the upgrade

Update the image version in echoserver.yaml.

# echoserver.yaml (relevant section)
spec:
  containers:
  - name: echoserver
    image: openkruise-registry.cn-shanghai.cr.aliyuncs.com/openkruise/demo:1.10.3
    env:
    - name: NODE_NAME
      value: version2  # Optional: helps identify the new version
kubectl apply -f echoserver.yaml

Step 3: Check rollout status

kubectl get rollouts rollouts-demo -n default

Expected output:

NAME            STATUS        CANARY_STEP   CANARY_STATE   MESSAGE                                                                         AGE
rollouts-demo   Progressing   1             StepPaused     Rollout is in step(1/3), and you need manually confirm to enter the next step   41m
Field Value Meaning
STATUS Progressing Release is in progress
CANARY_STEP 1 Currently in step 1 of 3
CANARY_STATE StepPaused Step 1 is complete; waiting for manual approval

Step 4: Approve batches and monitor progress

Approve step 1 to move to step 2.

kubectl-kruise rollout approve rollouts/rollouts-demo -n default

Monitor the rollout as it progresses.

kubectl get rollouts rollouts-demo -n default -w

After you approve step 1, the rollout automatically advances through step 2 (50% pods, 60s pause) and step 3 (all pods, 60s pause). Key state transitions to watch for:

CANARY_STATE Meaning
StepPaused Batch complete; either waiting for manual approval or timed auto-pause
StepUpgrade Upgrading pods in this batch
StepReady Batch upgrade complete
Completed All steps finished

The rollout is complete when STATUS=Healthy and CANARY_STATE=Completed.

Roll back if the new version is abnormal

If the new version behaves unexpectedly, restore the previous Deployment configuration and reapply. No changes to the Rollout resource are required.

# echoserver.yaml (rollback version)
spec:
  containers:
  - name: echoserver
    image: openkruise-registry.cn-shanghai.cr.aliyuncs.com/openkruise/demo:1.10.2
    env:
    - name: NODE_NAME
      value: version1
kubectl apply -f echoserver.yaml

What's next