Weighted-Routing(Canary) with Kubernetes and Istio

Mert Açıkportalı
5 min readNov 26, 2019

--

Final Architecture Preview

Weighted-Routing (Canary) for two deployments (versions)

Prerequisites

I’d like you to know that this is an intermediate-advanced topic. Therefore before starting, I assume that you at least know what

are. If you don’t, no worries, I tried to provide the most informative resources to help you understand fast. You can click on the terms and start learning what they are.

Environment Setup

Let’s start with the environment setup. Feel free to skip the installation if you already have the tools.

I used Ubuntu 18.04 LTS Guest Machine with 4 Processors, 16 GB RAM, 30 GB Storage. Resources are given high because running Istio on Minikube is a demanding operation. I’ll provide commands for Ubuntu distro.

minikube

First, you need to install minikube. Follow these steps

# Update your system
sudo apt-get update -y
sudo apt-get upgrade -y
# Install required packages
sudo apt-get install curl wget apt-transport-https -y
# Download latest minikube
wget https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
# Add minikube to $PATH and give executable permission
sudo cp minikube-linux-amd64 /usr/local/bin/minikube
sudo chmod +x /usr/local/bin/minikube
# Verify installation
minikube version

You now have minikube installed.

kubectl

Let’s proceed with kubectl which is a tool for communicating Kubernetes API Server(Control Plane).

sudo apt-get update && sudo apt-get install -y apt-transport-httpscurl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee -a /etc/apt/sources.list.d/kubernetes.listsudo apt-get update
sudo apt-get install -y kubectl
kubectl version -o json

You now have kubectl installed.

Helm

Now, install Helm which is a package manager for Kubernetes. You can think this as yum for Kubernetes.

curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash

You now have Helm installed.

Skip Istio for now, we will install it after creating Minikube Kubernetes cluster.

Create Minikube Cluster

Since Istio is a resource demanding service mesh, we will start our Minikube cluster as follows

sudo minikube start --memory=8192 --cpus=4 --kubernetes --vm-driver none# To run minikube as your user from now on
sudo mv /home/$USER/.kube /home/$USER/.minikube $HOME
sudo chown -R $USER /home/$USER/.kube /home/$USER/.minikube
minikube status

Install Istio

Now we can install Istio to our cluster.

# Download Istio version 1.4.0
curl -L https://git.io/getLatestIstio | ISTIO_VERSION=1.4.0 sh -
cd istio-1.4.0# Deploy Istio Custom Resource Definitions
for i in install/kubernetes/helm/istio-init/files/crd*yaml; do kubectl apply -f $i; done
# Deploy Istio Components
kubectl apply -f install/kubernetes/istio-demo.yaml
# Wait pods to be Running
watch -n1 kubectl get pods -n istio-system
# Enable sidecar injection
kubectl label namespace default istio-injection=enabled
Verify that the istio-system is created by watch command

Now that we have a Minikube single-node Kubernetes Cluster with Istio Service Mesh installed, we can create our service and make two deployments.

As you can see, we have labeled our default namespace with istio-injection=enabled. This means each pod will have its own Istio sidecar. When you deploy a pod, it will contain your container and another sidecar container.

Deploy Two Version for Our Service

I dockerized two NodeJS apps, coded print statements with “Hello Production” and “Hello Feature” to HTML respectively.

Execute below script to create two directories and build an image with two different tags named production and feature.

  • hmerac/nodejs:production
  • hmerac/nodejs:feature
# Create two directories for creating Docker images inside them
mkdir production feature
# Download Dockerfile, two package.json and two server.js
curl https://raw.githubusercontent.com/Hmerac/AWSCSAProNotes/master/Dockerfile | tee production/Dockerfile feature/Dockerfile
curl https://raw.githubusercontent.com/Hmerac/AWSCSAProNotes/master/package.json | tee production/package.json feature/package.jsoncurl https://raw.githubusercontent.com/Hmerac/AWSCSAProNotes/master/server_production.js --output production/server.jscurl https://raw.githubusercontent.com/Hmerac/AWSCSAProNotes/master/server_feature.js --output feature/server.js# Build Docker images
docker build -f production/Dockerfile -t hmerac/nodejs:production ./production
docker build -f feature/Dockerfile -t hmerac/nodejs:feature ./feature# Verify the Docker images
docker images

We now have two Docker images for deployment. Think production tag as your production environment and feature as your development environment. We will deploy feature image using weighted routing and route only 10% traffic to that version.

Let’s deploy our service and these versions to Kubernetes by using these commands

# Deploy our NodeJS service
kubectl apply -f https://raw.githubusercontent.com/Hmerac/AWSCSAProNotes/master/final_solution/istio_components/service.yml
# Make the production deployment for our NodeJS service
kubectl apply -f https://raw.githubusercontent.com/Hmerac/AWSCSAProNotes/master/final_solution/istio_components/deployment_production.yml

Our production system is deployed and traffic is being routed 100%.

All of the traffic is being routed to Production

Let’s create our Istio components to implement weighted routing. Here is the list of the components (Click on them to learn more)

# Create Ingress Gateway
kubectl apply -f https://raw.githubusercontent.com/Hmerac/AWSCSAProNotes/master/final_solution/istio_components/ingress_gateway.yml
# Create Virtual Service
kubectl apply -f https://raw.githubusercontent.com/Hmerac/AWSCSAProNotes/master/final_solution/istio_components/virtual_service.yml
# Create Destination Rule
kubectl apply -f https://raw.githubusercontent.com/Hmerac/AWSCSAProNotes/master/final_solution/istio_components/destination_rule.yml

To make things seem more real, let’s map nodejs.com to our Ingress Gateway’s IP.

echo “$(kubectl get service -n istio-system | grep ingress | awk ‘{print $3}’) nodejs.com” | sudo tee -a /etc/hosts

Make curl requests to the nodejs.com and the response will be “Hello Production” since we haven’t deployed our feature version yet.

Making requests to Ingress Gateway

Let’s deploy our feature version and see if some of our requests hit it.

# Make the feature deployment for our NodeJS service
kubectl apply -f https://raw.githubusercontent.com/Hmerac/AWSCSAProNotes/master/final_solution/istio_components/deployment_feature.yml
One out of nine requests hit Feature version

At this point, you have the full control of weights. You can configure it to 0% and stop the deployment in case of errors or to 100% and switch to feature completely

Stay safe! ✌️

--

--

Mert Açıkportalı
Mert Açıkportalı

Written by Mert Açıkportalı

From Vault 11, the Last Survivor 💫 I have a theoretical degree in Theoretical Physics 👨‍🎓