Cross cutting of a Microservices Architecture
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
Istio and Service Mesh
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
Canary Deployment
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
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
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
Helm
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