Book Details Sample Application
In this tutorial, we are going to discuss about virtual services, gateway configuration and destination rules by deploying the book details sample application as a part of the cluster.
While discussing about Istio installation we deployed a sample application, that is book details sample application.
Now, let us have some detailed understanding. Within the application we had 4 microservices that is 1 product page made of Python and 3 versions of reviews made of Java and details page made of Ruby and the ratings made with node JS.
Book Details Sample Application Overview
We don’t need to worry about the technology by which these microservices are deployed. All we need to worry is how the functionality can be controlled using the Istio.
So within Java we do have 3 versions of microservices. That is version 1, version 2 and version 3. The way how we can identify is version 1 is not going to display any stars and version 2 is going to display the stars in black color and version 3 going to display the stars in red color.
So we call that as subset within that particular services. Why do we need that specific subset? That will be controlled within the destination rules what subset can be accessed and what percentage of the requests can be accessed and who can access. All that control can be done using that specific subset.
And whenever I am deploying the application, the application will get deployed behind the ingress controller and by default, the ingress controller not going to allow any traffic into the cluster.
So to allow the traffic we need to create the gateway. Let’s create the entities one after the other. I am into the server. Let me list what are all the entities available.
ashok@waytoeasylearn:~$ kubectl get all
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.152.183.1 <none> 443/TCP 4h46m
Deploy the sample application
So here, I do not have any services or deployment or pods. Let me go ahead and deploy the sample application bookinfo.yaml.
root@cluster-node:~/istio-1.10.0# kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
service/details created
serviceaccount/bookinfo-details created
deployment.apps/details-v1 created
service/ratings created
serviceaccount/bookinfo-ratings created
deployment.apps/ratings-v1 created
service/reviews created
serviceaccount/bookinfo-reviews created
deployment.apps/reviews-v1 created
deployment.apps/reviews-v2 created
deployment.apps/reviews-v3 created
service/productpage created
serviceaccount/bookinfo-productpage created
deployment.apps/productpage-v1 created
I deployed within the default namespace itself so all the entities should get created. Within each pod I am going to have two containers the reason because Istio is enabled.
root@cluster-node:~/istio-1.10.0# kubectl get pods
NAME READY STATUS RESTARTS AGE
details-v1-79f774bdb9-c4vn8 2/2 Running 0 20s
productpage-v1-6b746f74dc-92qn8 2/2 Running 0 20s
ratings-v1-b6994bb9-cnggv 2/2 Running 0 19s
reviews-v1-545db77b95-62vs4 2/2 Running 0 20s
reviews-v2-7bf8c9648f-mmp2h 2/2 Running 0 20s
reviews-v3-84779c7bbc-l2pbr 2/2 Running 0 20s
So by default it’s going to inject the proxy as well. So once the containers get created. We will get into the yaml file and have some better understanding. You can refer Git hub repository here where all the required services, pods everything will get created.
We don’t need to worry about the internal details. It’s a sample application. As it is, I am going to execute. So the next thing that I’m going to create is the destination rules.
Destination Rules
You can refer here for complete destination rules. So whenever I’m going to access the product page that should land with the subset version 1 with the label v1.
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: productpage
spec:
host: productpage
subsets:
- name: v1
labels:
version: v1
The same way I do have reviews and I am going to create three subsets. That is subsets for version 1, version 2, version 3.
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: reviews
spec:
host: reviews
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
- name: v3
labels:
version: v3
So here name: v1 is just the name and within the name v1, I am going to use the label version as v1 as the subset. Similarly for v2 and v3 as well.
And coming to the ratings destination rules,
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: ratings
spec:
host: ratings
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
- name: v2-mysql
labels:
version: v2-mysql
- name: v2-mysql-vm
labels:
version: v2-mysql-vm
These are all the subset that I am defining what is the version that should be used for any specific name of that subset.
Gateway
Now I will create the gateway.
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: bookinfo-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- '*'
So here, I created the gateway with the name bookinfo-gateway that is just a gateway where it is going to get applied within the default Istio controller ingress gateway and it is going to allow the protocol http that is in port 80 from all the host (* means all).
So here the gateway, it will get created. It’s going to allow all the host coming from the port 80. And this is where the virtual service going to get created and that virtual service is for the gateway coming from all the host.
Virtual Service
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: bookinfo
spec:
hosts:
- '*'
gateways:
- bookinfo-gateway
http:
- match:
- uri:
exact: /productpage
- uri:
prefix: /static
- uri:
exact: /login
- uri:
exact: /logout
- uri:
prefix: /api/v1/products
route:
- destination:
host: productpage
port:
number: 9080
So here it is going to match for this specific suffix within the uri. Whenever it is matching this specific suffix /product page, /static, /login, /logout and /api/v1/products it will land up with the product page host. And in our case that is the service that’s going to run within the cluster in the port 9080.
root@cluster-node:~/istio-1.10.0# kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
details ClusterIP 10.97.32.38 9080/TCP 32m
kubernetes ClusterIP 10.96.0.1 443/TCP 14d
productpage ClusterIP 10.104.193.125 9080/TCP 32m
ratings ClusterIP 10.98.209.205 9080/TCP 32m
reviews ClusterIP 10.102.73.7 9080/TCP 32m
Here I am going to have a service running with the name productpage 9080.
So anything that is landing with this specific uri will be taken to this particular host or the pod having this specific host and the port 9080 and any request coming into the cluster from the port 80 will be allowed and I’m going to allow from all the host.
So basically, I’m going to create a gateway to allow all host from port 80 and I will be having a virtual service with all the rules in terms of what pod to be taken into. Now virtual service also I will be creating it. And along with that, I will be having the destination rules within the virtual service.
Create Destination Rules
Let me go ahead and create the destination rules. Let me go ahead and create the destination rules that is going to define within that specific service, what are all the subsets can be used.
root@cluster-node:~/istio-1.10.0# kubectl apply -f samples/bookinfo/networking/destination-rule-all.yaml
destinationrule.networking.istio.io/productpage created
destinationrule.networking.istio.io/reviews created
destinationrule.networking.istio.io/ratings created
destinationrule.networking.istio.io/details created
So the destination rules for the productpage, reviews, ratings and details will get created. Now I can go ahead and get what are all the destination rules that have been created using the command kubectl get destinationrules.
root@cluster-node:~/istio-1.10.0# kubectl get destinationrules
NAME HOST AGE
details details 106s
productpage productpage 106s
ratings ratings 106s
reviews reviews 106s
So these are the destination rules that have been created.
Create Gateway and Virtual Service
Now, I can go ahead and create the gateway and the virtual service. So I will create bookinfo-gateway with where I will allow all the traffic from all the host in the port 80. And I am going to create virtual service where it is going to route all the traffic coming from this specific uri into that specific host.
root@cluster-node:~/istio-1.10.0# kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml
gateway.networking.istio.io/bookinfo-gateway created
virtualservice.networking.istio.io/bookinfo created
Don’t get confused with the virtual service and the service running within the Kubernetes. I can go ahead and list what are all the virtual service that got created with the following command
root@cluster-node:~/istio-1.10.0# kubectl get virtualservices
NAME GATEWAYS HOSTS AGE
bookinfo ["bookinfo-gateway"] ["*"] 4m38s
So I do have the virtual services where I am going to allow from all the host. And I can list what are all the gateway that got created using the following command
root@cluster-node:~/istio-1.10.0# kubectl get gateway
NAME AGE
bookinfo-gateway 5m31s
So I do have the gateway as well.
Export Environment Variables
1. INGRESS_HOST
Since I am running within the same machine minikube, I can use the minikube IP address. I am going to assign the minikube IP address to a environmental variable INGRESS_HOST.
root@cluster-node:~# export INGRESS_HOST=$(minikube ip)
Within the machine I need to route all the traffic to a specific port and that particular port details will get routed to the port 80 of the ingress controller.
2. INGRESS_PORT
Now Let me go ahead and get that specific port i.e., the Ingress port using this specific command. So I can use the ingress gateway, get the json path and grep the port at which the http protocol is listening to. So I’m going to use the command kubectl within the namespace istio system.
root@cluster-node:~# export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
Here I’m going to get the service istio-ingressgateway and get the output as a json path. Within that I’m going to get the port and store it in the variable INGRESS_PORT.
Let me go ahead and echo this particular variable.
root@cluster-node:~# echo $INGRESS_HOST
192.168.1.50
So this is the IP address and it’s going to assign the internal IP address. In case if I am using curl I can use the internal IP address or otherwise I need to use the external IP address.
Let me go ahead and echo the port.
root@cluster-node:~# echo $INGRESS_PORT
31214
So it is responding in the port 31214.
SECURE_INGRESS_PORT
In case if I wanted to get the secure port, I can go ahead and export that in a specific variable by grepping the name as https and store it in this specific variable.
root@cluster-node:~# export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].nodePort}')
I can echo that as well, but I am not going to use in this particular demo.
root@cluster-node:~# echo $SECURE_INGRESS_PORT
32375
So It’s responding in the port 32375.
TCP_INGRESS_PORT
In case if I wanted the TCP I can go ahead and use the name as TCP. I will be getting the output and get stored within the variable TCP_INGRESS_PORT.
root@cluster-node:~# export TCP_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="tcp")].nodePort}')
Let me echo that as well.
root@cluster-node:~# echo $TCP_INGRESS_PORT
30845
And in the future use cases, I will be executing all this command in a single go. So that I will be getting the entire URL. Now what I can do, I can generate the URL using the INGRESS_HOST and the INGRESS_PORT and store it in the variable GATEWAY_URL.
root@cluster-node:~# export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT
So I’m going to use it with the curl command. So in case if I am using the curl command I should be getting the title. Let me go ahead and test it out quickly curl. And I’m going to access the GATEWAY_URL/product page. I will grep the title.
root@cluster-node:~# curl -s "http://${GATEWAY_URL}/productpage" | grep -o "<title>.*</title>"
Simple Bookstore App
So I do have the title that means the host, port and the URL is correct. As well as the application is also functioning properly. I’m going to use this specific application and do the demo of traffic shifting.
Summary
In a quick summary, we discussed about how to use the virtual services, destination rules and the gateway and how that’s getting created and what is the use of it within the Istio enabled cluster and how to generate the gateway url for our sample application.