loading...

Easy microservices with Kubernetes and Istio ✅ ☸️ ⛵️

sendilkumarn profile image Sendil Kumar N Updated on ・11 min read

Microservices are great

They make your applications

  • Modular & Loosely coupled
  • Faster development & Increased productivity
  • Individual deployment
  • Granular Scaling
  • Fault Isolation

But Microservices are a pain to maintain

With so many moving components, Microservices makes it difficult to maintain and identify the bottlenecks.

Microservices shift the problems from inside the application into the layers between them.

This makes it harder to fix the problems when arises. Because the networks are not ideal always.

Added to that there needs to be a mindset change when we design applications for failure or chaos.

This results in newer problems in:

Connect

Developing applications as microservices means. The applications are split into multiple small/micro/nano/macro services. These services should be capable of running anywhere and everywhere. But in order to work, these services should communicate with each other.

These small services should be interconnected. They should know where the other services live and how to connect with them. Even when the services are running different versions they should be compatible.

They should be consistent and highly available. The connections should be intelligent and configurable.

Secure

These services should be secured. The requests to them should be properly authorized and authenticated.

The traffic between the services should be encrypted, this prevents a man-in-the-middle attack. The requests to any services should be properly audited.

Control

We need to control the services on the fly like providing a new feature to only a set of customers and others. Every time when we change versions (either upgrade or downgrade), we should not turn the services on and off. Instead just enable and disable them on the fly, making it invisible to your end users.

Monitor

Since these services scale up and down autonomously, it is important to monitor or observe them. Observe them for any issues, errors, exceptions, time lag between the request and response. Once we find these bottlenecks we should be able to fix and rollout newer releases fast.

While there are a lot of new applications, projects and products are created to address the problems with Microservices. But still maintaining high availability, resiliency and reliability all together are harder to fix.

Istio - the game changer.

Istio components need not be installed or configured in each service. Instead, it runs along with your services independently. (Yes you heard it right it runs separately)*

Istio makes it easy to create a network of deployed services with load balancing, service-to-service authentication, monitoring, and more, without any changes in service code. — Istio

Istio helps to address these problems. Istio helps to

  • Automatically load balance the traffic between services
  • Configure and Control the routing between services
  • Provides authentication and authorization to secure these services
  • Automatic metrics, logs, and traces collection to observe these services

And the best of all is that you don’t need to change anything in the existing services. Istio is platform independent and designed to run in a variety of environments. — Check out Istio Architecture here

* Separately here refers that they are not inside your application but runs separately.

Code Code Code

Enough talking, let us talk code.

We will use Kotlin Hipster to generate the application.

KHipster is built on top of JHipster. With KHipster generating microservices is not a pain anymore. It is easy simple and faster way to generate a robust Kotlin + Angular / React / Vue based Microservices.

K(J)Hipster is a development platform to generate, develop and deploy Spring Boot + Angular/React Web applications and Spring microservices.

So what are we gonna do today,

  • Generate microservices with KHipster
  • Generate Kubernetes & Istio configuration files for the generated KHipster microservices application
  • Code walkthrough
  • Deploy them on the GCP. (technically on any Kubernetes cluster)

Generate Microservices with KHipster

Generating microservices with KHipster is very simple and easy. Let us create a JDL (JHipster Domain-specific Language) file.

$ mkdir hello-istio
$ cd hello-istio
$ touch app.jdl

Enter the following contents:

// Gateway application
application {
    config {
        baseName gateway,
        applicationType gateway,
        clientFramework react,
        serviceDiscoveryType no
    }
}

// Microservice Application 1
application {
    config {
        baseName application1,
        applicationType  microservice,
        serviceDiscoveryType no,
    }
}

Generate the application by installing KHipster (that is an NPM library.)

$ npm install -g generator-jhipster-kotlin

Once installed run khipster import-jdl application.jdl.

That is it, we have our microservices application ready. You can add entities to the applications and many more check out here for a more detailed guide on JDL and JDL samples.

Generate Kubernetes & Istio configuration files

Create a new folder k8s inside the hello-istio folder.

$ khipster kubernetes

Note: It checks whether you have installed Docker since we need Docker for creating and pushing the images and use them later.

