Canary Deployments with kgateway and Argo Rollouts

Brian Jimerson

Apr 1, 2025

Introduction

A canary deployment is a technique that allows teams to release a new version of software to a subset of consumers (people or other software) in a safe manner. Gradually, more consumers are moved to the latest version of the software until eventually all consumers are using the new version, at which point the old version can be retired.

Canary deployments reduce the risk of releasing new software by testing it with a small group of consumers while continuing to run the stable version for the majority. This allows teams to quickly and safely roll back if issues are found, without impacting the entire consumer base.

Canary deployments are accomplished by deploying the new software version alongside the stable version and splitting the traffic between them. The percentage of traffic to the new version is initially very small; it is gradually increased over time to send more and more consumers to the new version. How the traffic is split and what the promotion and rollback criteria are is up to the software delivery team. The important thing is that the new version can be tested in a safe, incremental manner as load increases until it is considered stable and ready for full promotion.

This technique is akin to the deployment’s namesake: coal miners often sent canaries into mines before entering themselves. Canaries are very sensitive to poisonous gases that can be present in mines. If the canary didn’t show signs of distress, the miners could assume it was safe to enter—or at least that gas levels were not immediately dangerous.

A simple canary deployment might look like this:

Argo Rollouts is a very popular tool for performing canary deployments in Kubernetes environments. According to the Argo Rollouts website:

Argo Rollouts is a Kubernetes controller and set of CRDs that provides advanced deployment capabilities such as blue-green, canary, canary analysis, experimentation, and progressive delivery features to Kubernetes.

Argo Rollouts can leverage many different ingress controllers and service meshes to shift traffic between versions of software, including Kubernetes Gateway API implementations via the Gateway API Plugin. The Kubernetes Gateway API is an open, standard Kubernetes project to address routing in Kubernetes. Kgateway is a CNCF project that implements the Kubernetes Gateway API based on Envoy proxy.

In this post and supporting documents, we will explore how you can use kgateway with Argo Rollouts to easily set up canary deployments for your software. We will use the reviews service that is part of the Istio bookinfo sample application to demonstrate canary deployments with kgateway and Argo Rollouts.

The reviews service has 3 versions available to demonstrate traffic shaping in Istio. We will use it to demonstrate an Argo Rollout in action. We will create an Argo Rollout resource that initially deploys version 1 of the reviews service, then roll out version 2 and observe the progressive shift of traffic to it. Finally, version 2 will be promoted as the stable version.

The installation and configuration of kgateway, Argo Rollouts, and many of the Kubernetes objects are beyond the scope of this post. For a full set of instructions, there is a companion lab available.

Argo Rollouts in Action

By using the Gateway API plugin, Argo Rollouts can leverage kgateway for shifting routes between application versions, as well as more advanced HTTP manipulation, such as header inspection.

First, we create 2 services: 1 for the stable version and 1 for the canary version. These names are arbitrary, and initially, they both have the same selector. Argo Rollouts will take care of managing selectors for us.

---
apiVersion: v1
kind: Service
metadata:
  name: reviews-stable
  labels:
    app: reviews
    service: reviews
spec:
  ports:
  - port: 9080
    name: http
  selector:
    app: reviews
---
apiVersion: v1
kind: Service
metadata:
  name: reviews-canary
  labels:
    app: reviews
    service: reviews
spec:
  ports:
  - port: 9080
    name: http
  selector:
    app: reviews

Then, an HTTP Route is created that references both services. You don’t need to worry about weights for the routes; Argo Rollouts takes care of that for us, too!

---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: bookinfo-reviews
spec:
  parentRefs:
  - name: http-gateway
  hostnames:
  - www.bookinfo.com
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /reviews
    backendRefs:
    - name: reviews-canary
      port: 9080
    - name: reviews-stable
      port: 9080

Finally, an Argo Rollout resource tells Argo how to control traffic to the services as it progresses through the deployment.

Note that the Argo Rollout resource replaces the traditional Kubernetes Deployment resource. It will create and modify the necessary Kubernetes resources for you automatically.

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: reviews-rollout
...
spec:
...
  strategy:
    canary:
      stableService: reviews-stable
      canaryService: reviews-canary
...
      plugins:
        argoproj-labs/gatewayAPI:
          httpRoutes:
          - name: bookinfo-reviews
            useHeaderRoutes: true
            namespace: default
      steps:
      - setCanaryScale:
          replicas: 1
...
      - pause: {}
      - setWeight: 10
      - pause: {duration: 10s}
      - setWeight: 20
      - pause: {duration: 10s}
      - setWeight: 40
      - pause: {duration: 10s}
      - setWeight: 60
      - pause: {duration: 10s}
      - setWeight: 100
...

The Rollout references the stable and canary services as the two services participating in the canary deployment. In the steps stanza, it creates one replica of the canary service, and gradually increases the weight of traffic to the canary service every 10 seconds.

You can view the status of the Rollout using the argo kubectl plugin, and see that 100% of the traffic is going to the stable version, since that is the only version deployed:

