Warning
This content has been generated by machine translation. The translations are automated and have not undergone human review or validation.
4.4.2 Applying Service Mesh - Istio to microservices apps
Installation is possible with istioctl, Helm, or manual. Here, we will install the istioctl standard described as an example in the OKE document and check that it is applied to the service according to the Istio document.
- Official documentation
Install Istio
Connect to Cloud Shell or work environment.
Download Istio
curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.12.1 TARGET_ARCH=x86_64 sh -
Go to the Istio route
cd istio-1.12.1
Add to PATH environment variable
export PATH=$PWD/bin:$PATH
Run pre-verification
istioctl x precheck
Installation
istioctl install --set profile=demo
Scale
Scale beyond 2 to account for upgrades that are set to pod’s disruption budget default of 1.
kubectl scale --replicas=2 deployment -n istio-system istio-egressgateway kubectl scale --replicas=2 deployment -n istio-system istio-ingressgateway kubectl scale --replicas=2 deployment -n istio-system istiod
Istio Enable
productpage service Istio Enable
Redistributing by adding Istio sidecar
Add sidecar to productpage app only with istioctl kube-inject command.
curl -s https://raw.githubusercontent.com/istio/istio/release-1.12/samples/bookinfo/platform/kube/bookinfo.yaml | istioctl kube-inject -f - | sed 's/replicas: 1/replicas: 3/g' | kubectl apply -l app=productpage,version=v1 -f -
Check the results
You can see that the istio-proxy container has been added in the product Pod.
oke_admin@cloudshell:~ (ap-seoul-1)$ kubectl get pod NAME READY STATUS RESTARTS AGE details-v1-79f774bdb9-29z48 1/1 Running 0 89m details-v1-79f774bdb9-d5lfq 1/1 Running 0 89m details-v1-79f774bdb9-sqp9p 1/1 Running 0 89m productpage-v1-c6885474-6g754 2/2 Running 0 16s productpage-v1-c6885474-r9l8l 2/2 Running 0 19s productpage-v1-c6885474-sz9mf 2/2 Running 0 14s ratings-v1-b6994bb9-6xlq7 1/1 Running 0 89m ratings-v1-b6994bb9-j2l78 1/1 Running 0 89m ratings-v1-b6994bb9-w748t 1/1 Running 0 89m reviews-v2-7bf8c9648f-4rh4z 1/1 Running 0 7m16s reviews-v2-7bf8c9648f-6vhlq 1/1 Running 0 7m18s reviews-v2-7bf8c9648f-8zjcw 1/1 Running 0 7m16s sleep-557747455f-jxk5z 1/1 Running 0 12m oke_admin@cloudshell:~ (ap-seoul-1)$ kubectl describe pod productpage-v1-c6885474-6g75 Name: productpage-v1-c6885474-6g754 Namespace: default ... Containers: productpage: Container ID: cri-o://95f68b2fcb5e8168879e1a5703bf520a94729664cc410edbe0d3255113344149 Image: docker.io/istio/examples-bookinfo-productpage-v1:1.16.2 ... istio-proxy: Container ID: cri-o://74f2707caa99b8b12b3e293a129f74234c5ac1ab36729f70045de640eeb2b4b4 Image: docker.io/istio/proxyv2:1.12.1 ...
Access the productpage page as before.
- http://{productpage external ip}:9080/productpage
Check the istio-proxy log
You can see that the web page is accessed as before and additionally goes through istio-proxy.
oke_admin@cloudshell:~ (ap-seoul-1)$ kubectl logs -l app=productpage -c istio-proxy -f ... [2021-12-20T09:16:54.826Z] "GET /details/0 HTTP/1.1" 200 - via_upstream - "-" 0 178 2 2 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36" "adeb5dbb-261c-9982-9d66-523cc3890e2b" "details:9080" "10.244.2.43:9080" outbound|9080||details.default.svc.cluster.local 10.244.2.149:41122 10.96.175.211:9080 10.244.2.149:55324 - default [2021-12-20T09:16:54.842Z] "GET /reviews/0 HTTP/1.1" 200 - via_upstream - "-" 0 379 591 591 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36" "adeb5dbb-261c-9982-9d66-523cc3890e2b" "reviews:9080" "10.244.2.51:9080" outbound|9080||reviews.default.svc.cluster.local 10.244.2.149:45512 10.96.197.86:9080 10.244.2.149:35752 - default [2021-12-20T09:16:54.820Z] "GET /productpage HTTP/1.1" 200 - via_upstream - "-" 0 5183 616 615 "10.179.87.76" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36" "adeb5dbb-261c-9982-9d66-523cc3890e2b" "146.56.142.95:9080" "10.244.2.149:9080" inbound|9080|| 127.0.0.6:41867 10.244.2.149:9080 10.179.87.76:0 - default
Full Service Istio Enable
Enable Istio for Review v2 and other services with the following command.
curl -s https://raw.githubusercontent.com/istio/istio/release-1.12/samples/bookinfo/platform/kube/bookinfo.yaml | istioctl kube-inject -f - | kubectl apply -l app!=reviews -f - curl -s https://raw.githubusercontent.com/istio/istio/release-1.12/samples/bookinfo/platform/kube/bookinfo.yaml | istioctl kube-inject -f - | kubectl apply -l app=reviews,version=v2 -f -
Execution result
If Istio-proxy is added and you see 2 containers per Pod, bookinfo.yaml is reapplied to note that replica=1.
oke_admin@cloudshell:~ (ap-seoul-1)$ kubectl get pod NAME READY STATUS RESTARTS AGE details-v1-5c6d488c49-ltw8r 2/2 Running 0 69s productpage-v1-c6885474-6g754 2/2 Running 0 15h ratings-v1-7dfc8d4bbf-p8n2f 2/2 Running 0 68s reviews-v2-5ff75858c7-zhn57 2/2 Running 0 64s sleep-557747455f-jxk5z 1/1 Running 0 16h
Note
If you label istio-injection as shown below, pods deployed in that namespace will automatically have istio sidecar added.
kubectl label namespace <NAMESPACE_NAME> istio-injection=enabled
Set up Istio Ingress Gateway
Earlier in another chapter, we used the nginx ingress controller as the Ingress Controller. To control microservices, configure Istio’s Ingress Gateway for services.
References
Gateway: Describes the load balancer information for incoming and outgoing traffic to and from the service mesh.
VirtualService: Specifies routing rules for traffic.
Create an Istio Ingress Gateway for the example book-info with the contents below.
kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: bookinfo-gateway spec: selector: istio: ingressgateway # use Istio default gateway implementation servers: - port: number: 80 name: http protocol: HTTP hosts: - "*" --- apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: bookinfo spec: hosts: - "*" gateways: - bookinfo-gateway http: - match: - uri: exact: /productpage - uri: exact: /login - uri: exact: /logout - uri: prefix: /static route: - destination: host: productpage port: number: 9080 EOF
Check the IP for access through the Istio Ingress Gateway.
oke_admin@cloudshell:~ (ap-seoul-1)$ kubectl get svc -n istio-system NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE istio-egressgateway ClusterIP 10.96.59.144 <none> 80/TCP,443/TCP 66m istio-ingressgateway LoadBalancer 10.96.150.51 146.56.186.52 15021:32250/TCP,80:32707/TCP,443:32572/TCP,31400:32532/TCP,15443:31522/TCP 66m istiod ClusterIP 10.96.188.42 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP 66m
Check the connection
- Example, http://146.56.186.52:80/productpage
Metric monitoring
Install Prometheus & Grafana
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.12/samples/addons/prometheus.yaml kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.12/samples/addons/grafana.yaml
External access to the installed Grafana dashboard
- Option #1:
- You can connect through a local proxy with the istioctl dashboard grafana command. Cloud Shell does not allow public IP and external access, so if external access is required, relevant settings are required.
- Option #2:
- You can set up external access through the Istio Ingress Gateway.
- Set up external access through settings - https://istio.io/latest/docs/tasks/observability/gateways/
- Option #1:
Set up external access by referring to the official documentation.
Example of external connection setting
Domain settings for settings
Check the Istio Ingress Gateway’s External IP and set it in the DNS server or in the client’s /etc/hosts file. Enter the domain address you want to use.
export INGRESS_DOMAIN="istio.thekoguryo.ml"
Open external connection
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: grafana-gateway namespace: istio-system spec: selector: istio: ingressgateway servers: - port: number: 80 name: http-grafana protocol: HTTP hosts: - "grafana.${INGRESS_DOMAIN}" --- apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: grafana-vs namespace: istio-system spec: hosts: - "grafana.${INGRESS_DOMAIN}" gateways: - grafana-gateway http: - route: - destination: host: grafana port: number: 3000 --- apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: grafana namespace: istio-system spec: host: grafana trafficPolicy: tls: mode: DISABLE --- EOF
Test data generation
- Generate test data by connecting through Istio Ingress Gateway of productpage.
- Example test app page, http://146.56.186.52:80/productpage
- Generate test data by connecting through Istio Ingress Gateway of productpage.
Access Grafana
If you connect to the set address, you can check the basic dashboard provided by Istio.
- You can check the processing information of each service by looking at the Grafana dashboard.
Distributed Tracing
A microservice processes a client’s request through a decentralized service and then responds to the client. The Bookinfo app used as an example also provides the client with information collected by the productpage service from the backend service. In such a distributed environment, there are various tools for tracing call information between services for a client’s request. Istio leverages Envoy’s distributed tracing capabilities to leverage tools such as Jaeger, Zipkin, and LightStep. Here we will see how to do it via Zipkin. For other tools, please refer to the related page.
Zipkin
Install Zipkin
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.12/samples/addons/extras/zipkin.yaml
Access the installed Zipkin page from outside
- Same as Grafana Option #2: Use external access.
- Set up external access by referring to the official documentation.
Example of external connection setting
Domain settings for settings
export INGRESS_DOMAIN="istio.thekoguryo.ml"
Open external connection
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: tracing-gateway namespace: istio-system spec: selector: istio: ingressgateway servers: - port: number: 80 name: http-tracing protocol: HTTP hosts: - "tracing.${INGRESS_DOMAIN}" --- apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: tracing-vs namespace: istio-system spec: hosts: - "tracing.${INGRESS_DOMAIN}" gateways: - tracing-gateway http: - route: - destination: host: tracing port: number: 80 --- apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: tracing namespace: istio-system spec: host: tracing trafficPolicy: tls: mode: DISABLE --- EOF
Test data generation
- Generate test data by connecting through Istio Ingress Gateway of productpage.
- Example test app page, http://146.56.186.52:80/productpage
- Generate test data by connecting through Istio Ingress Gateway of productpage.
Access the Zipkin page.
Service trace test
- On the Find a trace screen, click the red plus sign to set the service to search and run the query.
Check the search results and click SHOW on the right for the item you want to track.
You can see the call relationship between services for the request, the time, and tag information for each service.
Trace by Trace ID
For each request, it can be traced through Span ID (Trace ID). You can check it in the log.
If you search directly through the Trace ID search box at the top right of the screen, you can check the request immediately.
service mesh visualization
A microservice processes a client’s request through a decentralized service and then responds to the client. The Bookinfo app used as an example also provides the client with information collected by the productpage service from the backend service. In such a distributed environment, Kiali provides visualization of call information between services for client requests.
Install Kiali
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.12/samples/addons/kiali.yaml
External access to installed Kiali page
- Same as Grafana Option #2: Use external access.
- Set up external access by referring to the official documentation.
Example of external connection setting
Domain settings for settings
export INGRESS_DOMAIN="istio.thekoguryo.ml"
Open external connection
cat <<EOF | kubectl apply -f - apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: kiali-gateway namespace: istio-system spec: selector: istio: ingressgateway servers: - port: number: 80 name: http-kiali protocol: HTTP hosts: - "kiali.${INGRESS_DOMAIN}" --- apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: kiali-vs namespace: istio-system spec: hosts: - "kiali.${INGRESS_DOMAIN}" gateways: - kiali-gateway http: - route: - destination: host: kiali port: number: 20001 --- apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: kiali namespace: istio-system spec: host: kiali trafficPolicy: tls: mode: DISABLE --- EOF
Test data generation
- Generate test data by connecting through Istio Ingress Gateway of productpage.
- Example test app page, http://146.56.186.52:80/productpage
- Generate test data by connecting through Istio Ingress Gateway of productpage.
Access Kiali Dashboard.
If you click Graph in the navigation menu, you can visualize the call information between services.
Reviews New version release
Reviews v3 distribution
Deploy the Reviews v3 version.
Deploy v3 assuming version update with Istio enabled.
curl -s https://raw.githubusercontent.com/istio/istio/release-1.12/samples/bookinfo/platform/kube/bookinfo.yaml | istioctl kube-inject -f - | kubectl apply -l app=reviews,version=v3 -f -
Check the deployment result
oke_admin@cloudshell:~ (ap-seoul-1)$ kubectl get pod NAME READY STATUS RESTARTS AGE ... reviews-v2-5ff75858c7-hwrgv 2/2 Running 0 5h15m reviews-v3-5484f6cbd6-685b6 2/2 Running 0 3m8s ...
Test by connecting through Istio Ingress Gateway in productpage.
- Example test app page, http://146.56.186.52:80/productpage
- Reviews v2 and Reviews v3 are routed once, as each Pod is not set according to the distribution rule. You can see that Reviews v2 (black star) and Reviews v3 (red star) are displayed at once.
Weighted Routing
Let’s look at a scenario where only some requests based on weight are routed for validation before the new version is fully serviced.
Check the version label of the deployed Reviews Pod. Version=v2 and version=v2 are assigned respectively.
oke_admin@cloudshell:~ (ap-seoul-1)$ kubectl get pod -L version NAME READY STATUS RESTARTS AGE VERSION details-v1-5c6d488c49-m5t7j 2/2 Running 0 5h28m v1 productpage-v1-c6885474-qkpx9 2/2 Running 0 5h28m v1 ratings-v1-7dfc8d4bbf-97p6z 2/2 Running 0 5h28m v1 reviews-v2-5ff75858c7-hwrgv 2/2 Running 0 5h28m v2 reviews-v3-5484f6cbd6-685b6 2/2 Running 0 15m v3 sleep-557747455f-jxk5z 1/1 Running 0 22h
Deploy the below settings required by Istio for routing by label.
- DestinationRule: Filter by labels for service endpoints. In the test example, only the Pod, not the Service Type, has a version label. It seems to be the label of the pod
- VirtualService: Distributed based on weight for the defined destination. The sum of the weights should be 100. 90 times out of 100 times, 10 times, it is guessed by probability, not by exact distribution.
kubectl apply -f - <<EOF apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: reviews spec: hosts: - reviews http: - route: - destination: host: reviews subset: v2 weight: 90 - destination: host: reviews subset: v3 weight: 10 --- 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 EOF
Repeat the test as shown below.
counter=1; \ while [ $counter -lt 20 ]; \ do curl -s http://146.56.186.52/productpage | grep color | head -1; counter=$(( $counter + 1 )); \ done
Test results
You can see that 18 out of 20 are black asterisks and 2 red asterisks. Chances are it won’t be accurate.
oke_admin@cloudshell:~ (ap-seoul-1)$ counter=1; \ > while [ $counter -lt 20 ]; \ > do > curl -s http://146.56.186.52/productpage | grep color | head -1; > counter=$(( $counter + 1 )); \ > done <font color="black"> <font color="black"> <font color="black"> <font color="red"> <font color="black"> <font color="black"> <font color="black"> <font color="black"> <font color="black"> <font color="black"> <font color="black"> <font color="black"> <font color="black"> <font color="black"> <font color="black"> <font color="black"> <font color="red"> <font color="black"> <font color="black">
Check the call flow to Kiali
As you can see in the picture below, you can see that it is distributed according to the weights set in Reviews v2 and v3.
As an individual, this article was written with my personal time. There may be errors in the content of the article, and the opinions in the article are personal opinions.