Head First: HTTP Routing in Kubernetes using Istio

In this blog post, we are going to look at how to use path-based HTTP routing in Kubernetes using a service mesh called Istio. I am going to be using Azure for this blog, but you should be able to customize the steps for any cloud provider easily.

What is a service mesh?

A service mesh ensures that communication among containerized and often ephemeral application infrastructure services is fast, reliable, and secure. The mesh provides critical capabilities including service discovery, load balancing, encryption, observability, traceability, authentication and authorization, and support for the circuit breaker pattern. [1]

What is Istio?

Istio, backed by Google, IBM, and Lyft, is currently the best‑known service mesh architecture. Kubernetes, which was originally designed by Google, is currently the only container orchestration framework supported by Istio. [1]

Let us dive in head first!

The Acme Corp (GitHub) is a multi-national service aggregation company that has offices across the globe. They would like to convert their existing monolithic application to microservices.

The architects have identified two microservices that they would like to start with, namely, the books aggregation microservice and the vinyl album aggregation microservice. The high-level architecture diagram for what we are going to be building is shown below:

High level architecture diagram
High level architecture diagram

The developers have converted the monolithic application into two containerized application and they have pushed the images to docker hub (Vinyl Microservice and Book Microservice).

The book microservice will respond to HTTP requests that have the URL prefix “/BookCatalogue” and the vinyl microservice will respond to the “/VinylProductCatalogue” URL prefix.

Let us start by creating:

  1. 2 SQL databases. One for the vinyl microservice and other for the book microservice
    • Run the migration for vinyl database located here
    • Run the migration for the book database located here
    • Be sure to note down the connection string for the two databases
  2. 1 AKS cluster (You will need at least 2 vCPU and 7 GB of RAM)
    • Make sure that the AKS cluster can access the databases that you created above

Once all the resources have been successfully provisioned, let us start installing Istio

Installing Istio

Fire up the Azure Cloud Shell and fetch credentials for Kubernetes cluster by running the following command

az aks get-credentials --resource-group <<name of your resource group>>
                       --name <<name of your aks cluster>>

Now, create a namespace for Istio by running the following command

kubectl create namespace istio-system --save-config

In order to install Istio, we will be using the YAML file shown below:

apiVersion: install.istio.io/v1alpha2
kind: IstioControlPlane
spec:
  profile: default
  values:
    global:
      defaultNodeSelector:
        beta.kubernetes.io/os: linux
      controlPlaneSecurityEnabled: true
      mtls:
        enabled: false

Line 4: This will install Istio in the default profile. In the default profile we will get: an ingress gateway (used to route traffic), Istio pilot (used for traffic management) and Prometheus Line 8: This will ensure that Istio pods will only run on Linux nodes. Line 9: We enable mutual TLS for the control plane. Line 11: We disable mutual TLS for all services in the data plane

Create this file in the could shell and call it “istio.aks.yaml” and then install Istio by running the following command:

istioctl manifest apply -f istio.aks.yaml logtostderr

After the install is complete, you should be seeing the following output

Output after installing Istio
Output after installing Istio

In order to use Istio, we need to enable Istio injection for the namespace that we plan to use. For this demo, we are going to be using the default namespace, so, let us enable Istio injection by running the following command:

kubectl label namespace default istio-injection=enabled

Deploy the Vinyl Microservice

In this section we will be deploying the vinyl microservice using the YAML file below:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: vinyl-deployment
  labels:
    app: vinyl-api
spec:
  replicas: 1
  selector:
    matchLabels:
      app: vinyl-api
  template:
    metadata:
      labels:
        app: vinyl-api
    spec:
      containers:
      - name: vinyl-api
        image: lalitadithya/acmecorpvinylproductcalalogueapi:latest
        ports:
        - containerPort: 80
        env:
        - name: ConnectionString
          value: "<<Insert your connection string here>>"
---
apiVersion: v1
kind: Service
metadata:
  name: vinyl-api-service
  labels:
    app: vinyl-api
spec:
  ports:
  - name: vinyl-api-inbound
    port: 8000
    targetPort: 80
  selector:
    app: vinyl-api

This YAML file tells Kubernetes to create a service called “vinyl-api-service” that will be listening on port 8000. The image for this service will be pulled from docker hub. Be sure to update the connection string in the YAML file.

