# `Istio` Example: `Bookinfo` Application Installation
###### tags: `ITRI`, `istio`, `example`
***
## Reference
- Official Website: ISTIO/DOCS/EXAMPLES/BOOKINFO APPLICATION: [Bookinfo Application](https://istio.io/docs/examples/bookinfo/)
- Chinese Version: [Bookinfo 应用](https://istio.io/zh/docs/examples/bookinfo/)
- Blog of 青蛙小白: [Istio 1.0学习笔记(二):部署官方示例Bookinfo](https://blog.frognew.com/2018/08/learning-istio-1.0-2.html)
***
## *Bookinfo* Architecture

Four separate microservices in `Bookinfo`:
- `productpage` The `productpage` microservice calls the `details` and `reviews` microservices to populate the page. (用來生成頁面)
- `details` The `details` microservice contains book information. (包含圖書的資訊)
- `reviews` The `reviews` microservice contains book reviews. It also calls the `ratings` microservice. (提供圖書評論功能,可以調用 `rating` 給圖書星星)
- After following the steps below, 我們可以看到:
```bash
# kubectl get pod -l app=reviews -n istio-example
NAME READY STATUS RESTARTS AGE
reviews-v1-5787f7b87-5g6k4 2/2 Running 0 5h9m
reviews-v2-6d8b975647-t9t2m 2/2 Running 0 5h9m
reviews-v3-7d5549f9-sphc8 2/2 Running 0 5h9m
```
- `ratings` The `ratings` microservice contains book ranking information that accompanies a book review. (提供圖書給星星功能)
- There are 3 versions of the reviews microservice:
|Version|GUI|
|-|-|
|v1|<li>Version v1 doesn’t call the `ratings` service.</li> |
|v2|<li>Version v2 calls the `ratings` service, and displays each rating as 1 to 5 ++black++ stars.</li> |
|v3|<li>Version v3 calls the `ratings` service, and displays each rating as 1 to 5 ++red++ stars.</li> |
Notice that:
- this application is polyglot (多語言的)
- these services have no dependencies on *Istio*
仍不失它是一個有趣的 service mesh 示例。
***
## Deploying the application
官方的 example 並不需要我們再去修改 application。 We only simply need to configure and run the services in an *Istio-enabled* environment, with *Envoy sidecars* injected along side each service.

所有的微服务之间的调用都是通过 Envoy sidecar,即图中小黑色长方形,微服务的 sidecar 组成了服务网格 Service Mesh。
### Running on Kubernetes
#### Create namespace `istio-example` for *Bookinfo*
Check if `istio-sidecar-injector` is running.
```bash
# kubectl get pod -n istio-system | grep injector
istio-sidecar-injector-fc58d99f-vck25 1/1 Running 0 4h7m
```
- `istio-sidecar-injector` 可以自动将 *Envoy* 容器作为 sidecar 注入到我们的业务应用 Pod 中,只要业务应用 Pod 所在的 namespace 包含 `istio-injection=enabled` 的 Label。
In this note, we create a namespace `istio-example` for *Bookinfo* application.
```bash
# kubectl create namespace istio-example
```
Default *Istio* installation uses automatic sidecar injection. Label the namespace:
```bash
# kubectl label namespace istio-example istio-injection=enabled
```
#### Run the *Bookinfo* application
*Bookinfo* application was defined in `samples/bookinfo/platform/kube/bookinfo.yaml`.
```yaml=
# Copyright 2017 Istio Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
##################################################################################################
# Details service
##################################################################################################
apiVersion: v1
kind: Service
metadata:
name: details
labels:
app: details
service: details
spec:
ports:
- port: 9080
name: http
selector:
app: details
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: bookinfo-details
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: details-v1
labels:
app: details
version: v1
spec:
replicas: 1
selector:
matchLabels:
app: details
version: v1
template:
metadata:
labels:
app: details
version: v1
spec:
serviceAccountName: bookinfo-details
containers:
- name: details
image: docker.io/istio/examples-bookinfo-details-v1:1.15.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 9080
---
##################################################################################################
# Ratings service
##################################################################################################
apiVersion: v1
kind: Service
metadata:
name: ratings
labels:
app: ratings
service: ratings
spec:
ports:
- port: 9080
name: http
selector:
app: ratings
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: bookinfo-ratings
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: ratings-v1
labels:
app: ratings
version: v1
spec:
replicas: 1
selector:
matchLabels:
app: ratings
version: v1
template:
metadata:
labels:
app: ratings
version: v1
spec:
serviceAccountName: bookinfo-ratings
containers:
- name: ratings
image: docker.io/istio/examples-bookinfo-ratings-v1:1.15.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 9080
---
##################################################################################################
# Reviews service
##################################################################################################
apiVersion: v1
kind: Service
metadata:
name: reviews
labels:
app: reviews
service: reviews
spec:
ports:
- port: 9080
name: http
selector:
app: reviews
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: bookinfo-reviews
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: reviews-v1
labels:
app: reviews
version: v1
spec:
replicas: 1
selector:
matchLabels:
app: reviews
version: v1
template:
metadata:
labels:
app: reviews
version: v1
spec:
serviceAccountName: bookinfo-reviews
containers:
- name: reviews
image: docker.io/istio/examples-bookinfo-reviews-v1:1.15.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 9080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: reviews-v2
labels:
app: reviews
version: v2
spec:
replicas: 1
selector:
matchLabels:
app: reviews
version: v2
template:
metadata:
labels:
app: reviews
version: v2
spec:
serviceAccountName: bookinfo-reviews
containers:
- name: reviews
image: docker.io/istio/examples-bookinfo-reviews-v2:1.15.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 9080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: reviews-v3
labels:
app: reviews
version: v3
spec:
replicas: 1
selector:
matchLabels:
app: reviews
version: v3
template:
metadata:
labels:
app: reviews
version: v3
spec:
serviceAccountName: bookinfo-reviews
containers:
- name: reviews
image: docker.io/istio/examples-bookinfo-reviews-v3:1.15.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 9080
---
##################################################################################################
# Productpage services
##################################################################################################
apiVersion: v1
kind: Service
metadata:
name: productpage
labels:
app: productpage
service: productpage
spec:
ports:
- port: 9080
name: http
selector:
app: productpage
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: bookinfo-productpage
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: productpage-v1
labels:
app: productpage
version: v1
spec:
replicas: 1
selector:
matchLabels:
app: productpage
version: v1
template:
metadata:
labels:
app: productpage
version: v1
spec:
serviceAccountName: bookinfo-productpage
containers:
- name: productpage
image: docker.io/istio/examples-bookinfo-productpage-v1:1.15.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 9080
---
```
Deploy the application:
```bash
# cd istio-<version>
# kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml -n istio-example
```
### Confirm all services, pods & application
If thay are correctly defined and running:
```bash
# kubectl get services -n istio-example
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
details ClusterIP 10.233.55.254 <none> 9080/TCP 4h8m
productpage ClusterIP 10.233.17.112 <none> 9080/TCP 4h8m
ratings ClusterIP 10.233.28.165 <none> 9080/TCP 4h8m
reviews ClusterIP 10.233.12.187 <none> 9080/TCP 4h8m
# kubectl get pods -n istio-example
NAME READY STATUS RESTARTS AGE
details-v1-6978996b-blfrn 2/2 Running 0 4h9m
productpage-v1-7658b8dcc6-9bbc5 2/2 Running 0 4h9m
ratings-v1-84975bc778-zspbs 2/2 Running 0 4h9m
reviews-v1-5787f7b87-5g6k4 2/2 Running 0 4h9m
reviews-v2-6d8b975647-t9t2m 2/2 Running 0 4h9m
reviews-v3-7d5549f9-sphc8 2/2 Running 0 4h9m
```
Send a request to it by a `curl` command from `ratings` for checking *BookInfo* is running:
```bash
# kubectl exec -it -n istio-example $(kubectl get pod -n istio-example -l app=ratings -o jsonpath='{.items[0].metadata.name}') -c ratings -- curl productpage:9080/productpage | grep -o "<title>.*</title>"
<title>Simple Bookstore App</title>
```
## Istio Gateway: Determining the ingress IP and port
Now that the `Bookinfo` services are up and running, you need to make the application accessible from outside of your Kubernetes cluster, e.g., from a browser.
An ==Istio Gateway== is used for this purpose.
1. Define the ingress gateway for the application:
```bash
# kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml -n istio-example
```
2. Confirm the gateway has been created:
```bash
# kubectl get gateway -n istio-example
NAME AGE
bookinfo-gateway 4h
```
3. Set the `INGRESS_HOST` and `INGRESS_PORT` variables for accessing the gateway.
Check if our Kubernetes cluster is running in an environment that supports external load balancers:
```bash
# kubectl get svc istio-ingressgateway -n istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-ingressgateway LoadBalancer 10.233.12.169 <pending> 15020:32165/TCP,80:31380/TCP,443:31390/TCP,31400:31400/TCP,15029:31238/TCP,15030:31865/TCP,15031:30552/TCP,15032:31756/TCP,15443:30065/TCP 4h38m
```
- If the `EXTERNAL-IP` value is set, our environment has an external load balancer that you can use for the ingress gateway.
- If the `EXTERNAL-IP` value is `<none>` (or perpetually `<pending>`), our environment does not provide an external load balancer for the ingress gateway.
- In this case, you can access the gateway using the service’s node port.
Set the ingress ports:
```bash
export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].nodePort}')
```
Setting the ingress IP depends on the cluster provider:
```bash
export INGRESS_HOST=$(kubectl get po -l istio=ingressgateway -n istio-system -o jsonpath='{.items[0].status.hostIP}')
```
4. Set `GATEWAY_URL`:
```bash
# export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT
```
### Confirm the app is accessible from outside the cluster
Check from the CLI.
```bash
# curl -s http://${GATEWAY_URL}/productpage | grep -o "<title>.*</title>"
<title>Simple Bookstore App</title>
```
Open browser to `http://$GATEWAY_URL/productpage` to view the Bookinfo web page.

If you refresh the page several times (重新整理頁面多次時), you should see different versions of reviews shown in productpage, presented in a *round robin* style (red stars, black stars, no stars), since we haven’t yet used *Istio* to ++control the version routing++.
***
## Apply default destination rules
Before using *Istio* to ++control the Bookinfo version routing++, we need to define the available versions, called *subsets*, in destination rules.
Create default destination rules for the *Bookinfo* services.
Since we did not enable mutual TLS, apply `samples/bookinfo/networking/destination-rule-all.yaml`.
```bash
# kubectl apply -f samples/bookinfo/networking/destination-rule-all.yaml -n istio-example
```
Display the destination rules.
```bash
# kubectl get destinationrules -n istio-example
NAME HOST AGE
details details 1d
productpage productpage 1d
ratings ratings 1d
reviews reviews 1d
```
***
## Clean Up Appication
Remove the application virtual services.
```bash
# kubectl delete -f samples/bookinfo/networking/virtual-service-all-v1.yaml -n istio-example
```
## Uninstall from Kubernetes environment
If we want to clear all the `Bookinfo` example, use the script.
```bash
# samples/bookinfo/platform/kube/cleanup.sh
```
Confirm shutdown.
```bash
# kubectl get virtualservices -n istio-example #-- there should be no virtual services
# kubectl get destinationrules -n istio-example #-- there should be no destination rules
# kubectl get gateway -n istio-example #-- there should be no gateway
# kubectl get pods -n istio-example #-- the Bookinfo pods should be deleted
```
***
<center>** End **</center>
***
***