By Ohad Ben Nun
Motivation
Istio offers a great array of tools for viewing, monitoring & controlling our internal & external K8S traffic, but deploying & managing Istio can sometimes be a bit of a hassle.
Luckily, GKE now provides an option to deploy Istio in one step!
Deploying Istio on your K8S cluster will:
- Encrypt services traffic (mTLS)
- Provide monitoring tools (Prometheus & Grafana)
- Allow to control ingress/egress/internal cluster traffic
Before we begin
GKE Istio addon is currently available in Google Cloud as a beta.
This article assumes:
- You have already setup a GCP account with the required billing information & permissions to execute the commands shown here (see Istio GKE overview)
- You are familiar with Kubernetes, Google Cloud & have the required binaries (kubectl & gcloud cli)
- You have SSL certificates (both public & private keys) to use Istio’s mTLS features
Deploying Istio
Deploying Istio can be done in several ways:
- Using a Helm Chart
- Using GCP CLI (full installation guide)
I also heard that the Istio team is also developing a Kubernetes Operator…
Set gcloud context
Run the following:
gcloud config set project [project-id]
gcloud config set compute/zone [zone]
Note: you can get all available zones with:
gcloud compute zones list
Creating a cluster with Istio on GKE
Run the following (should take a couple of minutes):
gcloud beta container clusters create [cluster-name] \
--addons=Istio --istio-config=auth=MTLS_PERMISSIVE \
--machine-type=n1-standard-2 \
--num-nodes=3
After the operation is completed, you’ll have:
- A GKE cluster with 3 nodes
- A TCP Load Balancer for ingress traffic
Set ‘kubectl context’ to the new cluster:
gcloud container clusters get-credentials [cluster-name] --project=[project-id]
Validating Istio Deployment
Run the following:
kubectl get pods -n istio-system
You should get an output with all the running pods under the namespace ‘istio-system’, for example:
istio-citadel-776fb85794-dm7ws 1/1 Running 0 4h
istio-cleanup-secrets-vlr5g 0/1 Completed 0 4h
istio-egressgateway-7f778c7fcf-kqsvf 1/1 Running 0 4h
istio-galley-794f98cf5f-gdjbr 1/1 Running 0 4h
istio-ingressgateway-56b648f9fb-w8v8g 1/1 Running 0 4h
istio-pilot-d87948784–7z222 2/2 Running 0 4h
istio-policy-5757c77d8f-p7clp 2/2 Running 0 4h
istio-security-post-install-2bblz 0/1 Completed 0 4h
istio-sidecar-injector-f555db659-hmf45 1/1 Running 0 4h
istio-telemetry-85c84d85c6-sgh4q 2/2 Running 0 4h
prometheus-7c589d4989-xrp6n 2/2 Running 1 4h
Enabling Istio’s sidecar injection
To let Istio actually manage your services, each service in your application needs to have an Envoy sidecar proxy running in its pod to proxy network traffic between itself and other services.
Istio provides “Automatic sidecar injection” for namespaces with the label ‘istio-injection=true’.
Let’s enable the sidecar injection for our desired namespace by running the following:
kubectl label namespace [desired-namespace] istio-injection=enabled
Now, Istio will auto-inject the sidecar to each new pod in the namespace!
If there are some pods already running before enabling the ‘sidecar-injection’ mechanism, the pods should be deleted to allow Istio to inject the sidecar to the pods.
If you add subsequent namespaces, remember to enable Istio!
Allowing ingress traffic from GCP Load Balancer
To allow traffic from the load-balancer to the cluster, you can follow the steps described here.
For GKE clusters, you can follow these steps:
First, let’s find the ingress ports (HTTP & HTTPS) we should allow with firewall rules:
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}')
Now, let’s create the firewall rules to allow the incoming traffic:
gcloud compute firewall-rules create allow-gateway-http --allow tcp:$INGRESS_PORTgcloud compute firewall-rules create allow-gateway-https --allow tcp:$SECURE_INGRESS_PORT
Deploying an app in our cluster
We can now deploy your application or continue with a demo application for K8S like this one:
git clone https://github.com/Tufin/generic-bank
cd generic-bank
./deploy <timezonedb-token>
To get the timezonedb token, go to https://timezonedb.com/register. But for now you can just deploy with a random string since this will be blocked by Istio anyway.
Routing Ingress Traffic to the App
Adding a Gateway
At this point we have a load-balancer which is implemented by the Istio ingress controller (using the Envoy proxy).
Now we add an Istio Gateway which describes the allowed hosts, ports, protocols for the controller.
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: gateway
spec:
selector:
istio: ingressgateway # use istio default controller
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
Note: the example above uses http. If you want to implement https you will need to add certificates, as follows:
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: gateway
spec:
selector:
istio: ingressgateway # use istio default controller
servers:
- port:
number: 443
name: https
protocol: HTTPS
hosts:
- example.com
tls:
mode: SIMPLE #enables HTTPS on this port
serverCertificate: /etc/istio/ingressgateway-certs/tls.crt
privateKey: /etc/istio/ingressgateway-certs/tls.key
Virtual Service
Now we need to route URI to services:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: admin
spec:
hosts:
- "*"
gateways:
- gateway
http:
- match:
- uri:
prefix: /admin
- uri:
prefix: /boa
- uri:
prefix: /time
route:
- destination:
host: admin
port:
number: 80
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: customer
spec:
hosts:
- "*"
gateways:
- gateway
http:
- match:
- uri:
prefix: /customer
- uri:
prefix: /accounts
- uri:
prefix: /balance
route:
- destination:
host: customer
port:
number: 80
Testing Ingress Connectivity
Find the ingress IP:
export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
Get the customer URL:echo http://$INGRESS_HOST:$INGRESS_PORT/customer/
And open the URL in your browser. You should see something like this:
Now open the admin URL:echo http://$INGRESS_HOST:$INGRESS_PORT/admin/
The times are invalid because Istio 1.0.x blocks all outbound access by default. Istio 1.1 will change this to allow all egress traffic by default.
Summary
- We created a K8S cluster with Istio installed as an add-on.
Google created a load-balancer for us as part of the cluster creation.
Istio is configured in Permissive mode which means that services will accept both mTLS and clear http (we will show you how to improve this in a subsequent post). - We created a Gateway which receives all ingress traffic (Layers 4/5)
- We’ve created two Virtual Services that route the traffic from the gateway to a specific service according to URI path (Layers 7)
- We deployed an application into the cluster
Congrats! We’ve deployed our first Istio enabled K8S app!