Platform Setup

Minikube

1
$ sudo pacman -S minikube libvirt qemu-desktop dnsmasq iptables-nft
1
2
3
4
$ sudo usermod -aG libvirt $(whoami)
$ sudo systemctl start libvirtd.service
$ sudo systemctl enable libvirtd.service
$ sudo systemctl status libvirtd.service
1
$ virt-host-validate

set the kvm2 provider in minikube:

1
$ minikube config set driver kvm2

With minikube you can quickly create a local Kubernetes cluster. To get started, use the following flags:

  • --profile sets the cluster name to default.
  • --memory sets the cluster to use 16GB of memory.
  • --kubernetes-version specifies the cluster kubernetes version to v1.26.1.
1
$ minikube start --memory=16384 --cpus=4 --kubernetes-version=v1.26.1

Create a route to services deployed with type LoadBalancer and sets their Ingress to their ClusterIP.. Run this command in a different terminal

1
$ minikube tunnel

Install Istio with Helm

Install and configure Istio in a Kubernetes cluster using Helm.

1
$ pacman -S helm
1
2
$ proxychains helm repo add istio https://istio-release.storage.googleapis.com/charts
$ proxychains helm repo update

The general syntax for helm installation is:

1
$ helm install <release> <chart> --namespace <namespace> --create-namespace [--set <other_parameters>]
  • <chart> A path to a packaged chart, a path to an unpacked chart directory or a URL.
  • <release> A name to identify and manage the Helm chart once installed.
  • <namespace> The namespace in which the chart is to be installed.

Create the namespace, istio-system, for the Istio components:

1
$ kubectl create namespace istio-system

Install the Istio base chart which contains cluster-wide Custom Resource Definitions (CRDs) which must be installed prior to the deployment of the Istio control plane:

1
$ helm install istio-base istio/base -n istio-system --set defaultRevision=default

Validate the CRD installation with the helm ls command:

1
2
3
$ helm ls -n istio-system
NAME       NAMESPACE    REVISION UPDATED         STATUS   CHART        APP VERSION
istio-base istio-system 1        ... ... ... ... deployed base-1.16.1  1.16.1

In the output locate the entry for istio-base and make sure the status is set to deployed.

Install the Istio discovery chart which deploys the istiod service:

1
$ helm install istiod istio/istiod -n istio-system --wait

Verify the Istio discovery chart installation:

1
2
3
4
$ helm ls -n istio-system
NAME       NAMESPACE    REVISION UPDATED         STATUS   CHART         APP VERSION
istio-base istio-system 1        ... ... ... ... deployed base-1.16.1   1.16.1
istiod     istio-system 1        ... ... ... ... deployed istiod-1.16.1 1.16.1

Get the status of the installed helm chart to ensure it is deployed:

1
$ helm status istiod -n istio-system

Check istiod service is successfully installed and its pods are running:

1
2
3
$ kubectl get deployments -n istio-system --output wide
NAME     READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS   IMAGES                         SELECTOR
istiod   1/1     1            1           10m   discovery    docker.io/istio/pilot:1.16.1   istio=pilot

(Optional) Install an ingress gateway:

1
2
$ git clone git@github.com:istio/istio.git
$ cd istio
1
2
3
$ kubectl create namespace istio-ingress
# $ helm install istio-ingress manifests/charts/gateways/istio-ingress/ -n istio-ingress
$ helm install istio-ingress istio/gateway -n istio-ingress --wait

The namespace the gateway is deployed in must not have a istio-injection=disabled label.

1
$ kubectl label namespace default istio-injection=enabled

Examples: Bookinfo Application

Deploy the sample application

1
$ kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml

As each pod becomes ready, the Istio sidecar will be deployed along with it.

1
$ kubectl get services
1
$ kubectl get pods

Verify everything is working correctly up to this point.

1
$ kubectl exec "$(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}')" -c ratings -- curl -sS productpage:9080/productpage | grep -o "<title>.*</title>"

Open the application to outside traffic

The Gateway configuration resources allow external traffic to enter the Istio service mesh and make the traffic management and policy features of Istio available for edge services.

Configuring ingress using a gateway

The application is deployed but not accessible from the outside. To make it accessible, you need to create an Istio Ingress Gateway, which maps a path to a route at the edge of your mesh.

1
$ vim samples/bookinfo/networking/bookinfo-gateway.yaml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: bookinfo-gateway
spec:
  # The selector matches the ingress gateway pod labels.
  # If you installed Istio using Helm following the standard documentation, this would be "istio=ingress"
  selector:
    istio: ingressgateway # use istio default controller
  servers:
  - port:
      number: 8080
      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:
        prefix: /static
    - uri:
        exact: /login
    - uri:
        exact: /logout
    - uri:
        prefix: /api/v1/products
    route:
    - destination:
        host: productpage
        port:
          number: 9080

The gateways list specifies that only requests through your frontend-gateway are allowed. All other external requests will be rejected with a 404 response.

1
$ kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml

Determining the ingress IP and ports

Every Gateway is backed by a service of type LoadBalancer. The external load balancer IP and ports for this service are used to access the gateway. Kubernetes services of type LoadBalancer are supported by default in clusters running on most cloud platforms but in some environments (e.g., test) you may need to do the following:

  • minikube - start an external load balancer by running the following command in a different terminal:

    1
    
    $ minikube tunnel
    
  • kind - follow the guide for setting up MetalLB to get LoadBalancer type services to work.

  • other platforms - you may be able to use MetalLB to get an EXTERNAL-IP for LoadBalancer services.

