Kubernetes for java Developers part-2

Cross cutting of a Microservices Architecture

 

  • Communication Configuration
  • Security
  • Retry 
  • Metric 
  • Tracing

 

All the cross cutting concerns which we need to add in the each microservices requires lot of time and effort which adds complexity to the services

Solution : Service Mesh with SideCar pattern

  • We can place all not business logic out of Business logic and place it in a sidecar application 
  • Acts as a proxy
  • Third party application
  • Cluster operator can configure it easily
  • Developers can focus on the actual business logic
  • Service Mesh has a control plane which injects the side car proxy in each microservice
  • Istio is the implementation of Service Mesh

Istio and Service Mesh

  • Istio is Service Mesh
  • Service Mesh manages communication between microservices

Create cluster on EKS

eksctl create cluster --name my-kube-cluster --node-type t2.medium --nodes 2 --nodes-min 2 --nodes-max 3

Download istio 

curl -L https://istio.io/downloadIstio | sh -

Add istio client to your path

 export PATH=$PWD/bin:$PATH

install demo configuration file for istio client

istioctl install --set profile=demo -y

Get details of Ingressgateway

kubectl get svc istio-ingressgateway -n istio-system

Set the ingress IP and ports:

export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].port}')
export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].port}')

Check the set variable

echo $SECURE_INGRESS_PORT
443
echo $INGRESS_HOST

echo $INGRESS_PORT
80

Set ingress host

% kubectl get svc istio-ingressgateway -n istio-system
NAME                   TYPE           CLUSTER-IP       EXTERNAL-IP                                                              PORT(S)                                                                      AGE
istio-ingressgateway   LoadBalancer   10.100.119.196   a2ad7951e826a42b7a54bfe2c998ca53-852284782.us-west-2.elb.amazonaws.com   15021:32206/TCP,80:30954/TCP,443:30130/TCP,31400:30349/TCP,15443:31354/TCP   9m50s
% export INGRESS_HOST=a2ad7951e826a42b7a54bfe2c998ca53-852284782.us-west-2.elb.amazonaws.com 
% export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT
% echo $GATEWAY_URL
a2ad7951e826a42b7a54bfe2c998ca53-852284782.us-west-2.elb.amazonaws.com:80

Clone the project 

git@github.com:pulkitpushkarna/kubernetes-spring-boot.git

Checkout to istio-v1-project-image

git checkout istio-v1-project-image

Deploy pods

kubectl create -f helloworld-deployment.yaml

helloworld-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: hello-world-rest-api
  name: hello-world-rest-api
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hello-world-rest-api
  template:
    metadata:
      labels:
        app: hello-world-rest-api
    spec:
      containers:
        - image: pulkitpushkarna/kubernetes-with-spring-boot:v1
          imagePullPolicy: IfNotPresent
          name: hello-world-rest-api
          ports:
            - containerPort: 8080

Get pods

kubectl get pod

You will observe that one container is there in the pod 

Delete the deployment

kubectl delete -f helloworld-deployment.yaml

Add a namespace label to instruct Istio to automatically inject Envoy sidecar proxies when you deploy your application

kubectl label namespace default istio-injection=enabled

Now execute the deployment file

kubectl create -f helloworld-deployment.yaml

Get pods

kubectl get pods

You will observe that there are 2 containers in the pod. One is istio proxy and other one is app container

Execute service file

kubectl create -f helloworld-service.yaml
apiVersion: v1
kind: Service
metadata:
  labels:
    app: hello-world-rest-api
  name: hello-world-rest-api
  namespace: default
spec:
  #type: LoadBalancer
  ports:
    - port: 8080
      name: http
  selector:
    app: hello-world-rest-api

helloworld-service.yaml

Execute the gateway file

kubectl apply -f creating-http-gateway.yaml

creating-http-gateway.yaml

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: http-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
    - port:
        number: 80
        name: http
        protocol: HTTP
      hosts:
        - "*"

Execute the virtual Service file

kubectl apply -f creating-virtualservice-external.yaml

creating-virtualservice-external.yaml

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: helloworld-virtual-services
spec:
  hosts:
    - "*"
  gateways:
    - http-gateway                      # 1
  http:
    - match:
        - uri:
            prefix: /
      route:
        - destination:
            host: hello-world-rest-api             # 2
            port:
              number: 8080

Validate your network

istioctl analyze

Now access deployed application with gateway

pulkitpushkarna@pulkit-pushkarna kubenetes-spring-boot % echo $GATEWAY_URL
a2ad7951e826a42b7a54bfe2c998ca53-852284782.us-west-2.elb.amazonaws.com:80

Enter generated Url on browser now you should be able to access our deployed application