Create the above YAML file in the cloud shell and call it “deploy-vinyl.yaml” and deploy the microservice by running the following command:

kubectl apply -f ./deploy-vinyl.yaml

Deploy the book microservice

In this section we will be deploying the book microservice using the YAML file below:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: book-deployment
  labels:
    app: book-api
spec:
  replicas: 1
  selector:
    matchLabels:
      app: book-api
  template:
    metadata:
      labels:
        app: book-api
    spec:
      containers:
      - name: book-api
        image: lalitadithya/acmecorpbookcatalogueapi:latest
        ports:
        - containerPort: 80
        env:
        - name: ConnectionString
          value: "<<Insert your connection string here>>"
---
apiVersion: v1
kind: Service
metadata:
  name: book-api-service
  labels:
    app: book-api
spec:
  ports:
  - name: book-api-inbound
    port: 9000
    targetPort: 80
  selector:
    app: book-api

This YAML file tells Kubernetes to create a service called “vinyl-book-service” that will be listening on port 9000. The image for this service will be pulled from docker hub. Be sure to update the connection string in the YAML file.

Create the above YAML file in the cloud shell and call it “deploy-book.yaml” and deploy the microservice by running the following command:

kubectl apply -f ./deploy-book.yaml

Apply the routing rules

For applying the routing rules, we are going to the use the following YAML:

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: public-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: book-api-vservice
spec:
  hosts:
  - "*"
  gateways:
  - public-gateway
  http:
  - match:
    - uri:
        prefix: /BookCatalogue
    route:
    - destination:
        port:
          number: 9000
        host: book-api-service
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: vinyl-api-vservice
spec:
  hosts:
  - "*"
  gateways:
  - public-gateway
  http:
  - match:
    - uri:
        prefix: /VinylProductCatalogue
    route:
    - destination:
        port:
          number: 8000
        host: vinyl-api-service

Line 1 to 14: These lines create a default Istio gateway called “public-gateway” that will be listening for HTTP connections on port 80 from any host. Line 16 to 33: Here we create a virtual service for the “books” API service. A Virtual Service defines a set of traffic routing rules to apply when a host is addressed. Each routing rule defines matching criteria for traffic of a specific protocol. If the traffic is matched, then it is sent to a named destination service (or subset/version of it) defined in the registry. In this case, we are telling the Istio gateway to route any HTTP traffic that start with “/BookCatalogue” to the “book-api-service” service on port 9000. Line 35 to 52: Here we create a virtual service for the “vinyl” API service. A Virtual Service defines a set of traffic routing rules to apply when a host is addressed. Each routing rule defines matching criteria for traffic of a specific protocol. If the traffic is matched, then it is sent to a named destination service (or subset/version of it) defined in the registry. In this case, we are telling the Istio gateway to route any HTTP traffic that start with “/VinylProductCatalogue” to the “vinyl-api-service” service on port 8000.

Deploy the gateway along with the routing rules by running the following command:

kubectl apply -f ./istio-gateway.yaml

The results

Find out the public IP of your AKS cluster by running the following command:

kubectl get svc istio-ingressgateway -n istio-system

Note down the IP address in the column “EXTERNAL-IP” and use Postman to make HTTP GET requests to the following end points:

  1. http://IP Address/VinylProductCatalogue/api/VinylAlbums
  2. http://IP Address/BookCatalogue/api/Books

The first endpoint should return a list of Vinyl Albums served by the Vinyl Microservice and the second endpoint will return a list of Books served by the Books Microservice.

Using Postman to call the APIs
Using Postman to call the APIs
Using Postman to call the APIs
Using Postman to call the APIs

What did we just do?

We installed Istio on an AKS cluster, deployed two microservices and then an Istio gateway. We configured the gateway to use path-based routing and route traffic to the microservices based on the HTTP URL. We verified that all is good, by hitting the two microservices using Postman.

References

[1] “Ngnix Blog,” Ngnix, [Online]. Available. [Accessed 2020]
Share: Twitter Facebook
Lalit Adithya's Picture

About Lalit Adithya

Lalit is a coder, blogger, architect, and a photographer. He has been coding since 2010 and he has taken business critical websites and desktop apps from inception to production by working in/leading cross functional teams with an Agile focus. He currently focuses on developing & securing cloud native applications.

Bangalore, India https://lalitadithya.com