Before you update a Service, you can use canary releases to test the stability of the new Service version. The Application Load Balancer (ALB) Ingress controller allows you to use annotations to specify the percentage of traffic routed to a canary Service. This topic describes how to use an ALB Ingress to perform canary releases.

Prerequisites

An ALBConfig object and an IngressClass are created. For more information, see Create an ALBConfig object.

Usage notes for canary annotations

ALB Ingresses allow you to use canary annotations to perform canary releases based on headers, cookies, and weights. Canary releases that use different rules take effect in the following order: header-based > cookie-based > weight-based. If you configure the header-based, cookie-based, and weight-based rules at the same time, the rules with the highest priority shall prevail. For more information about canary annotations, see Use annotations to perform canary releases.

Step 1: Create an application

  1. Obtain the kubeconfig file of a cluster and use kubectl to connect to the cluster.
  2. Deploy a Service named tea.
    1. Create a file named tea-deploy.yaml and copy the following content to the file:
      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: 80
    2. Run the following command to deploy the tea Service:
      kubectl apply -f tea-deploy.yaml
  3. Deploy a Service named tea-svc.
    1. Create a file named tea-svc.yaml and copy the following content to the file:
      apiVersion: v1
      kind: Service
      metadata:
        name: tea-svc
      spec:
        ports:
        - port: 80
          targetPort: 80
          protocol: TCP
        selector:
          app: tea
        type: NodePort
    2. Run the following command to deploy the tea-svc Service:
      kubectl apply -f tea-svc.yaml
  4. Deploy an Ingress named tea-ingress.
    1. Create a file named test-ingress.yaml and copy the following content to the file:
      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: tea-svc
                  port:
                    number: 80
    2. Run the following command to deploy the Ingress:
      kubectl apply -f tea-ingress.yaml

Step 2: Perform a canary release for a new Service version

Deploy a new Service version and a new Ingress version to route all requests that carry the location: hz header to the new Service version named canary and route 50% of the other requests to the new Service version. Other requests include requests that carry other headers and requests that do not carry headers.

  1. Deploy the new Service version named canary.
    1. Create a file named canary-deploy.yaml and copy the following content to the file:
      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: 80
    2. Run the following command to deploy the canary Service:
      kubectl apply -f canary-deploy.yaml
  2. Deploy a Service named canary-svc.
    1. Create a file named canary-svc.yaml and copy the following content to the file:
      apiVersion: v1
      kind: Service
      metadata:
        name: canary-svc
      spec:
        ports:
        - port: 80
          targetPort: 80
          protocol: TCP
        selector:
          app: canary
        type: NodePort
    2. Run the following command to deploy the canary-svc Service:
      kubectl apply -f canary-svc.yaml
  3. Deploy an Ingress to route requests based on headers.
    1. Create a file named canary-header-ingress.yaml and copy the following content to the file:
      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
            http:
              paths:
                - backend:
                    service:
                      name: canary-svc
                      port:
                        number: 80
                  path: /
                  pathType: Prefix
      • Set alb.ingress.kubernetes.io/canary to true to enable canary annotations.
      • Set alb.ingress.kubernetes.io/canary-by-header and alb.ingress.kubernetes.io/canary-by-header-value to the key and value of the header that you want to match. In this example, the KV pair of the header is set to location: hz. All requests that carry the location: hz header are routed to the new Service version. Requests that carry other headers are matched against other canary release rules based on the priorities of the rules and then routed to the Service versions associated with the matching rules.
    2. Run the following command to deploy an Ingress to route requests based on headers:
      kubectl apply -f canary-header-ingress.yaml
  4. Deploy an Ingress to route requests based on weights.
    1. Create a file named canary-weight-ingress.yaml and copy the following content to the file:
      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
            http:
              paths:
                - backend:
                    service:
                      name: canary-svc
                      port:
                        number: 80
                  path: /
                  pathType: Prefix
      alb.ingress.kubernetes.io/canary-weight: specifies the percentage of traffic routed to the new Service version. In this example, the value is set to 50, which indicates that 50% of the traffic is routed to the new Service version.
    2. Run the following command to deploy an Ingress to route requests based on weights:
      kubectl apply -f canary-weight-ingress.yaml
  5. Check whether the canary release is successful.
    1. Run the following command to query the IP address of the ALB instance:
      kubectl get ing

      Expected 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
    2. Run the following command multiple times to send requests that carry the location: hz header to the Service:
      curl -H Host:demo.domain.ingress.top -H "location:hz" http://alb-ny3ute4r8yevni****.cn-chengdu.alb.aliyuncs.com

      Expected output:

      new

      new is returned for the requests that carry the location: hz header. The requests that carry the location: hz header are routed to the new Service version.

    3. Run the following command multiple times to send requests that do not carry headers to the Service:
      curl -H Host:demo.domain.ingress.top http://alb-ny3ute4r8yevni****.cn-chengdu.alb.aliyuncs.com

      new is returned for 50% of the requests that do not carry headers and old is returned for the remaining 50% of the requests. 50% of the requests that do not carry headers are routed to the new Service version.

    4. Run the following command multiple times to send requests that carry the location: bj header to the Service:
      curl -H Host:demo.domain.ingress.top -H "location:bj" http://alb-ny3ute4r8yevni****.cn-chengdu.alb.aliyuncs.com

      new is returned for 50% of the requests that carry the location: bj header and old is returned for the remaining 50% of the requests. 50% of the requests that carry the location: bj header are routed to the new Service version.

    All requests that carry the location: hz header are routed to the new Service version named canary. Only 50% of the requests that carry other headers and do not carry headers are routed to the new Service version. The canary release is successful.

Step 3: Deprecate the old Service version

After the new Service version runs as expected for a period of time, you need to deprecate the old Service version and keep only the new Service version. To do this, you need to change the Service in the Ingress of the old Service version to the new Service version so that the Ingress can route traffic to the new Service version. Then, delete the canary Ingresses.

  1. Run the following command to change the Service in the tea-ingress.yaml file from tea-svc to canary-svc:
    vim tea-ingress.yaml
    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
                port:
                  number: 80
  2. Run the following command for the modified Ingress to take effect:
    Kubectl apply -f tea-ingress.yaml
  3. Check whether the old Service version is deprecated.
    1. Run the following command multiple times to send requests that carry the location: hz header to the Service:
      curl -H Host:demo.domain.ingress.top -H "location:hz" http://alb-ny3ute4r8yevni****.cn-chengdu.alb.aliyuncs.com

      Expected output:

      new

      new is returned for the requests that carry the location: hz header. Requests that carry the location: hz header are routed to the new Service version.

    2. Run the following command multiple times to send requests that do not carry headers to the Service:
      curl -H Host:demo.domain.ingress.top http://alb-ny3ute4r8yevni****.cn-chengdu.alb.aliyuncs.com

      Expected output:

      new

      new is returned for the requests that do not carry headers to the Service. Requests that do not carry headers to the Service are routed to the new Service version.

    3. Run the following command multiple times to send requests that carry the location: bj header to the Service:
      curl -H Host:demo.domain.ingress.top -H "location:bj" http://alb-ny3ute4r8yevni****.cn-chengdu.alb.aliyuncs.com

      Expected output:

      new

      new is returned for the requests that carry the location: bj header. Requests that carry the location: bj header are routed to the new Service version.

    Requests that carry the location: hz header, requests that carry other headers, and requests that do not carry headers are all routed to the new Service version. The old Service version is deprecated.
  4. Run the following command to delete the canary Ingresses named canary-weight-ingress and canary-header-ingress:
    kubectl delete ing canary-weight-ingress canary-header-ingress