As with other KHipster / JHipster commands, this will ask you a set of questions. Let us answer them.

Let us choose the Microservice Application for the first question.

? Which *type* of application would you like to dep?
    Monolithic Application
  > Microservice Application 

The next question is to link your applications for which you have to generate the configuration files. If you are following this sample folder structure, just use the default path, else (thanks for being creative ✨) use the folder in which you have your microservice applications.

? Enter the root directory where your gateway(s) and microservices are located (../)

The next question is to select the respective microservices applications here.

? Which applications do you want to include in your configuration? (Press <space> to select, <a> to toggle all, <i> to invert selection)
❯◯ application1
 ◯ gateway

Since microservices need monitoring, that helps the developers and operations to understand what is going on and where is the fault.

JHipster provides two options one with our own JHipster-Console. The other is with Prometheus. For the purpose of this example, I will choose none of them.

Do you want to set up monitoring for your applications? (Use arrow keys)
❯ No
  Yes, for logs and metrics with the JHipster Console (based on ELK and Zipkin)
  Yes, for metrics only with Prometheus (only compatible with JHipster >= v3.12)

The next question is about the Kubernetes namespace, let us choose the default for this.

? What should we use for the Kubernetes namespace? (default)

Since we need to create a Docker image and push this into the Docker repository. The next question is the Docker repository name.

? What should we use for the base Docker repository name? sendilkumarn

Let us push the Docker images using docker push command.

? What command should we use for push Docker image to the repository? (docker push)

The next question is whether we need to configure Istio. There are three options here for you to choose from.

  • Not to have Istio at all
  • A Manual sidecar injection.
  • An Automatic sidecar injection using label tags

So what is the difference between Manual / Automatic sidecar injection?

  • In the case of manual, the deployment pod specs are modified to have sidecar related details.
  • In the case of automated, the sidecar is injected at the pod creation time.

Let us choose, Automatic injection. So we need not worry about adding this in every deployment.

Note: Check here for detailed information about sidecar injection.

? Do you want to configure Istio? (Use arrow keys)
  Not required
  Manual sidecar injection (ensure istioctl in $PATH)
❯ Label tag namespace as an automatic injection is already configured

Routing and Load balancing are one of the coolest features that Istio provides out of the box.

Living outside your services they control routing the requests to the services and Load Balance the request between services or various versions of the services.

The next question is whether we need to generate Istio route files. Let us select Yes for the route files.

? Do you want to generate Istio route files?
  No
❯ Yes

The route files help you to configure routing requests, set request timeouts, switch to Https, control traffic, circuit breaking, and health checking.

The next question is the service type for the edge services. Let us use Ingress for this.

? Choose the kubernetes service type for your edge services
  LoadBalancer - Let a kubernetes cloud provider automatically assign an IP
  NodePort - expose the services to a random port (30000 - 32767) on all cluster nodes
❯ Ingress - create ingresses for your services. Requires a running ingress controller

There are three options here

  • Load Balancer — This will create an external IP for the services and you can use that IP to access the application.
  • Nodeport — This will use the cluster IP and expose’s the service via a static port.
  • Ingress — It is a collection of rules that allow inbound connections to the services.

Since we have selected Ingress, the next question is to say a DNS with which we can route the services. If you have a domain name you can use that here, else give a dummy entry here and change your etc/hosts file to match the IP with the Domain name.

? What is the root FQDN for your ingress services (e.g. example.com, sub.domain.co, www.10.10.10.10.xip.io, [namespace.ip]...)? (default.192.168.99.100.nip.io) sendilkumarn.com

If you don’t have the DNS, then edit your /etc/hosts file to have this,

x.x.x.x  sendilkumarn.com

Code walkthrough

It is time 🕰 to check what KHipster has generated.

