Istio the Hard Way Round 2
Istio the hard way round 2 - working with Istio Routes/VirtualServices -- ROUGH DRAFT V1
Using the route demo
Starting from where we left off in the install guide aka Istio the Hard way. You may recall that we installed the sample Istio bookinfo application which consists of several microservices.
Let's walk through the route demo.
Let's review and make sure we are ready for part 2.
Recall we installed the sample Istio BookInfo application.
Installed sample Istio application
kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
The BookInfo Istio Demo application has the following microservices:
- Productpage Microservice
- Details Microservice
- Reviews Microservice
- Ratings Microservice
BookInfo Services
As you can see the Istio Bookinfo sample is made of the Productpage, Details, Reviews and Ratings microservices.
If you followed along with the first guide then you will have three versions of the Ratingsmicroservice.
To illustrate the problem this causes, access the Bookinfo app’s /productpage in a browser and refresh several times. You’ll notice that sometimes the book review output contains star ratings and other times it does not. This is because without an explicit default service version to route to, Istio routes requests to all available versions in a round robin fashion. --route demo
First, let's route all of the traffic to just v1 of the reviews microservices. But before we do that. Let's peek around a bit, and make sure all is well.
Make sure Minikube is running, we are in the right context and the right namespace
## Is minikube running? $ minikube status host: Running kubelet: Running apiserver: Running kubeconfig: Configured ## Are we in the right namespace $ kubectx minikube Switched to context "minikube". ## Are we using the right namespace $ kubens bookinfo Context "minikube" modified. Active namespace is "bookinfo".
Make sure our services are running
$ kubectl get pod NAME READY STATUS RESTARTS AGE details-v1-74f858558f-z72cw 2/2 Running 0 3d20h hello-world-c7598fbb5-2v4l2 2/2 Running 0 42h productpage-v1-8554d58bff-p8cwp 2/2 Running 0 3d20h ratings-v1-7855f5bcb9-m2rxl 2/2 Running 0 3d20h reviews-v1-59fd8b965b-d6xml 2/2 Running 0 3d20h reviews-v2-d6cfdb7d6-m58mw 2/2 Running 0 3d20h reviews-v3-75699b5cfb-kt4hs 2/2 Running 0 3d20h
You may have to restart Minikube and/or change the context to minikube. Refer to the first guide to see how to do this and the guides it points to regarding kubectl and minikube install and usage.
Recall that we ran minikube tunnel to connect to the microservices through the istio gateway in the first guide. Let's see if we cleaned up.
See if minikube tunnel is running
ps -e | grep minikube | grep tunnel | awk '{print $1}'
If the minikube tunnel is not running, start it.
Start the minikube tunnel cleanly
## Clean up any old minikube tunnel config $ minikube tunnel -c ### Output E0308 17:16:35.346896 71396 tunnel.go:51] error cleaning up: conflicting rule in routing table: 10.96/12 192.168.64.18 UGSc bridge1 ## Start up a new minikube tunnel in its own terminal $ minikube tunnel Status: machine: minikube pid: 71405 route: 10.96.0.0/12 -> 192.168.64.18 minikube: Running services: [istio-ingressgateway] errors: minikube: no errors router: no errors loadbalancer emulator: no errors
Notice that we run the minikube tunnel cleanup command to clean up any residual config from our last run.
Next recall that we need to set up the istio gateway environment variables using util/set_up_gateway.sh from the first guide, shown below.
util/set_up_gateway.sh
#!/bin/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}') export INGRESS_HOST=$(minikube ip) env | grep INGRESS export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT echo "GATEWAY is $GATEWAY_URL" echo "https://$GATEWAY_URL/productpage"
Thus we want to source this script to get the GATEWAY_URL environment variable.
Source set_up_gateway.sh
$ pwd /Users/richardhightower/istio/istio-1.4.5 $ source util/set_up_gateway.sh INGRESS_PORT=30851 SECURE_INGRESS_PORT=31073 INGRESS_HOST=192.168.64.18 GATEWAY is 192.168.64.18:30851 https://192.168.64.18:30851/productpage
Now reload https://$GATEWAY_URL/productpage until you see three versions of reviews, one with black stars, one with red stars and one with no stars.
Black stars reviews
Red Stars reviews
No Star reviews
Route all traffic to v1
Recall the goal of the initial step of the route demo.
To route to one version only, you apply virtual services that set the default version for the microservices. In this case, the virtual services will route all traffic to v1 of each microservice. --route demo
samples/bookinfo/networking/virtual-service-all-v1.yaml routes all traffic to v1 of each microservice
kubectl apply -f samples/bookinfo/networking/virtual-service-all-v1.yaml ### Output virtualservice.networking.istio.io/productpage created virtualservice.networking.istio.io/reviews created virtualservice.networking.istio.io/ratings created virtualservice.networking.istio.io/details created
samples/bookinfo/networking/virtual-service-all-v1.yaml
apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: productpage spec: hosts: - productpage http: - route: - destination: host: productpage subset: v1 --- apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: reviews spec: hosts: - reviews http: - route: - destination: host: reviews subset: v1 --- apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: ratings spec: hosts: - ratings http: - route: - destination: host: ratings subset: v1 --- apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: details spec: hosts: - details http: - route: - destination: host: details subset: v1 ---
Notice that virtual-service-all-v1.yaml changes the spec->http->route->destination->->subset to v1 for each microservice.
To see that this is working go to https://192.168.64.18:30851/productpage (your URL will vary https://$GATEWAY_URL/productpage).
Let's look at this new deployment config with kiali. Before we do that, let's run some more traffic through this config.
Open up a new terminal and do the following:
Run some traffic through the new set up
## Load gateway config env vars $ source util/set_up_gateway.sh ### Output INGRESS_PORT=30851 SECURE_INGRESS_PORT=31073 INGRESS_HOST=192.168.64.18 GATEWAY is 192.168.64.18:30851 https://192.168.64.18:30851/productpage ## Curl the page and see that it is working as expected $ curl -s https://$GATEWAY_URL/productpage | grep "<title>" ### Output <title>Simple Bookstore App</title> ## Run some load through the set up. $ for i in `seq 1 10000`; do curl -s -o /dev/null https://$GATEWAY_URL/productpage; done
In a new terminal use istioctl dashboard kiali to launch kiali.
use istioctl dashboard kiali to launch kiali dashboard
$ istioctl dashboard kiali ### Output https://localhost:64338/kiali
In the Kiali web UI do the following:
- Click on Graph Navigation on the left side bar.
- Select the bookinfo namespace from the namespace dropdown on the top left side of the main window
Kiali view of routing to only version 1
You may wonder why ratings v1 and reviews v2, and v3 are still visible and yet no lines are drawn to them. It is because they are still deployed. There just is no routes that are routing traffic to them defined. If there was traffic, then you would see lines drawn to those versions of services.
BookInfo Kubernetes Deployments in istio bookinfo demo
BookInfo Services defined in istio bookinfo demo
Route based on user identity
Next, let's change the route manifest files to route traffic based on a user named Jason. The Jason user gets routed to the service reviews v2.
Note that Istio doesn’t have any special, built-in understanding of user identity. This example is enabled by the fact that the productpage service adds a custom end-user header to all outbound HTTP requests to the reviews service. --Route based on user identity
Run the following command to enable user-based routing:
samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml - apply user Jason routing
$ kubectl apply -f samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml ### Output virtualservice.networking.istio.io/reviews configured
samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml
apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: reviews spec: hosts: - reviews http: - match: - headers: end-user: exact: jason route: - destination: host: reviews subset: v2 - route: - destination: host: reviews subset: v1
See the config spec->http->match->headers->end-user->exact:jason.
Now, go to https://$GATEWAY_URL/productpage in your browser, and log in as user jason.
Logout or Log in as another user (e.g., Rick, Sue, etc.). The traffic is routed to reviews v1 for all users except Jason. Note the differences in logging in as any user or a user named Jason.
Istio Route logging in as Joe instead of Jason
Istio Route logging in as Jason
Log into as Jason and refresh the page a few times. Now load up the services graph in Kiali again. Notice that the Jason route use reviews v2 microservice and the reviews v microservice uses the ratings v1 service.
Jason Route uses reviews v2 which uses ratings v1
See VirtualService route rules because you can match URI, headers, request params, cookies, ports, gateway origins and a lot more than just headers.
The match values can be matched in several modes not just exact.
- exact: value for exact match
- prefix: prefix match
- regex: regex-based match (e.g., non empty string ^(?!\s*$).+)
Checking to see if a user is logged in
Let's cement that last concept and augment the last example a bit. Let's create a route that if a user is logged in at all routes reviews v3. If they are a gold user, their user name is prefixed with gold_ they get routed to reviews v2. Then if they are not logged in at all they get routed to reviews v1.
- Logged in go to reviews v3
- Logged in as gold user to reviews v2
- Not logged in go to reviews v1.
Create a new route manifest file called route_loggedin.yaml.
Create a new route manifest file called route_loggedin.yaml
$ touch route_loggedin.yaml $ atom route_loggedin.yaml
The route_loggedin.yaml will contain a prefix match and a regex match for header end-user as follows.
route_loggedin.yaml
apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: reviews-logged-in spec: hosts: - reviews http: - match: - headers: end-user: regex: ^(?!\s*$).+ route: - destination: host: reviews subset: v3 - match: - headers: end-user: prefix: gold_ route: - destination: host: reviews subset: v2 - route: - destination: host: reviews subset: v1
Recall last time we used only an exact match. Now let's apply our new route manifest.
apply our new Istio VirtualService route manifest
## Delete the old rule so we don't have conflicts. $ kubectl delete -f samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml ### Output virtualservice.networking.istio.io "reviews" deleted ## Apply the new rules. $ kubectl apply -f route_loggedin.yaml ### Output virtualservice.networking.istio.io/reviews-logged-in created ## Now let's see it. $ kubectl get virtualservice reviews-logged-in -o yaml ### Output apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: | {"apiVersion":"networking.istio.io/v1alpha3","kind":"VirtualService","metadata":{"annotations":{},"name":"reviews-logged-in","namespace":"bookinfo"},"spec":{"hosts":["reviews"],"http":[{"match":[{"headers":{"end-user":{"regex":"^(?!\\s*$).+"}}}],"route":[{"destination":{"host":"reviews","subset":"v3"}}]},{"match":[{"headers":{"end-user":{"prefix":"gold_"}}}],"route":[{"destination":{"host":"reviews","subset":"v2"}}]},{"route":[{"destination":{"host":"reviews","subset":"v1"}}]}]}} creationTimestamp: "2020-03-09T01:58:39Z" generation: 1 name: reviews-logged-in namespace: bookinfo resourceVersion: "97713" selfLink: /apis/networking.istio.io/v1alpha3/namespaces/bookinfo/virtualservices/reviews-logged-in uid: c8194fc6-520d-47eb-be9b-1ce0681d45e7 spec: hosts: - reviews http: - match: - headers: end-user: regex: ^(?!\s*$).+ route: - destination: host: reviews subset: v3 - match: - headers: end-user: prefix: gold_ route: - destination: host: reviews subset: v2 - route: - destination: host: reviews subset: v1
Now try logging in as a gold user, a logged in user and then try not logging in.
Istio route rules: Not logged in
Istio route rules: Logged in as a gold user
Istio route rules: Any logged-in user
Try using the productpage web app with all three different ways then load up the Kiali Dashboard, and look at the services graph. Turn on request percentages (2nd row of dropdowns and the 2nd column).
Istio route rules shown in Kiali with request percentages
Conclusion
In this task, we used Istio to send all traffic to the v1 versions of each microservice in the Istio BookInfo sample. Then you routed traffic differently if the user was logged in as Jason using an exact match. Then we just did a rift and wrote some route rules that matched if a user was logged, if they were not logged in and if they were a gold user using prefix, and regex matches.
Resources
- Istio the hard way, part 1
- Istio the hard way, part 2, working with routes
- VirtualService route rules
- Set up Minikube on a Mac
- Kubectl cheatsheet
- Get started with Istio
- Set up Istio command line
- Set up Istio on minikube
- Install sample app
- Overview of tracing
- Set up Jaeger
- Master metrics set up
- Use Grafana
- Set up Kiali
- View example in Kiali
- Stuff you might want to demo in Kiali
- Set up Logging
- Set up FluentD and EFK
- Description of different istio profiles
- Kubernetes CNI driver for Istio if you can't use init containers and side cars
- Using istioctl kube-inject instead of auto injection
- Traffic Management
Engineering Consultant focused on AI
4 年The latest version is here https://github.com/cloudurable/istio-the-hardway/blob/master/route.md