kubectl argo rollouts get rollout reviews-rollout --watch
Name:            reviews-rollout
Namespace:       default
Status:          ✔ Healthy
Strategy:        Canary
  Step:          12/12
  SetWeight:     100
  ActualWeight:  100
Images:          docker.io/istio/examples-bookinfo-reviews-v1:1.20.2 (stable)
Replicas:
  Desired:       1
  Current:       1
  Updated:       1
  Ready:         1
  Available:     1
NAME                                   KIND        STATUS     AGE    INFO
⟳ reviews-rollout                      Rollout     ✔ Healthy  48s    
└──# revision:1                                                      
   └──⧉ reviews-rollout-7d484c47b8     ReplicaSet  ✔ Healthy  48s    stable
      └──□ reviews-rollout-7d484c47b8-lhr5r  Pod        ✔ Running  48s    ready:1/1

And viewing the canary and stable services, you can see that Argo Rollouts updated the selector for the same pod:

reviews-canary  ClusterIP  34.118.230.235  <none>  9080/TCP  4m41s  app=reviews,rollouts-pod-template-hash=7d484c47b8
reviews-stable  ClusterIP  34.118.230.94   <none>  9080/TCP  4m41s  app=reviews,rollouts-pod-template-hash=7d484c47b8

When we are ready to perform a canary deployment of our new version, we can easily use the argo kubectl plugin to update the image for the Rollout to version 2 (v2):

kubectl argo rollouts set image reviews-rollout reviews=docker.io/istio/examples-bookinfo-reviews-v2:1.20.2

If we view the Rollout’s status, we notice that the canary’s status is paused. The canary is waiting for a person to tell it that it is OK to proceed with the rollout. We did this by setting the first pause step to empty, which tells Argo to wait for a manual approval before proceeding.

Name:            reviews-rollout
Namespace:       default
Status:          ॥ Paused
Message:         CanaryPauseStep
Strategy:        Canary
  Step:          2/12
  SetWeight:     0
  ActualWeight:  0
Images:          docker.io/istio/examples-bookinfo-reviews-v1:1.20.2 (stable)
                 docker.io/istio/examples-bookinfo-reviews-v2:1.20.2 (canary)
Replicas:
  Desired:       1
  Current:       2
  Updated:       1
  Ready:         2
  Available:     2
NAME                                   KIND        STATUS     AGE    INFO
⟳ reviews-rollout                      Rollout     ॥ Paused   6m7s   
├──# revision:2                                                      
│  └──⧉ reviews-rollout-594c75879c     ReplicaSet  ✔ Healthy  14s    canary
│     └──□ reviews-rollout-594c75879c-t988z  Pod        ✔ Running  14s    ready:1/1
└──# revision:1                                                      
   └──⧉ reviews-rollout-7d484c47b8     ReplicaSet  ✔ Healthy  6m7s   stable
      └──□ reviews-rollout-7d484c47b8-lhr5r  Pod        ✔ Running  6m7s   ready:1/1

We should be able to test the new version before it’s rolled out. To do this, we set a header route in the rollout; the header route uses the Gateway API plugin to inspect HTTP headers. If a request is received that has a header role=qa, that request will be sent to the canary version. So, while the rollout is paused, we can test the canary version simply by setting a header value.

We can continue the rollout by using the argo kubectl plugin again:

kubectl argo rollouts promote reviews-rollout

And observe the rollout as it progresses, until 100% of the traffic is routed to the new version and it is promoted to be the stable version:


Name:            reviews-rollout
Namespace:       default
Status:          ✔ Healthy
Strategy:        Canary
  Step:          12/12
  SetWeight:     100
  ActualWeight:  100
Images:          docker.io/istio/examples-bookinfo-reviews-v1:1.20.2
                 docker.io/istio/examples-bookinfo-reviews-v2:1.20.2 (stable)
Replicas:
  Desired:       1
  Current:       2
  Updated:       1
  Ready:         2
  Available:     2
NAME                                   KIND        STATUS     AGE    INFO
⟳ reviews-rollout                      Rollout     ✔ Healthy  3m2s   
├──# revision:2                                                      
│  └──⧉ reviews-rollout-5468ccc755     ReplicaSet  ✔ Healthy  115s   stable
│     └──□ reviews-rollout-5468ccc755-k8nkt  Pod        ✔ Running  114s   ready:1/1
└──# revision:1                                                      
   └──⧉ reviews-rollout-fb7dcdf44      ReplicaSet  ✔ Healthy  3m2s   delay:18s
      └──□ reviews-rollout-fb7dcdf44-8d7dn  Pod        ✔ Running  3m1s   ready:1/1

Conclusion

In this post we have seen how Argo Rollouts and kgateway can enable teams to perform canary deployments of their software, drastically reducing the risk of releasing new software. This is a powerful example of how kgateway uses the standard Kubernetes Gateway API to allow tools such as Argo Rollouts to be highly interoperable.

For the full set of instructions and to see this in action for yourself, complete the companion lab.