.
├── README.md
├── application1
│   ├── application1-deployment.yml
│   ├── application1-destination-rule.yml
│   ├── application1-mysql.yml
│   ├── application1-service.yml
│   ├── application1-virtual-service.yml
│   └── jwt-secret.yml
├── gateway
│   ├── gateway-deployment.yml
│   ├── gateway-destination-rule.yml
│   ├── gateway-gateway.yml
│   ├── gateway-mysql.yml
│   ├── gateway-service.yml
│   ├── gateway-virtual-service.yml
│   └── jwt-secret.yml
├── istio
│   ├── grafana-gateway.yml
│   ├── jaeger-gateway.yml
│   └── kiali-gateway.yml
└── kubectl-apply.sh
  • application1 folder contains configuration files for Microservice application
  • gateway folder contains configuration files for Microservice gateway
  • istio folder contains configuration files for Istio gateways
  • kubectl-apply.sh is a bash script to deploy all the services together

Inside the Gateway folder,

The gate-deployment.yaml contains the application configuration for the gateway application deployment.

The gate-destination-rule.yml contains the network definitions related to Load Balancing and connection timeouts.

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: gateway-destinationrule
  namespace: default
spec:
  host: gateway
  trafficPolicy:
    loadBalancer:
      simple: RANDOM
    connectionPool:
      tcp:
        maxConnections: 30
        connectTimeout: 100ms
      http:
        http1MaxPendingRequests: 10
        http2MaxRequests: 100
        maxRequestsPerConnection: 10
        maxRetries: 5
    outlierDetection:
      consecutiveErrors: 5
      interval: 30s
      baseEjectionTime: 60s
  subsets:
    - name: v1
      labels:
        version: 'v1'

In the spec, we mention the host as the gate application.

Then we define the traffic policy

Load Balancer can be either simple or consistent

Simple — pre-configured. By default it supports

  • RoundRobin
  • Least Conn
  • Random
  • Pass through

We have chosen Random here. The Istio team suggests that Random is better than the RoundRobin if we don't have any health configuration. It checks for the services that are healthy and routes the request to it. For more information on this — Check here

The gateway-gateway.yml contains configuration for Istio’s Ingress gateway. This will sit at the edge of the service mesh created by the Istio. It configures exposed ports and protocols and helps to connect to the underlying services.

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: gateway-gateway
  namespace: default
  labels:
    gateway: gateway-gateway
    istio: ingressgateway
spec:
  selector:
    istio: ingressgateway
  servers:
    - port:
        number: 80
        name: http
        protocol: HTTP
      hosts:
        - gateway.sendilkumarn.com
    - port:
        number: 80
        name: http2
        protocol: HTTP2
      hosts:
        - gateway.sendilkumarn.com
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: gateway-gw-virtualservice
  namespace: default
  labels:
    service: gateway-gw-virtualservice
spec:
  hosts:
    - gateway.sendilkumarn.com
  gateways:
    - gateway-gateway
  http:
    - match:
        - uri:
            prefix: /application1/
      route:
        - destination:
            host: application1
    - match:
        - uri:
            prefix: /
      route:
        - destination:
            host: gateway

Note that the hosts in the configuration file are based on the DNS name that we have provided. This makes the entire application easy to reach via the browser.

There is also a virtual service defined in the configuration file. Since Ingress Gateways in Istio doesn’t include any traffic routing configuration (which is quite the opposite to what Kubernetes does). The virtual service here helps to achieve traffic routing.

The gate-service.yml contains the configuration for the microservice gateway service.

The gate-mysql.yml contains the configuration for the MySQL Database. (This file might vary based on the production database that you choose while generating the application.)

The gate-virtual-service.yaml contains the configuration for the virtual service that helps to route the requests in the mesh.

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: gateway-virtualservice
  namespace: default
spec:
  hosts:
    - gateway
  http:
    - route:
        - destination:
            host: gateway
            subset: 'v1'
          weight: 100
      retries:
        attempts: 3
        perTryTimeout: 2s

Similarly, we also have the same set of configuration for the microservices applications.

The Istio folder consists of some gateway for the services that will be running inside the istio-system namespace.

  • graphana - analytics and monitoring
  • jaegar - end to end distributed tracing
  • kiali - Service mesh observability & configuration

Wow, that's a lot of configuration files. But KHipster/ JHipster make your work a lot easier. KHipster FTW.

Deploy the application to the GCP

Now the fun part to deploy the generated application on Google Kubernetes Engine running in Google Cloud.