Checkout to branch

git checkout istion-v2-project-image

In the helloworld-deployment.yaml of thids branch replica is set to 2

kubectl delete -f helloworld-deployment.yaml

Delete the existing deployment

Execute the deployment file

kubectl apply -f helloworld-deployment.yaml 

If you try to access the your pods by gateway url you will observe that load balancing is takin place between 2 deployed apps

Exercise 1

  • Set up instio on the your kubernetes cluster
  • Make the configurations to access external Ip of load balancer via istioingressgateway.
  • Deploy the hello world deployment, service, gateway and virtual service.
  • Try to access app endpoint from ELB load balancer external IP

Canary Deployment

  • A canary deployment is a deployment strategy that releases an application or service incrementally to a subset of users.
  • All infrastructure in a target environment is updated in small phases (e.g: 2%, 25%, 75%, 100%)
  • A canary release is the lowest risk-prone, compared to all other deployment strategies, because of this control.

execute deployment file for canary deployment

kubectl apply -f helloworld-v2-deployment.yaml 

helloworld-v2-deployment.yaml

apiVersion: v1
kind: Service
metadata:
  name: hello-world-rest-api
  labels:
    app: hello-world-rest-api
spec:
  ports:
    - port: 8080
      name: http
  selector:
    app: hello-world-rest-api
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-world-rest-api-v1
  labels:
    version: v1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hello-world-rest-api
      version: v1
  template:
    metadata:
      labels:
        app: hello-world-rest-api
        version: v1
    spec:
      containers:
        - name: hello-world-rest-api
          image: pulkitpushkarna/kubernetes-with-spring-boot:v1
          imagePullPolicy: IfNotPresent #Always
          ports:
            - containerPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: hello-world-rest-api-v2
  labels:
    version: v2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hello-world-rest-api
      version: v2
  template:
    metadata:
      labels:
        app: hello-world-rest-api
        version: v2
    spec:
      containers:
        - name: hello-world-rest-api
          image: pulkitpushkarna/kubernetes-with-spring-boot:v2
          imagePullPolicy: IfNotPresent #Always
          ports:
            - containerPort: 8080

Deploy virtual service for canary deployment

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: helloworld-virtual-services
spec:
  hosts:
    - "*"
  gateways:
    - http-gateway
  http:
    - match:
        - uri:
            exact: /
      route:
        - destination:
            host: hello-world-rest-api
            subset: v1
          weight: 10
        - destination:
            host: hello-world-rest-api
            subset: v2
          weight: 90
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: hello-world-rest-api
spec:
  host: hello-world-rest-api
  subsets:
    - name: v1
      labels:
        version: v1
    - name: v2
      labels:
        version: v2
kubectl apply -f hello-worldcanary.yaml

If we try to access the loadbalancer we will observe that 90 % traffic goes to v2 and 10 % goes to v1

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: student-rest-api
  name: student-rest-api
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: student-rest-api
  template:
    metadata:
      labels:
        app: student-rest-api
    spec:
      containers:
        - image: pulkitpushkarna/student-microservice
          imagePullPolicy: IfNotPresent
          name: student-rest-api
          ports:
            - containerPort: 8080
kubectl apply -f student-deployment.yaml

Setting up student microservice

apiVersion: v1
kind: Service
metadata:
  labels:
    app: student-rest-api
  name: student-rest-api
  namespace: default
spec:
  #type: LoadBalancer
  ports:
    - port: 8080
      name: http
  selector:
    app: student-rest-api
kubectl apply -f student-service.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: http-gateway-student
spec:
  selector:
    istio: ingressgateway
  servers:
    - port:
        number: 80
        name: http
        protocol: HTTP
      hosts:
        - "*"
kubectl apply -f student-gateway.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: helloworld-virtual-services
spec:
  hosts:
    - "*"
  gateways:
    - http-gateway-student
  http:
    - match:
        - uri:
            exact: /students
      route:
        - destination:
            host: student-rest-api
            port:
              number: 8080
kubectl apply -f student-virtualsewrvice.yaml

After executing all student related yaml files you will observe that you can access all students via /students endpoint and Single student via /students/id endpoint

Load-balancer-external-ip/students
Load-balancer-external-ip/students/1

Now inside the student-virtualsewrvice.yaml change keyword prefix to exact you will obeserve that you will only be able to access following API

Load-balancer-external-ip/students

Difference between exact and Prefix

Data visualisation by Kiali

  • Kiali is a management console for an Istio-based service mesh
  • It provides dashboards, observability, and lets you operate your mesh with robust configuration and validation capabilities.
  • It shows the structure of your service mesh by inferring traffic topology and displays the health of your mesh.

