Weighted-Routing(Canary) with Kubernetes and Istio
Final Architecture Preview
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 kubectlkubectl 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/.minikubeminikube 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
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/Dockerfilecurl 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 ./productiondocker 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%.
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.
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
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! ✌️