ALB Ingress supports canary releases based on request headers, cookies, and weights. Use canary annotations to route a portion of traffic to a new Service version during an upgrade, validate the new version in production, and then promote it when ready.
Prerequisites
Before you begin, ensure that you have:
-
Two vSwitches in different zones, deployed in the same virtual private cloud (VPC) as the ACK cluster. See Create and manage a vSwitch.
-
The ALB Ingress controller installed in the cluster. See Manage the ALB Ingress controller.
To use an ALB Ingress in an ACK dedicated cluster, first grant the cluster the required permissions. See Authorize an ACK dedicated cluster to access the ALB Ingress controller.
-
An AlbConfig created. See Create an AlbConfig.
-
kubectl connected to the ACK cluster. See Obtain the kubeconfig file of a cluster and use kubectl to connect to the cluster.
Canary annotations
All canary Ingresses require the alb.ingress.kubernetes.io/canary: "true" annotation. Without it, the canary Ingress conflicts with the production Ingress instead of routing alongside it.
The following annotations control how traffic is split:
| Annotation | Description |
|---|---|
alb.ingress.kubernetes.io/canary |
Set to "true" to mark this Ingress as a canary. Required on every canary Ingress. |
alb.ingress.kubernetes.io/canary-by-header |
The request header key to match. Requests carrying this header are routed to the canary Service. |
alb.ingress.kubernetes.io/canary-by-header-value |
The header value to match. Must be used together with canary-by-header—has no effect if canary-by-header is not set. |
alb.ingress.kubernetes.io/canary-weight |
The percentage of traffic (0–100) routed to the canary Service for requests that do not match a header or cookie rule. A value of 0 sends no traffic; a value of 100 sends all traffic. |
alb.ingress.kubernetes.io/order |
Controls the order in which routing rules are evaluated. Valid values: 1–1000. Default: 10. A lower value means higher priority. By default, rule order follows the lexicographical order of Ingress namespace and name. |
Rule priority: When multiple canary rules are in effect, they are evaluated in this order: header-based > cookie-based > weight-based.
Usage notes
-
Header-based and cookie-based rules cannot be combined with weight-based rules on the same Ingress. Configure them on separate Ingresses, or use custom routing rules for more complex conditions.
-
The host in a canary Ingress must match the host in the production Ingress exactly.
-
Use
alb.ingress.kubernetes.io/orderto set an explicit priority when multiple canary Ingresses share the same host, rather than relying on lexicographical ordering.
Step 1: Deploy the production Service
Deploy a Deployment, Service, and Ingress for the production version.
-
Create
tea-deploy.yamlwith the following content and apply it:apiVersion: apps/v1 kind: Deployment metadata: name: tea spec: replicas: 1 selector: matchLabels: app: tea template: metadata: labels: app: tea spec: containers: - name: tea image: registry.cn-hangzhou.aliyuncs.com/acs-sample/old-nginx:latest ports: - containerPort: 80kubectl apply -f tea-deploy.yaml -
Create
tea-svc.yamlwith the following content and apply it:apiVersion: v1 kind: Service metadata: name: tea-svc spec: ports: - port: 80 targetPort: 80 protocol: TCP selector: app: tea type: NodePortkubectl apply -f tea-svc.yaml -
Create
tea-ingress.yamlwith the following content and apply it:apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: tea-ingress spec: ingressClassName: alb rules: - host: demo.domain.ingress.top # Replace with your domain name, resolved to the load balancer IP. http: paths: - path: / pathType: Prefix backend: service: name: tea-svc port: number: 80kubectl apply -f tea-ingress.yaml
Step 2: Deploy the canary Service and routing rules
Deploy the new Service version alongside two canary Ingresses: one that routes requests with a specific header to the canary, and one that splits remaining traffic by weight.
Before applying the canary Ingresses, note the following requirements:
-
Set
alb.ingress.kubernetes.io/canary: "true"on every canary Ingress. Without this annotation, the canary Ingress conflicts with the production Ingress. -
The
hostfield must match the production Ingress host exactly (demo.domain.ingress.topin this example). -
Header-based and weight-based rules must be on separate Ingresses.
-
Create
canary-deploy.yamlwith the following content and apply it:apiVersion: apps/v1 kind: Deployment metadata: name: canary spec: replicas: 1 selector: matchLabels: app: canary template: metadata: labels: app: canary spec: containers: - name: canary image: registry.cn-hangzhou.aliyuncs.com/acs-sample/new-nginx:latest ports: - containerPort: 80kubectl apply -f canary-deploy.yaml -
Create
canary-svc.yamlwith the following content and apply it:apiVersion: v1 kind: Service metadata: name: canary-svc spec: ports: - port: 80 targetPort: 80 protocol: TCP selector: app: canary type: NodePortkubectl apply -f canary-svc.yaml -
Create a header-based canary Ingress. All requests carrying
location: hzare routed tocanary-svc. Requests with other headers fall through to the next matching rule. Createcanary-header-ingress.yamlwith the following content and apply it:apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: alb.ingress.kubernetes.io/canary: "true" alb.ingress.kubernetes.io/canary-by-header: "location" alb.ingress.kubernetes.io/canary-by-header-value: "hz" name: canary-header-ingress namespace: default spec: ingressClassName: alb rules: - host: demo.domain.ingress.top # Must match the production Ingress host exactly. http: paths: - backend: service: name: canary-svc port: number: 80 path: / pathType: Prefixkubectl apply -f canary-header-ingress.yaml -
Create a weight-based canary Ingress. Requests that do not match the header rule are split 50/50 between the production and canary Services. Create
canary-weight-ingress.yamlwith the following content and apply it:apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: alb.ingress.kubernetes.io/canary: "true" alb.ingress.kubernetes.io/canary-weight: "50" name: canary-weight-ingress namespace: default spec: ingressClassName: alb rules: - host: demo.domain.ingress.top # Must match the production Ingress host exactly. http: paths: - backend: service: name: canary-svc port: number: 80 path: / pathType: Prefixkubectl apply -f canary-weight-ingress.yaml
Verify the canary release
-
Get the ALB instance address:
kubectl get ingExpected output:
NAME CLASS HOSTS ADDRESS PORTS AGE canary-header-ingress alb demo.domain.ingress.top alb-ny3ute4r8yevni****.cn-chengdu.alb.aliyuncs.com 80 8m23s canary-weight-ingress alb demo.domain.ingress.top alb-ny3ute4r8yevni****.cn-chengdu.alb.aliyuncs.com 80 8m16s tea-ingress alb demo.domain.ingress.top alb-ny3ute4r8yevni****.cn-chengdu.alb.aliyuncs.com 80 7m5s -
Verify that requests carrying
location: hzalways reach the canary:for i in $(seq 1 10); do curl -s -H "Host:demo.domain.ingress.top" -H "location:hz" http://alb-ny3ute4r8yevni****.cn-chengdu.alb.aliyuncs.com; doneAll 10 responses return
new. The header rule has the highest priority and routes 100% of matching requests to the canary. -
Verify that requests without a matching header are split ~50/50:
for i in $(seq 1 10); do curl -s -H "Host:demo.domain.ingress.top" http://alb-ny3ute4r8yevni****.cn-chengdu.alb.aliyuncs.com; doneThe responses alternate between
new(canary) andold(production), roughly half each. Requests carrying an unmatched header (for example,location: bj) follow the same weight-based split.
Step 3: Promote the new version
After the canary runs stably, redirect all production traffic to the new Service and clean up the canary Ingresses.
-
Update
tea-ingress.yamlto point tocanary-svc:apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: tea-ingress spec: ingressClassName: alb rules: - host: demo.domain.ingress.top http: paths: - path: / pathType: Prefix backend: service: name: canary-svc # Changed from tea-svc. port: number: 80kubectl apply -f tea-ingress.yaml -
Delete the canary Ingresses:
kubectl delete ing canary-weight-ingress canary-header-ingress -
Verify that all traffic reaches the new version:
for i in $(seq 1 10); do curl -s -H "Host:demo.domain.ingress.top" http://alb-ny3ute4r8yevni****.cn-chengdu.alb.aliyuncs.com; doneAll 10 responses return
new. The old Service version is fully deprecated.
What's next
-
For advanced ALB Ingress configurations including HTTP-to-HTTPS redirects and custom routing rules, see Advanced ALB Ingress configurations.
-
For troubleshooting guidance, see Ingress FAQ.