Skip to main content

Canary Deployment

Gateway API provides native support for weighted traffic splitting, enabling canary deployments without additional tools or service mesh infrastructure. In this section, we'll deploy a new version of the UI application and progressively shift traffic from the original version to the new one using HTTPRoute weights.

With traditional Kubernetes Ingress, weighted traffic splitting is not natively supported — you would need a service mesh like Istio or App Mesh to achieve this. Gateway API makes it a first-class feature through the backendRefs weight field.

Deploy the new UI version

First, we'll deploy a second version of the UI application (ui-v2) that uses an orange theme to make it visually distinguishable from the original blue theme:

~/environment/eks-workshop/modules/exposing/gateway-api/canary/deployment-ui-v2.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: ui-v2
namespace: ui
labels:
app.kubernetes.io/name: ui
app.kubernetes.io/version: v2
app.kubernetes.io/component: service
app.kubernetes.io/created-by: eks-workshop
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: ui
app.kubernetes.io/version: v2
template:
metadata:
labels:
app.kubernetes.io/name: ui
app.kubernetes.io/version: v2
spec:
containers:
- name: ui
image: public.ecr.aws/aws-containers/retail-store-sample-ui:1.2.1
ports:
- containerPort: 8080
protocol: TCP
env:
- name: RETAIL_UI_THEME
value: "orange"

The key difference is the RETAIL_UI_THEME=orange environment variable, which produces a visually distinct orange-themed UI.

We also need a Service to route traffic to the new pods:

~/environment/eks-workshop/modules/exposing/gateway-api/canary/service-ui-v2.yaml
apiVersion: v1
kind: Service
metadata:
name: ui-v2
namespace: ui
labels:
app.kubernetes.io/name: ui
app.kubernetes.io/version: v2
app.kubernetes.io/created-by: eks-workshop
spec:
selector:
app.kubernetes.io/name: ui
app.kubernetes.io/version: v2
ports:
- port: 8080
targetPort: 8080
protocol: TCP

Apply both resources:

~$kubectl apply -f ~/environment/eks-workshop/modules/exposing/gateway-api/canary/deployment-ui-v2.yaml
~$kubectl apply -f ~/environment/eks-workshop/modules/exposing/gateway-api/canary/service-ui-v2.yaml

Wait for the new pods to be ready:

~$kubectl wait --for=condition=Ready pods -l app.kubernetes.io/version=v2 -n ui --timeout=120s

Apply the 90/10 canary route

Now we'll replace the existing ui-route HTTPRoute with a weighted version that sends 90% of traffic to the original UI and 10% to ui-v2:

~/environment/eks-workshop/modules/exposing/gateway-api/canary/httproute-ui-canary.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: ui-route
namespace: ui
spec:
parentRefs:
- name: retail-store-gateway
namespace: ui
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: ui
port: 80
weight: 90
- name: ui-v2
port: 8080
weight: 10

Notice how the backendRefs field now contains two entries with explicit weight values. The Gateway controller distributes traffic proportionally based on these weights.

Apply the canary HTTPRoute:

~$kubectl apply -f ~/environment/eks-workshop/modules/exposing/gateway-api/canary/httproute-ui-canary.yaml

Test the traffic split

Send multiple requests to the Gateway and observe the distribution. Approximately 10% of responses should come from the orange-themed ui-v2:

~$export GATEWAY_URL=$(kubectl get gateway retail-store-gateway -n ui -o jsonpath='{.status.addresses[0].value}')
~$for i in $(seq 1 20); do curl -s $GATEWAY_URL | grep "theme" ; done
href="/assets/css/theme-default.css"theme: {
href="/assets/css/theme-default.css"theme: {
href="/assets/css/theme-default.css"theme: {
href="/assets/css/theme-default.css"theme: {
href="/assets/css/theme-default.css"theme: {
href="/assets/css/theme-orange.css"theme: {
href="/assets/css/theme-default.css"theme: {
href="/assets/css/theme-default.css"theme: {
href="/assets/css/theme-default.css"theme: {
href="/assets/css/theme-default.css"theme: {
href="/assets/css/theme-default.css"theme: {
href="/assets/css/theme-default.css"theme: {
href="/assets/css/theme-default.css"theme: {
href="/assets/css/theme-orange.css"theme: {
href="/assets/css/theme-default.css"theme: {
href="/assets/css/theme-orange.css"theme: {
href="/assets/css/theme-default.css"theme: {
href="/assets/css/theme-default.css"theme: {
href="/assets/css/theme-default.css"theme: {
href="/assets/css/theme-orange.css"theme: {

You should see that most responses return theme-default while roughly 1-2 out of 20 requests return theme-orange, confirming the 90/10 traffic split is working.

Increase traffic to 50/50

Once you're confident the new version is working correctly, increase the canary weight to 50%:

~/environment/eks-workshop/modules/exposing/gateway-api/canary/httproute-canary-50-50.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: ui-route
namespace: ui
spec:
parentRefs:
- name: retail-store-gateway
namespace: ui
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: ui
port: 80
weight: 50
- name: ui-v2
port: 8080
weight: 50
~$kubectl apply -f ~/environment/eks-workshop/modules/exposing/gateway-api/canary/httproute-canary-50-50.yaml

Test again to see the even split:

~$for i in $(seq 1 20); do curl -s $GATEWAY_URL | grep "theme" ; done

You should now see roughly half of the responses returning the orange theme.

Complete the rollout

When you're satisfied with the new version, shift all traffic to ui-v2 by setting the weights to 0/100:

~/environment/eks-workshop/modules/exposing/gateway-api/canary/httproute-canary-0-100.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: ui-route
namespace: ui
spec:
parentRefs:
- name: retail-store-gateway
namespace: ui
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: ui
port: 80
weight: 0
- name: ui-v2
port: 8080
weight: 100
~$kubectl apply -f ~/environment/eks-workshop/modules/exposing/gateway-api/canary/httproute-canary-0-100.yaml

Verify that all traffic now goes to the new version:

~$for i in $(seq 1 20); do curl -s $GATEWAY_URL | grep "theme" ; done

All responses should now return the orange theme, confirming the full cutover to ui-v2.

http://k8s-ui-retailst-xxxxxxxxxx.us-west-2.elb.amazonaws.com

Summary

In this section we performed a progressive canary deployment using Gateway API's native weighted traffic splitting:

  1. Deployed a new version of the UI with a distinct visual theme
  2. Started with a 90/10 split to test with minimal risk
  3. Increased to 50/50 after validating the new version
  4. Completed the rollout with a 0/100 split

Gateway API vs Ingress comparison

CapabilityGateway APIKubernetes Ingress
Weighted traffic splittingNative via backendRefs weightsNot supported natively
Canary deploymentsBuilt-in, no extra tools neededRequires service mesh or annotations
Cross-namespace routingNative via parentRefsRequires IngressGroup or similar workarounds
Role-oriented modelGatewayClass → Gateway → HTTPRouteSingle Ingress resource
Multiple backends per routeNative with weights and filtersLimited to single backend per path
Progressive rolloutsDeclarative weight updatesRequires external controllers

Gateway API's native traffic splitting makes canary deployments straightforward and declarative, eliminating the need for additional service mesh infrastructure or custom annotations that traditional Ingress requires.