Canary ¶
Ingress Nginx Has the ability to handle canary routing by setting specific annotations, the following is an example of how to configure a canary deployment with weighted canary routing.
Create your main deployment and service ¶
This is the main deployment of your application with the service that will be used to route to it
echo "
+---
+# Deployment
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: production
+ labels:
+ app: production
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: production
+ template:
+ metadata:
+ labels:
+ app: production
+ spec:
+ containers:
+ - name: production
+ image: registry.k8s.io/ingress-nginx/e2e-test-echo@sha256:6fc5aa2994c86575975bb20a5203651207029a0d28e3f491d8a127d08baadab4
+ ports:
+ - containerPort: 80
+ env:
+ - name: NODE_NAME
+ valueFrom:
+ fieldRef:
+ fieldPath: spec.nodeName
+ - name: POD_NAME
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.name
+ - name: POD_NAMESPACE
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.namespace
+ - name: POD_IP
+ valueFrom:
+ fieldRef:
+ fieldPath: status.podIP
+---
+# Service
+apiVersion: v1
+kind: Service
+metadata:
+ name: production
+ labels:
+ app: production
+spec:
+ ports:
+ - port: 80
+ targetPort: 80
+ protocol: TCP
+ name: http
+ selector:
+ app: production
+" | kubectl apply -f -
+
Create the canary deployment and service ¶
This is the canary deployment that will take a weighted amount of requests instead of the main deployment
echo "
+---
+# Deployment
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: canary
+ labels:
+ app: canary
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: canary
+ template:
+ metadata:
+ labels:
+ app: canary
+ spec:
+ containers:
+ - name: canary
+ image: registry.k8s.io/ingress-nginx/e2e-test-echo@sha256:6fc5aa2994c86575975bb20a5203651207029a0d28e3f491d8a127d08baadab4
+ ports:
+ - containerPort: 80
+ env:
+ - name: NODE_NAME
+ valueFrom:
+ fieldRef:
+ fieldPath: spec.nodeName
+ - name: POD_NAME
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.name
+ - name: POD_NAMESPACE
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.namespace
+ - name: POD_IP
+ valueFrom:
+ fieldRef:
+ fieldPath: status.podIP
+---
+# Service
+apiVersion: v1
+kind: Service
+metadata:
+ name: canary
+ labels:
+ app: canary
+spec:
+ ports:
+ - port: 80
+ targetPort: 80
+ protocol: TCP
+ name: http
+ selector:
+ app: canary
+" | kubectl apply -f -
+
Create Ingress Pointing To Your Main Deployment ¶
Next you will need to expose your main deployment with an ingress resource, note there are no canary specific annotations on this ingress
echo "
+---
+# Ingress
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: production
+ annotations:
+spec:
+ ingressClassName: nginx
+ rules:
+ - host: echo.prod.mydomain.com
+ http:
+ paths:
+ - pathType: Prefix
+ path: /
+ backend:
+ service:
+ name: production
+ port:
+ number: 80
+" | kubectl apply -f -
+
Create Ingress Pointing To Your Canary Deployment ¶
You will then create an Ingress that has the canary specific configuration, please pay special notice of the following:
- The host name is identical to the main ingress host name
- The
nginx.ingress.kubernetes.io/canary: "true"
annotation is required and defines this as a canary annotation (if you do not have this the Ingresses will clash) - The
nginx.ingress.kubernetes.io/canary-weight: "50"
annotation dictates the weight of the routing, in this case there is a "50%" chance a request will hit the canary deployment over the main deploymentecho " +--- +# Ingress +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: canary + annotations: + nginx.ingress.kubernetes.io/canary: \"true\" + nginx.ingress.kubernetes.io/canary-weight: \"50\" +spec: + ingressClassName: nginx + rules: + - host: echo.prod.mydomain.com + http: + paths: + - pathType: Prefix + path: / + backend: + service: + name: canary + port: + number: 80 +" | kubectl apply -f - +
Testing your setup ¶
You can use the following command to test your setup (replacing INGRESS_CONTROLLER_IP with your ingresse controllers IP Address)
for i in $(seq 1 10); do curl -s --resolve echo.prod.mydomain.com:80:$INGRESS_CONTROLLER_IP echo.prod.mydomain.com | grep "Hostname"; done
+
You will get the following output showing that your canary setup is working as expected:
Hostname: production-5c5f65d859-phqzc
+Hostname: canary-6697778457-zkfjf
+Hostname: canary-6697778457-zkfjf
+Hostname: production-5c5f65d859-phqzc
+Hostname: canary-6697778457-zkfjf
+Hostname: production-5c5f65d859-phqzc
+Hostname: production-5c5f65d859-phqzc
+Hostname: production-5c5f65d859-phqzc
+Hostname: canary-6697778457-zkfjf
+Hostname: production-5c5f65d859-phqzc
+