mirror of https://github.com/istio/istio.io.git
commit
1509c0f52f
|
@ -1,4 +1,5 @@
|
|||
<ul class="doc-side-nav doc-side-nav-demos">
|
||||
{% assign current = page.url | downcase | split: '/' %}
|
||||
<li><h5 class="doc-side-nav-title">Demos</h5></li>
|
||||
<li class="doc-side-nav-list-item"><a href="{{ site.baseurl }}/docs/demos/bookinfo.html" {% if current[3] == 'bookinfo.html' %}class='current'{% endif %}>Bookinfo - A Polyglot Microservice App</a></li>
|
||||
</ul>
|
||||
|
|
|
@ -0,0 +1,402 @@
|
|||
---
|
||||
bodyclass: docs
|
||||
headline: 'Bookinfo - A Polyglot Microservice App'
|
||||
layout: docs
|
||||
title: Bookinfo - A Polyglot Microservice App
|
||||
type: markdown
|
||||
sidenav: doc-side-demos-nav.html
|
||||
---
|
||||
|
||||
In this demo, we will deploy a simple app that displays information about a
|
||||
book, similar to a single catalog entry of an online book store. Displayed
|
||||
on the page is a description of the book, book details (ISBN, number of
|
||||
pages, and so on), and a few book reviews.
|
||||
|
||||
The bookinfo application is broken into four separate microservices:
|
||||
|
||||
* *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.
|
||||
* *ratings*. The ratings microservice contains book ranking information that accompanies a book review.
|
||||
|
||||
There are 3 versions of the reviews microservice:
|
||||
|
||||
* Version v1 doesn't call the ratings service.
|
||||
* Version v2 calls the ratings service, and displays each rating as 1 to 5 black stars.
|
||||
* Version v3 calls the ratings service, and displays each rating as 1 to 5 red stars.
|
||||
|
||||
The end-to-end architecture of the application is shown below.
|
||||
|
||||