Log into the Google Cloud Console, you can either create a new project or use the existing one. The project that I have used is amazing-istio

Once the project is created. Create a Kubernetes Cluster inside the project.

Install Google Cloud SDK.

gcloud container clusters create hello-istio --region=us-central1-a --machine-type=n1-standard-2 --num-nodes=8  --cluster-version=1.12.7-gke.22

Here we are creating a cluster with the gcloud tool with a cluster name hello-istio. In the region us-central1-a, with machine type n1-standard-2 (choose this as you need) with a number of nodes 8.

The above command will spin up 8 nodes, Kubernetes cluster. That will be more than enough for us to play with this simple microservices application.

Also, note the — cluster-version parameter, which sets the Kubernetes cluster to version 1.12.7-gke.22.

Note: If you want to change anything here, please feel free to change it as you might like.

You can also use the UI to generate the cluster.

It will take a while for your cluster to get started. Let us go and grab a ☕️ and a 🍪.

Once the cluster is up and running, let us connect to the cluster from your cloud shell (or) your terminal.

gcloud container clusters get-credentials hello-istio --zone us-central1-a --project amazing-istio

Next step, set the admin permissions for the cluster. Open your cloud shell(or) terminal and then use the following command to enable admin permissions.

kubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin --user=$(gcloud config get-value core/account)

Now it is the time to install Istio inside the Kubernetes cluster.

The easiest way to install is to download the latest Istio

curl -L https://git.io/getLatestIstio | sh -

It fetches the latest Istio source. Then add Istio to the path.

export PATH="$PATH:/home/<username>/istio-x.x.x/bin"

Check the Kubernetes version compatibility with the Istio version.

Install the Istio required CRDs

for i in istio-x.x.x/install/kubernetes/helm/istio-init/files/crd*yaml; do kubectl apply -f $i; done

Now apply the istio-demo.yaml file to create Istio related things in the cluster. This will create an istio-system namespace in the cluster and installs all the necessary components inside the cluster.

kubectl apply -f istio-x.x.x/install/kubernetes/istio-demo.yaml

You can check the usage and installation by running

kubectl get pods -n istio-system

This will show the list of pods that are running in the istio-system namespace.

Now lets head over to our generated K8s configuration file in local and start deploying them.

When the KHipster/JHipster Kubernetes completed. It said it is missing some docker images. Now we have to create the Docker image and push it to the Docker repository. Then we can use the Kubernetes cluster to fetch these images and deploy them in the GCP.

To build the Docker images run the following command in both the Microservice Gateway and Application folder.

./mvnw verify -Pprod dockerfile:build

Then we have to tag the built Docker image and push it into the Docker repository.

docker image tag gate <docker-repo-name>/gateway
docker image push <docker-repo-name>/gateway
docker image tag gate <docker-repo-name>/application1 
docker image push <docker-repo-name>/application1

once done head over to the k8s folder and run

Note: If you haven’t connected the cluster to the local terminal, please do the following command

$ gcloud container clusters get-credentials hello-istio --zone us-central1-a --project <your project name>
$ ./kubectl-apply.sh

This will deploy all the services and databases into the Kubernetes cluster. Perfect that is it you have deployed your awesome microservices application with Istio into GKE running on GCP.

Head over to gate.sendilkumarn.com (or) any URL given to check the application up and running.

Congrats 🎉🎉🎉🎉.

If it is your very first application cheers, share your story.

Now all you need is think about crafting your application while JHipster makes it easy to create, develop and deploy your ideas into production.

You can follow me on Twitter.

If you like this article, please leave a like or a comment. ❤️

Posted on Jul 14 '19 by:

sendilkumarn profile

Sendil Kumar N

@sendilkumarn

An explorer wandering in the land of programs. I am passionate about Open Source. "Docendo discimus"

Discussion

markdown guide
 

Thanks for the article. Very instructive just bit confused now with Istio in the landscape.

What about the whole Netflix OSS and Spring Cloud products , Eureka, Histrix, Zuul?
Are those going to be replaced by Istio ?
Should we use them together or are complementary ?

 

The answer is both. Istio is configurable. We can use them with the other libraries like Eureka, Hystrix, Zuul and others or use instead of them.