Canary Deploys with Kubernetes

Canary Deploys with Kubernetes

This guide shows how to use canary deploys in kubernetes using a service object to split direct traffic to two different deployments

gcloud config set compute/zone us-central1-a

# Set dynamically on Cloudshell or set explicitly if local
export PROJECT_ID=$(gcloud info --format='value(config.project)')

Enable APIs

gcloud services enable container.googleapis.com --async
gcloud services enable containerregistry.googleapis.com --async
gcloud services enable cloudbuild.googleapis.com --async
gcloud services enable sourcerepo.googleapis.com --async

Create the cluster

gcloud container clusters create test-cluster 
gcloud container clusters get-credentials test-cluster

Code the Application

Using Cloud Shell, write a simple Node.js server that you’ll deploy to Kubernetes Engine:

server.js

var http = require('http');
var handleRequest = function(request, response) {
  response.writeHead(200);
  response.end("Hello World!  -  V1");
}
var www = http.createServer(handleRequest);
www.listen(8080);
node server.js

Use the built-in Web preview feature of Cloud Shell to open a new browser tab and proxy a request to the instance you just started on port 8080. If you don’t see this feature in the Cloud Shell toolbar, click Navigation menu to close the left pane.)

A new browser tab will open to display your results:

Create your Docker Image

Dockerfile

FROM node:6.9.2
EXPOSE 8080
COPY server.js .
CMD node server.js
docker build -t gcr.io/$PROJECT_ID/hello-node:v1 .
 
docker run -it --rm -p 8080:8080 gcr.io/$PROJECT_ID/hello-node:v1

To see your results you can use the web preview feature of Cloud Shell:

gcloud docker -- push gcr.io/$PROJECT_ID/hello-node:v1

Create your Deployment resource

Create a deployment.yaml file that describes the details of your deployment

deployment.yaml

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: hello
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: hello
        track: prod
    spec:
      containers:
        - name: hello
          image: gcr.io/[PROJECT_ID]/hello-node:v1
          ports:
          - name: http-server
            containerPort: 8080

Expose it with a service

service.yaml

apiVersion: v1
kind: Service
metadata:
  name: hello-service
  labels:
    app: hello
spec:
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: http-server
  selector:
    app: hello

Deploy to Kubernetes

kubectl apply -f .

kubectl get deployments

kubectl get services

View your deployment

Now that you see the IP address, open your browser to that address in my case that http://35.226.58.213/ and you should see

Hello World! - V1

Create a new V2 Docker image

server.js

var http = require('http');
var handleRequest = function(request, response) {
  response.writeHead(200);
  response.end("Hello World!  -  V2");
}
var www = http.createServer(handleRequest);
www.listen(8080);
docker build -t gcr.io/$PROJECT_ID/hello-node:v2 .
 
gcloud docker -- push gcr.io/$PROJECT_ID/hello-node:v2

Create and deploy a new Canary deployment

deployment-canary.yaml

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: hello-canary
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: hello
        track: canary
    spec:
      containers:
        - name: hello
          image: gcr.io/[PROJECT_ID]/hello-node:v2
          ports:
          - name: http-server
            containerPort: 8080

Create your deployment and service on Kubernetes with the apply command

kubectl apply -f ./deployment-canary.yaml

Retrieve the LoadBalancer IP again

kubectl get services
 
 
while true; sleep 1; do curl http://35.226.58.213; echo \n;  done

Which should return something like

Hello World!  - V1n
Hello World!  - V1n
Hello World!  - V2n
Hello World!  - V1n