Back to overview
DevOps

Mastering Canary Deployments: A Step-by-Step Guide with Gateway API

Mastering Canary Deployments: A Step-by-Step Guide with Gateway API

Traffic Splitting with the Gateway API

In Kubernetes, implementing a canary deployment to roll out a new version to a subset of users often relied on Ingress annotations such as nginx.ingress.kubernetes.io/canary. While workable, this approach tied deployment configuration to a specific controller implementation.

The Kubernetes Gateway API includes native traffic splitting through the weight field in HTTPRoute. This gives you a standard way to manage canary releases across supported gateway controllers without proprietary annotations.

Comparing Ingress Annotations and HTTPRoute

Here is how a weighted canary configuration looks in NGINX Ingress compared to the Gateway API.

NGINX Ingress (Annotation-Based)

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-app-canary
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "10"
spec:
  rules:
  - host: app.neneos.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: my-app-v2
            port:
              number: 80
        

Requires a second Ingress resource and controller-specific annotations.

Gateway API (Standard HTTPRoute)

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: my-app-route
spec:
  parentRefs:
  - name: my-gateway
  hostnames:
  - "app.neneos.com"
  rules:
  - backendRefs:
    - name: my-app-stable
      port: 80
      weight: 90
    - name: my-app-canary
      port: 80
      weight: 10
        

Configures relative weights within a single HTTPRoute resource.

Step-by-Step Implementation

1. Prepare Deployments and Services

A canary release requires two distinct Deployments and corresponding Kubernetes Services running simultaneously: the stable version and the release candidate.

apiVersion: v1
kind: Service
metadata:
  name: my-app-stable
spec:
  selector:
    app: my-app
    version: v1.0.0
  ports:
  - name: http
    port: 80
    targetPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: my-app-canary
spec:
  selector:
    app: my-app
    version: v1.1.0
  ports:
  - name: http
    port: 80
    targetPort: 8080

2. Define the HTTPRoute with Weights

The backendRefs field in HTTPRoute accepts multiple backend Services under one rule. Incoming requests are distributed proportionally based on each backend's weight value.

With weights of 90 and 10, 90% of requests go to my-app-stable and 10% go to my-app-canary. As you verify the release candidate, shift the weights (for example 75/25, 50/50, and 0/100) until the new version handles all traffic.

3. Route by Request Header

You can route specific user groups, such as internal testers, to the canary version before exposing it to weighted public traffic. In the Gateway API, place more specific header match rules before the default weighted rule.

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: my-app-route
spec:
  parentRefs:
  - name: my-gateway
  hostnames:
  - "app.neneos.com"
  rules:
  - matches:
    - headers:
      - name: x-beta-tester
        value: "true"
    backendRefs:
    - name: my-app-canary
      port: 80
  - backendRefs:
    - name: my-app-stable
      port: 80
      weight: 95
    - name: my-app-canary
      port: 80
      weight: 5

Automating Traffic Shifts with Progressive Delivery

Manually updating manifest weights in production is slow and error-prone. Progressive delivery operators automate traffic shifting and rollbacks by evaluating live application metrics during the rollout.

Argo Rollouts

Argo Rollouts replaces the Kubernetes Deployment with a Rollout resource. With Gateway API support enabled, Argo Rollouts dynamically adjusts weight values in the target HTTPRoute across defined progression steps and analysis runs.

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: my-app
spec:
  replicas: 5
  strategy:
    canary:
      trafficRouting:
        gatewayAPI:
          httpRoute: my-app-route
      steps:
      - setWeight: 10
      - pause: { duration: 5m }
      - setWeight: 25
      - pause: { duration: 10m }
      - setWeight: 50
      - pause: { duration: 10m }

Flagger

For GitOps pipelines using Flux or standalone operators, Flagger provides automated canary management for Gateway API. Flagger reconciles target HTTPRoutes and evaluates metrics from providers such as Prometheus or Datadog, rolling back automatically if error rates or latencies exceed defined thresholds.

Operational Considerations

  • Metrics and telemetry: Ensure your Gateway controller (such as Envoy Gateway, Istio, Kong, or Azure Application Gateway for Containers) exports request rates and error counts to Prometheus. Canary automation depends on clean HTTP status and latency metrics.
  • Session affinity: If the application requires sticky sessions, check whether your Gateway controller supports SessionPersistence filters on HTTPRoute so users stay on a consistent backend version.
  • Database schema compatibility: Ensure database changes are backward-compatible before starting a canary rollout, because both versions will process live traffic concurrently.
  • Manifest cleanup: After a successful rollout finishes and the stable deployment is updated to the new image, reset the canary weight or remove the canary backendRef until the next release.
#Kubernetes #Canary #Gateway API #DevOps #Argo Rollouts #Traffic Splitting