How you heard of Istio?
MicroServices are great. However things get unwieldy pretty quicly. Istio, is basically what you are looking for. It’s a service mesh which does a lot of things. You will unravel in this series.
Prerequisites:
Basic understanding of below as we are not going to talk about these in details
Kubernetes
Docker
Goal:
We are going to deploy an NGINX app hosting our front end and an Express JS app hosting our backend using a Kubernetes deployment yaml.
We will also be creating services for the front end and back end app using Kubernetes Service yaml. The services are of type ClusterIP. You cannot access them outside Kubernetes cluster. This is intentional and we will see why.
We will be using istio to self discovery these services using Istio Virtual Service and expose them to public using Istio Gateway and Istio Ingress rules.
Setup:
At the time article was published.
Istio -> 1.4.3.
Kubernetes -> v1.15.5
ISTIO:cd ~curl -L https://istio.io/downloadIstio | sh -# Add path to bash profile or zshrc
export PATH="~/istio-1.4.3/bin:$PATH"
# We will be setting up istio in our kubernetes cluster in
# istio-system namepsace.
istioctl manifest apply --set profile=demoKubernetes:# We will be deploying our apps in istio-demo to isolate it from
# default namespace
kubectl create ns istio-demo # We will be labeling our istio-demo namespace with
# istio-injection=enabled for istio to detect objects and create
# sidecar for containers inside pod.
kubectl label namespace istio-demo istio-injection=enabled
Explanation:
Its important to understand two concepts:
- Data Plane
- Control Plane
Data Plane for Istio service mesh consists of:
- service proxy
- sidecar container
The data plane uses the service proxy and sidecar container to intercept all ingress and egress network traffic.
Service Proxy: (Envoy)
Service proxy exposes our applications to outside world. It also provide features like service discovery, circuit breaker, timeouts, retries, rewrite uri, health check, Staged Rollout etc.
Sidecar Container: (Envoy)
When ever Kubernetes deploys an app container in the pod, Istio also injects a sidecar called istio proxy alongside the container. Istio proxy intercepts the app container requests/reponse. The proxy responsibility to apply policies like ACL, tele metrics, tracing requests and etc.
Control Plane:
The control pane manages and configures the proxies to route traffic.
Pilot
Pilot provide the features to sidecar we discussed in data plane.
Mixer
Mixer enforces access control and usage policies across the service mesh, and collects telemetry data from the Envoy proxy and other services
Source: https://istio.io/docs/ops/deployment/architecture/arch.svg
Let’s connect the dots with our application
Lets first create the docker images for our kubernetes deployment:
cd client
npm install
npm run build
docker build -t frontend:1.0 .cd server
npm install
docker build -t backend:1.0 .
Inside Client folder:
kubectl apply -f frontend.deploy.yml
The above command deploys our front end app and exposes port 80 on containers.
kubectl get pods -n istio-demo
As you can see in the ready column instead of 1 container in the pod it shows 2 container. The second container is the sidecar istio proxy we discussed early.
Lets create a service to manage our front end deployments.
kubectl apply -f frontend.service.yml
The service is of type cluster ip and it can only be accessed inside the control. Outside world cannot interact with our applications using the service.
Inside Server folder:
kubectl apply -f backend.deploy.yml
You guessed it right. It deployed yet another sidecar istio proxy container for our node backend apps as well.
Let’s create a service to manage our back end deployments. This is of type ClusterIP as well.
kubectl apply -f backend.service.yml
Run the below command to see our services we just created for backend/frontend.
kubectl get svc -n istio-demo
Now let’s have Istio expose our app’s to external world. We do it by creating VirtualService and GateWay.
Gateway:
Let first create gateway to expose ports to outside world. We are exposing port 80 and 3030. The important thing to notice here is to attach an ingress gateway to our gateway. We do that by specifying in selector
selector:
istio: ingressgateway
Wait, is ingressgateway exists? Yes, it does. It was created during our setup. You can verify by running the below commands.
kubectl get svc istio-ingressgateway -n istio-system --show-labels
By default it exposes port 80 for use but not 3030.
We expose port 3030 by editing the above svc.
kubectl edit svc istio-ingressgateway -n istio-system
add the below snippet in the ports
- name: http-3030
nodePort: 31379
port: 3030
protocol: TCP
targetPort: 3030
and save and exit. (wq).
VirtualService:
Any request received by the gateway is forwarded to our Virtual Service. As you can see we attached our above gateway by specifying in gateways (myfirst-gateway) in the yaml file.
The virtual service will forward any request with uri /random to our backend service (node-backend-service.istio-demo.svc.cluster.local) and any uri with / to our front end service (nginx-frontend-service.istio-demo.svc.cluster.local) in the http key.
The destination host nomenclature
<service-name>.<name-space-in-which-service-is-created>.svc.cluster.local
node-backend-service.istio-demo.svc.cluster.local
nginx-frontend-service.istio-demo.svc.cluster.local
Go to browser and type localhost and our app should load. Voila.
You can also view grafana/tracing dashboard by typing below commands.
istioctl dashboard grafana
istioctl dashboard jaeger
Grafana:
Tracing:
We will explore more in the next series. Stay tuned.