|
||||
|
||||
This application is polyglot, i.e., the microservices are written in different languages.
|
||||
|
||||
_Note: The following instructions assume that you have access to a kubernetes cluster. To install kubernetes locally, checkout [minikube](https://github.com/kubernetes/minikube)_
|
||||
|
||||
|
||||
## Setup Istio
|
||||
|
||||
1. Clone the istio Github repository and start the core Istio services (the istio-manager, the istio-mixer, and the istio ingress controller).
|
||||
|
||||
```bash
|
||||
git clone https://github.com/istio/istio
|
||||
cd istio
|
||||
kubectl apply -f ./kubernetes/istio-install
|
||||
```
|
||||
|
||||
_Note: the current version of the bookinfo application MUST use the `default` Kubernetes namespace._
|
||||
|
||||
2. If you would like to view the metrics collected by Istio proxies, you need to install the Prometheus addon and start a Grafana service as well.
|
||||
|
||||
```bash
|
||||
kubectl apply -f ./kubernetes/addons/
|
||||
```
|
||||
|
||||
The Grafana image provided as part of this demo contains a built-in Istio-dashboard that you can access from:
|
||||
|
||||
```
|
||||
http://<grafana-svc-external-IP>:3000/dashboard/db/istio-dashboard
|
||||
```
|
||||
|
||||
> The addons yaml files contain services configured as type LoadBalancer. If services are deployed with type NodePort,
|
||||
> start kubectl proxy, and edit Grafana's Istio-dashboard to use the proxy. Access Grafana via kubectl proxy:*
|
||||
|
||||
```
|
||||
http://127.0.0.1:8001/api/v1/proxy/namespaces/<ns>/services/grafana:3000/dashboard/db/istio-dashboard
|
||||
```
|
||||
|
||||
2. Install the [istioctl](../reference/istioctl.md) CLI, which provides a
|
||||
convenient way to apply routing rules and policies for upstreams. The
|
||||
`demos/` directory has three binaries: `istioctl-osx`, `istioctl-win.exe`,
|
||||
`istioctl-linux` targeted at Mac, Windows and Linux users
|
||||
respectively. Download the tool appropriate to your platform and
|
||||
rename the tool to `istioctl`. For example:
|
||||
|
||||
```bash
|
||||
$ cp demos/istioctl-osx /usr/local/bin/istioctl
|
||||
```
|
||||
|
||||
> Note: If you already have a previously installed version of `istioctl`, make sure that
|
||||
> it is compatible with the manager image used in `demos/kubernetes/istio-manager.yaml`.
|
||||
> If in doubt, download again or add the `--tag` option when running `istioctl kube-inject`.
|
||||
> Invoke `istioctl kube-inject --help` for more details.
|
||||
|
||||
|
||||
## Start the Application
|
||||
|
||||
1. Change your current working directory to the bookinfo application directory:
|
||||
|
||||
```bash
|
||||
cd demos/apps/bookinfo
|
||||
```
|
||||
|
||||
1. Bring up the application containers:
|
||||
|
||||
```bash
|
||||
$ kubectl create -f <(istioctl kube-inject -f bookinfo.yaml)
|
||||
```
|
||||
|
||||
The above command creates the gateway ingress resource and launches
|
||||
the 4 microservices as described in the diagram above. The reviews
|
||||
microservice has 3 versions: v1, v2, and v3. Note that in a
|
||||
realistic deployment, new versions of a microservice are deployed
|
||||
over time instead of deploying all versions
|
||||
simultaneously.
|
||||
|
||||
Notice that the `istioctl kube-inject` command is used to modify the `bookinfo.yaml`
|
||||
file before creating the deployments. This injects the istio runtime proxy
|
||||
into kubernetes resources as documented [here](../reference/istioctl.md#kube-inject).
|
||||
Consequently, all of the microservices are now packaged with an Istio sidecar
|
||||
that manages incoming and outgoing calls for the service. The updated diagram looks
|
||||
like this:
|
||||
|
||||

|
||||
|
||||
|
||||
1. Confirm that all services and pods are correctly defined and running:
|
||||
|
||||
```bash
|
||||
$ kubectl get services
|
||||
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
details 10.0.0.31 <none> 9080/TCP 6m
|
||||
istio-ingress-controller 10.0.0.122 <pending> 80:32000/TCP 8m
|
||||
istio-manager 10.0.0.189 <none> 8080/TCP 8m
|
||||
istio-mixer 10.0.0.132 <none> 9091/TCP,42422/TCP 8m
|
||||
kubernetes 10.0.0.1 <none> 443/TCP 14d
|
||||
productpage 10.0.0.120 <none> 9080/TCP 6m
|
||||
ratings 10.0.0.15 <none> 9080/TCP 6m
|
||||
reviews 10.0.0.170 <none> 9080/TCP 6m
|
||||
```
|
||||
|
||||
and
|
||||
|
||||
```bash
|
||||
$ kubectl get pods
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
details-v1-1520924117-48z17 2/2 Running 0 6m
|
||||
istio-ingress-controller-3181829929-xrrk5 1/1 Running 0 8m
|
||||
istio-manager-175173354-d6jm7 2/2 Running 0 8m
|
||||
istio-mixer-3883863574-jt09j 2/2 Running 0 8m
|
||||
productpage-v1-560495357-jk1lz 2/2 Running 0 6m
|
||||
ratings-v1-734492171-rnr5l 2/2 Running 0 6m
|
||||
reviews-v1-874083890-f0qf0 2/2 Running 0 6m
|
||||
reviews-v2-1343845940-b34q5 2/2 Running 0 6m
|
||||
reviews-v3-1813607990-8ch52 2/2 Running 0 6m
|
||||
```
|
||||
|
||||
1. Determine the Gateway ingress URL
|
||||
|
||||
```bash
|
||||
$ export GATEWAY_URL=$(kubectl get po -l infra=istio-ingress-controller -o jsonpath={.items[0].status.hostIP}):$(kubectl get svc istio-ingress-controller -o jsonpath={.spec.ports[0].nodePort})
|
||||
$ echo $GATEWAY_URL
|
||||
192.168.99.100:32567
|
||||
```
|
||||
1. If you open the Bookinfo URL (http://$GATEWAY_URL/productpage) in your browser, you should see the bookinfo application productpage displayed.
|
||||
|
||||
## Traffic Management
|
||||
|
||||
### Content Based Routing
|
||||
|
||||
Since we have 3 versions of the reviews microservice running, we need to set the default route.
|
||||
Otherwise if you access the application several times, you would notice that sometimes the output contains
|
||||
star ratings. This is because without an explicit default version set, Istio will
|
||||
route requests to all available versions of a service in a random fashion.
|
||||
|
||||
1. Set the default version for all microservices to v1.
|
||||
|
||||
```bash
|
||||
$ istioctl create -f route-rule-all-v1.yaml
|
||||
```
|
||||
|
||||
You can display the routes that are defined with the following command:
|
||||
|
||||
```bash
|
||||
$ istioctl list route-rule
|
||||
kind: route-rule
|
||||
name: ratings-default
|
||||
namespace: default
|
||||
spec:
|
||||
destination: ratings.default.svc.cluster.local
|
||||
precedence: 1
|
||||
route:
|
||||
- tags:
|
||||
version: v1
|
||||
weight: 100
|
||||
---
|
||||
kind: route-rule
|
||||
name: reviews-default
|
||||
namespace: default
|
||||
spec:
|
||||
destination: reviews.default.svc.cluster.local
|
||||
precedence: 1
|
||||
route:
|
||||
- tags:
|
||||
version: v1
|
||||
weight: 100
|
||||
---
|
||||
kind: route-rule
|
||||
name: details-default
|
||||
namespace: default
|
||||
spec:
|
||||
destination: details.default.svc.cluster.local
|
||||
precedence: 1
|
||||
route:
|
||||
- tags:
|
||||
version: v1
|
||||
weight: 100
|
||||
---
|
||||
kind: route-rule
|
||||
name: productpage-default
|
||||
namespace: default
|
||||
spec:
|
||||
destination: productpage.default.svc.cluster.local
|
||||
precedence: 1
|
||||
route:
|
||||
- tags:
|
||||
version: v1
|
||||
weight: 100
|
||||
---
|
||||
```
|
||||
|
||||
> Note: In the current Kubernetes implemention of Istio, the rules are stored in ThirdPartyResources.
|
||||
> You can look directly at the stored rules in Kubernetes using the `kubectl` command. For example,
|
||||
> the following command will display all defined rules:
|
||||
> ```bash
|
||||
> $ kubectl get istioconfig -o yaml
|
||||
> ```
|
||||
|
||||
Since rule propagation to the proxies is asynchronous, you should wait a few seconds for the rules
|
||||
to propagate to all pods before attempting to access the application.
|
||||
|
||||
If you open the Bookinfo URL (`http://$GATEWAY_URL/productpage`) in your browser,
|
||||
you should see the bookinfo application `productpage` displayed. Notice that the `productpage`
|
||||
is displayed with no rating stars since `reviews:v1` does not access the ratings service.
|
||||
|
||||
1. Route a specific user to `reviews:v2`
|
||||
|
||||
Lets enable the ratings service for test user "jason" by routing productpage traffic to
|
||||
`reviews:v2` instances.
|
||||
|
||||
```bash
|
||||
$ istioctl create -f route-rule-reviews-test-v2.yaml
|
||||
```
|
||||
|
||||
Confirm the rule is created:
|
||||
|
||||
```bash
|
||||
$ istioctl get route-rule reviews-test-v2
|
||||
destination: reviews.default.svc.cluster.local
|
||||
match:
|
||||
httpHeaders:
|
||||
Cookie:
|
||||
regex: ^(.*?;)?(user=jason)(;.*)?$
|
||||
precedence: 2
|
||||
route:
|
||||
- tags:
|
||||
version: v2
|
||||
```
|
||||
|
||||
Log in as user "jason" at the `productpage` web page. You should now see ratings (1-5 stars) next
|
||||
to each review.
|
||||
|
||||
### Fault Injection
|
||||
|
||||
To test our bookinfo application microservices for resiliency, we will _inject a 7s delay_
|
||||
between the reviews:v2 and ratings microservices. Since the _reviews:v2_ service has a
|
||||
10s timeout for its calls to the ratings service, we expect the end-to-end flow to
|
||||
continue without any errors.
|
||||
|
||||
1. Inject the delay
|
||||
|
||||
Create a fault injection rule, to delay traffic coming from user "jason" (our test user).
|
||||
|
||||
```bash
|
||||
$ istioctl create -f destination-ratings-test-delay.yaml
|
||||
```
|
||||
|
||||
Confirm the rule is created:
|
||||
|
||||
```bash
|
||||
$ istioctl get route-rule ratings-test-delay
|
||||
destination: ratings.default.svc.cluster.local
|
||||
httpFault:
|
||||
delay:
|
||||
fixedDelaySeconds: 7
|
||||
percent: 100
|
||||
match:
|
||||
httpHeaders:
|
||||
Cookie:
|
||||
regex: "^(.*?;)?(user=jason)(;.*)?$"
|
||||
precedence: 2
|
||||
route:
|
||||
- tags:
|
||||
version: v1
|
||||
```
|
||||
|
||||
Allow several seconds to account for rule propagation delay to all pods.
|
||||
|
||||
1. Observe application behavior
|
||||
|
||||
If the application's front page was set to correctly handle delays, we expect it
|
||||
to load within approximately 7 seconds. To see the web page response times, open the
|
||||
*Developer Tools* menu in IE, Chrome or Firefox (typically, key combination _Ctrl+Shift+I_
|
||||
or _Alt+Cmd+I_) and reload the `productpage` web page.
|
||||
|
||||
You will see that the webpage loads in about 6 seconds. The reviews section will show
|
||||
*Sorry, product reviews are currently unavailable for this book*.
|
||||
|
||||
The reason that the entire reviews service has failed is because our bookinfo application
|
||||
has a bug. The timeout between the productpage and reviews service is less (3s + 1 retry = 6s total)
|
||||
than the timeout between the reviews and ratings service (10s). These kinds of bugs can occur in
|
||||
typical enterprise applications where different teams develop different microservices
|
||||
independently. Istio's fault injection rules help you identify such anomalies without
|
||||
impacting end users.
|
||||
|
||||
> Notice that we are restricting the failure impact to user "jason" only. If you login
|
||||
> as any other user, you would not experience any delays.
|
||||
|
||||
**Fixing the bug:** At this point we would normally fix the problem by either increasing the
|
||||
productpage timeout or decreasing the reviews to ratings service timeout,
|
||||
terminate and restart the fixed microservice, and then confirm that the `productpage`
|
||||
returns its response without any errors.
|
||||
(Left as an exercise for the reader - change the delay rule to
|
||||
use a 2.8 second delay and then run it against the v3 version of reviews.)
|
||||
|
||||
However, we already have this fix running in v3 of the reviews service, so
|
||||
we can next demonstrate deployment of a new version.
|
||||
|
||||
### Percentage-based Traffic Split
|
||||
|
||||
Now that we have tested the reviews service, fixed the bug and deployed a
|
||||
new version (`reviews:v3`), lets route all user traffic from `reviews:v1`
|
||||
to `reviews:v3` in two steps.
|
||||
|
||||
First, transfer 50% of traffic from `reviews:v1` to `reviews:v3` with the following command:
|
||||
|
||||
```bash
|
||||
$ istioctl replace -f route-rule-reviews-50-v3.yaml
|
||||
```
|
||||
|
||||
> Notice that we are using `istioctl replace` instead of `create`.
|
||||
|
||||
To see the new version you need to either Log out as test user "jason" or delete the test rules
|
||||
that we created exclusively for him:
|
||||
|
||||
```bash
|
||||
$ istioctl delete route-rule reviews-test-v2
|
||||
$ istioctl delete route-rule ratings-test-delay
|
||||
```
|
||||
|
||||
You should now see *red* colored star ratings approximately 50% of the time when you refresh
|
||||
the `productpage`.
|
||||
|
||||
> Note: With the Envoy sidecar implementation, you may need to refresh the `productpage` 100 times
|
||||
> to see the proper distribution.
|
||||
|
||||
When we are confident that our Bookinfo app is stable, we route 100% of the traffic to `reviews:v3`:
|
||||
|
||||
```bash
|
||||
$ istioctl replace -f route-rule-reviews-v3.yaml
|
||||
```
|
||||
|
||||
You can now log in to the `productpage` as any user and you should always see book reviews
|
||||
with *red* colored star ratings for each review.
|
||||
|
||||
## Policy Enforcement
|
||||
|
||||
### Rate Limiting [WIP]
|
||||
|
||||
Now we'll pretend that `ratings` is an external service for which we are paying (like going to rotten tomatoes),
|
||||
so we will set a rate limit on the service such that the load remains under the Free quota (5q/s):
|
||||
|
||||
```bash
|
||||
$ # (TODO) istioctl create -f mixer-rule-ratings-ratelimit.yaml
|
||||
$ kubectl apply -f ../../mixer-config-quota-bookinfo.yaml
|
||||
```
|
||||
|
||||
We now generate load on the `productpage` with the following command:
|
||||
|
||||
```bash
|
||||
$ while true; do curl -s -o /dev/null http://$GATEWAY_URL/productpage; done
|
||||
```
|
||||
|
||||
If you now refresh the `productpage` you'll see that while the load generator is running
|
||||
(i.e., generating more than 5 req/s), we stop seeing stars.
|
||||
|
||||
## Cleanup
|
||||
|
||||
1. Delete the routing rules and terminate the application and control plane pods
|
||||
|
||||
```bash
|
||||
$ ./cleanup.sh
|
||||
```
|
||||
|
||||
1. Optionally shut down the control plane services using the uninstall instructions [here](../../../kubernetes/README.md).
|
||||
|
||||
1. Confirm shutdown
|
||||
|
||||
```bash
|
||||
$ istioctl list route-rule #-- there should be no more routing rules
|
||||
$ kubectl get pods #-- the bookinfo, and (optionally) control plane services, should be deleted
|
||||
No resources found.
|
||||
```
|
|
@ -6,3 +6,5 @@ title: Demos
|
|||
type: markdown
|
||||
sidenav: doc-side-demos-nav.html
|
||||
---
|
||||
|
||||
Take the demo walkthroughs in this section to get a high-level idea of Istio's features. The demos are targeted towards Kubernetes users. We are working on adding support for other platforms.
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 45 KiB |
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 83 KiB |
Binary file not shown.
After Width: | Height: | Size: 53 KiB |
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 96 KiB |
Loading…
Reference in New Issue