Set the following environment variables to the name and namespace where the Istio ingress gateway is located in your cluster:

1
2
$ export INGRESS_NAME=istio-ingressgateway
$ export INGRESS_NS=istio-system

If you installed Istio using Helm, the ingress gateway name and namespace are both istio-ingress:

1
2
$ export INGRESS_NAME=istio-ingress
$ export INGRESS_NS=istio-ingress

Run the following command to determine if your Kubernetes cluster is in an environment that supports external load balancers:

1
2
3
$ kubectl get svc "$INGRESS_NAME" -n "$INGRESS_NS"
NAME                   TYPE           CLUSTER-IP       EXTERNAL-IP      PORT(S)   AGE
istio-ingressgateway   LoadBalancer   172.21.109.129   130.211.10.121   ...       17h

If the EXTERNAL-IP value is set, your environment has an external load balancer that you can use for the ingress gateway. If the EXTERNAL-IP value is <none> (or perpetually <pending>), your environment does not provide an external load balancer for the ingress gateway.

If your environment does not support external load balancers, you can try accessing the ingress gateway using node ports. Otherwise, set the ingress IP and ports using the following commands:

1
2
3
4
5
$ export INGRESS_HOST=$(kubectl -n "$INGRESS_NS" get service "$INGRESS_NAME" -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
$ export INGRESS_PORT=$(kubectl -n "$INGRESS_NS" get service "$INGRESS_NAME" -o jsonpath='{.spec.ports[?(@.name=="http2")].port}')
$ export SECURE_INGRESS_PORT=$(kubectl -n "$INGRESS_NS" get service "$INGRESS_NAME" -o jsonpath='{.spec.ports[?(@.name=="https")].port}')
$ export TCP_export INGRESS_PORT=$(kubectl -n "$INGRESS_NS" get service "$INGRESS_NAME" -o jsonpath='{.spec.ports[?(@.name=="http2")].port}')INGRESS_PORT=$(kubectl -n "$INGRESS_NS" get service "$INGRESS_NAME" -o jsonpath='{.spec.ports[?(@.name=="tcp")].port}')
$ export GATEWAY_URL=$INGRESS_HOST:$INGRESS_PORT

In certain environments, the load balancer may be exposed using a host name, instead of an IP address. In this case, the ingress gateway’s EXTERNAL-IP value will not be an IP address, but rather a host name, and the above command will have failed to set the INGRESS_HOST environment variable. Use the following command to correct the INGRESS_HOST value:

1
$ export INGRESS_HOST=$(kubectl -n "$INGRESS_NS" get service "$INGRESS_NAME" -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')

Accessing ingress services

1
2
3
$ curl -s -I "http://$INGRESS_HOST:$INGRESS_PORT/status/200"
HTTP/1.1 200 OK
server: istio-envoy

Access any other URL that has not been explicitly exposed. You should see an HTTP 404 error.

Use a wildcard * value for the host in the Gateway and VirtualService configurations. You can then use $INGRESS_HOST:$INGRESS_PORT in the browser URL.

Run the following command to retrieve the external address of the Bookinfo application.

1
$ echo "http://$GATEWAY_URL/productpage"

Paste the output from the previous command into your web browser and confirm that the Bookinfo product page is displayed.

View the dashboard

Deploy the Kiali dashboard, along with Prometheus, Grafana, and Jaeger.

1
2
$ kubectl apply -f samples/addons
$ kubectl rollout status deployment/kiali -n istio-system

Access the Kiali dashboard.

1
$ istioctl dashboard kiali

To see trace data, you must send requests to your service. The number of requests depends on Istio’s sampling rate and can be configured using the Telemetry API. With the default sampling rate of 1%, you need to send at least 100 requests before the first trace is visible. To send a 100 requests to the productpage service, use the following command:

1
$ for i in $(seq 1 100); do curl -s -o /dev/null "http://$GATEWAY_URL/productpage"; done

Traffic Management

Ingress

Request Timeouts

Circuit Breaking

Request Routing

Security

Authentication

JWT

Observability

Metrics

Visualizing Metrics with Grafana

Querying Metrics from Prometheus

Logs

Send access logs with OpenTelemetry collector

Distributed Tracing

OpenCensus Agent

Cleanup

Uninstall

1
$ helm ls -n istio-system
1
2
$ helm delete istio-ingress -n istio-ingress
$ kubectl delete namespace istio-ingress
1
$ helm delete istiod -n istio-system
1
$ helm delete istio-base -n istio-system
1
$ kubectl delete namespace istio-system
1
2
3
$ kubectl delete gateway frontend-gateway
$ kubectl delete virtualservice frontend-ingress
$ kubectl delete --ignore-not-found=true -f samples/httpbin/httpbin.yaml

Cleanup Istio ingress gateway

1
2
$ helm uninstall istio-ingress -n istio-ingress
$ kubectl delete ns istio-ingress

Remove Kiali

1
$ kubectl delete -f https://raw.githubusercontent.com/istio/istio/release-1.20/samples/addons/kiali.yaml

Reference

Istio Getting Started

Istio Ingress Gateway

Ingress

Request Timeouts

Circuit Breaking

Request Routing

JWT claim based routing

OpenCensus Agent

Visualizing Metrics with Grafana

Querying Metrics from Prometheus

Send access logs with OpenTelemetry collector