Set up kiali

kubectl get svc -n istio-system

Check for services in istio-system namespace

Go to /istio-1.11.1/samples/addons folder

Run following command to install kiali

 kubectl apply -f kiali.yaml

Port forwarding for kiali

kubectl port-forward svc/kiali -n istio-system 20001

Execute bookinfo.yaml

kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml

Execute virtual service for hello-world

kubectl apply -f creating-virtualservice-external.yaml

Execute following command to create traffic

watch curl http://aeee8b946ee12489a8f0a36f215a0dfe-153539747.us-west-2.elb.amazonaws.com/

Grafana

  •  Grafana is a multiple platform open source analytics and interactive visualization web application
  • It provides charts, graphs, and alerts for the web when connected to supported data sources
  • As a visualization tool, Grafana is a popular component in monitoring stacks.
  • It can be use to monitor kubernetes cluster.

Prometheus

  • Prometheus is a free software application used for Event Monitoring and alerting.
  • It records real-time metrics in a time series database (allowing for high dimentianality built using a Http pull model, with flexible queries and real-time alerting.

Setting up prometheus and grafana

kubectl apply -f grafana.yaml  
kubectl apply -f prometheus.yaml 

Go to /istio-1.11.1/samples/addons folder and execute the command below

Port Forwarding for grafana

kubectl port-forward svc/grafana -n istio-system 3000

Some handy commands to interact with clusters

kubectl config view

View cluster configruration

Cluster info

kubectl cluster-info

Get list of clusters

kubectl config get-contexts
kubectl config current-context

Get Current cluster

kubectl config use-context <context-name>

Set context

eksctl delete cluster --name my-kube-cluster

Delete cluster

Exercise 2

  • Perform Canary deployment for hello-world application.
  • Deploy student microservice.
  • Test difference between exact and prefix keywords in virtual service for the student microservice.
  • Use kiali for data visualisation.
  • Use grafana and prometheus for monitoring.

Helm

  • helm helps you manage Kubernetes applications
  • Helm Charts help you define, install, and upgrade even the most complex Kubernetes application.​
  • Following are the features of Helm
    • ​Manage Complexity
    • Easy updates
    • Simple sharing
    • Rollbacks

Instructions to install helm

https://helm.sh/docs/intro/install/

Start Minikube

minikube start 

Make a dir

mkdir my-helm-app

Inside my-helm-app dir create a file Chart.yaml and templates folder

pulkitpushkarna@pulkit-pushkarna ~ % cd my-helm-app 
pulkitpushkarna@pulkit-pushkarna my-helm-app % touch Chart.yaml
pulkitpushkarna@pulkit-pushkarna my-helm-app % mkdir templates

Enter the following configuration in Chart.yaml file

apiVersion: v1
name: my-helm-app # Name should be same as name of the parent folder
version: 0.1.0
appVersion: v1
description: This is a demo chart

In the templates folder place copy the webserver.yaml file from kubernetes-spring-boot project

cp /<path-to-project>/kubenetes-spring-boot/webserver.yaml .

Go to the previous folder and run the install command

pulkitpushkarna@pulkit-pushkarna templates % cd ..
pulkitpushkarna@pulkit-pushkarna my-helm-app % helm install my-help-app .

Check your cluster

kubectl get all 

Run helm list command

pulkitpushkarna@pulkit-pushkarna my-helm-app % helm list
NAME       	NAMESPACE	REVISION	UPDATED                             	STATUS  	CHART            	APP VERSION
my-help-app	default  	1       	2021-08-27 18:22:24.110505 +0530 IST	deployed	my-helm-app-0.1.0	v1   

Copy webserver-service.yaml in templates directory

pulkitpushkarna@pulkit-pushkarna my-helm-app % cd templates 
pulkitpushkarna@pulkit-pushkarna templates % cp ~/projects/kubenetes-spring-boot/webserver-service.yaml .
pulkitpushkarna@pulkit-pushkarna templates % ls
webserver-service.yaml	webserver.yaml

We have added webserver-service so we will update the version of the chart

pulkitpushkarna@pulkit-pushkarna templates % cd ..
pulkitpushkarna@pulkit-pushkarna my-helm-app % vim Chart.yaml
apiVersion: v1
name: my-helm-app # Name should be same as name of the parent folder
version: 0.2.0 # version changed
appVersion: v1
description: This is a demo chart

Update the helm chart

pulkitpushkarna@pulkit-pushkarna my-helm-app % helm upgrade my-help-app .
Release "my-help-app" has been upgraded. Happy Helming!
NAME: my-help-app
LAST DEPLOYED: Fri Aug 27 18:38:06 2021
NAMESPACE: default
STATUS: deployed
REVISION: 2
TEST SUITE: None
pulkitpushkarna@pulkit-pushkarna my-helm-app % helm list
NAME       	NAMESPACE	REVISION	UPDATED                             	STATUS  	CHART            	APP VERSION
my-help-app	default  	2       	2021-08-27 18:38:06.122446 +0530 IST	deployed	my-helm-app-0.2.0	v1  

Check cluster for the service which we have created

kubectl get all

Run the deployed application on browser

minikube service webserver-service

Rollback to previous revision

pulkitpushkarna@pulkit-pushkarna my-helm-app % helm rollback my-help-app 1 

You can check your cluster webserver-service is removed from the cluster because it was not there in the first revision

Go back to the revision 2 you will notice that service is back

helm rollback my-help-app 2

Uninstall help chart

helm uninstall my-help-app

Parameterized charts

create values.yaml file

pulkitpushkarna@pulkit-pushkarna my-helm-app % touch values.yaml
pulkitpushkarna@pulkit-pushkarna my-helm-app % vim values.yaml
pulkitpushkarna@pulkit-pushkarna my-helm-app % cat values.yaml 
replicaCount: 1
pulkitpushkarna@pulkit-pushkarna my-helm-app % cd templates 
pulkitpushkarna@pulkit-pushkarna templates % ls
webserver-service.yaml	webserver.yaml
pulkitpushkarna@pulkit-pushkarna templates % vim webserver.yaml 

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mywebserver
  labels:
    app: spring-boot-app
spec:
  replicas: {{ .Values.replicaCount}}
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
  selector:
    matchLabels:
      app: spring-boot-app
  template:
    metadata:
      labels:
        app: spring-boot-app
    spec:
      containers:
        - name: my-spring-boot-app
          image: pulkitpushkarna/kubernetes-with-spring-boot:v1
          ports:
            - containerPort: 8080

Introduce expression for replicaCount in webserver.yaml

Change the yaml chart version

pulkitpushkarna@pulkit-pushkarna templates % cd ..
pulkitpushkarna@pulkit-pushkarna my-helm-app % vim Chart.yaml 

apiVersion: v1
name: my-helm-app # Name should be same as name of the parent folder
version: 0.3.0
appVersion: v1
description: This is a demo chart

Install helm chart you will observer that only one replica is created for webserver

pulkitpushkarna@pulkit-pushkarna my-helm-app % helm install my-helm-app .
NAME: my-helm-app
LAST DEPLOYED: Fri Aug 27 19:16:20 2021
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
pulkitpushkarna@pulkit-pushkarna my-helm-app % kubectl get all

Uninstall app

helm uninstall my-helm-app

Install app by providing replicaCount 

helm install my-helm-app . --set replicaCount=3

Change replica count without uninstalling the helm chart

helm upgrade my-helm-app . --set replicaCount=2

Parametized app version

pulkitpushkarna@pulkit-pushkarna my-helm-app % helm uninstall my-helm-app                     
release "my-helm-app" uninstalled
pulkitpushkarna@pulkit-pushkarna my-helm-app % vim values.yaml 

replicaCount: 1
myAppVersion: pulkitpushkarna/kubernetes-with-spring-boot:v1
pulkitpushkarna@pulkit-pushkarna my-helm-app % cd templates 
pulkitpushkarna@pulkit-pushkarna templates % vim webserver.yaml 

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mywebserver
  labels:
    app: spring-boot-app
spec:
  replicas: {{ .Values.replicaCount}}
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
  selector:
    matchLabels:
      app: spring-boot-app
  template:
    metadata:
      labels:
        app: spring-boot-app
    spec:
      containers:
        - name: my-spring-boot-app
          image: {{ .Values.myAppVersion}}
          ports:
            - containerPort: 8080
pulkitpushkarna@pulkit-pushkarna my-helm-app % helm uninstall my-helm-app
release "my-helm-app" uninstalled
pulkitpushkarna@pulkit-pushkarna my-helm-app % helm install my-helm-app . --set myAppVersion=pulkitpushkarna/kubernetes-with-spring-boot:v2
NAME: my-helm-app
LAST DEPLOYED: Fri Aug 27 19:58:33 2021
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None

Exercise 3

  • Start minikube
  • Create helm chart for the deployment and webserver.yaml and webserver-service.yaml.
  • Try to access deployed webservice from minkube service command.
  • Parameterise replicas parameter of the yaml file webserver.yaml file in your template folder.

Kubernetes for java Developers part-2

By Pulkit Pushkarna

Kubernetes for java Developers part-2

  • 682