flagger/docs/gitbook/install/install-istio.md

11 KiB
Raw Blame History

Install Istio

This guide walks you through setting up Istio with Jaeger, Prometheus, Grafana and Lets Encrypt TLS for ingress gateway on Google Kubernetes Engine.

Istio GKE diagram

Prerequisites

You will be creating a cluster on Googles Kubernetes Engine GKE, if you dont have an account you can sign up here for free credits.

Login into GCP, create a project and enable billing for it.

Install the gcloud command line utility and configure your project with gcloud init.

Set the default project replace `PROJECT_ID` with your own project:

gcloud config set project PROJECT_ID

Set the default compute region and zone:

gcloud config set compute/region europe-west3
gcloud config set compute/zone europe-west3-a

Enable the Kubernetes and Cloud DNS services for your project:

gcloud services enable container.googleapis.com
gcloud services enable dns.googleapis.com

Install the kubectl command-line tool:

gcloud components install kubectl

Install the helm command-line tool:

brew install kubernetes-helm

GKE cluster setup

Create a cluster with three nodes using the latest Kubernetes version:

k8s_version=$(gcloud container get-server-config --format=json \
| jq -r '.validNodeVersions[0]')

gcloud container clusters create istio \
--cluster-version=${k8s_version} \
--zone=europe-west3-a \
--num-nodes=3 \
--machine-type=n1-highcpu-4 \
--preemptible \
--no-enable-cloud-logging \
--disk-size=30 \
--enable-autorepair \
--scopes=gke-default,compute-rw,storage-rw

The above command will create a default node pool consisting of n1-highcpu-4 vCPU: 4, RAM 3.60GB, DISK: 30GB preemptible VMs. Preemptible VMs are up to 80% cheaper than regular instances and are terminated and replaced after a maximum of 24 hours.

Set up credentials for kubectl:

gcloud container clusters get-credentials istio -z=europe-west3-a

Create a cluster admin role binding:

kubectl create clusterrolebinding "cluster-admin-$(whoami)" \
--clusterrole=cluster-admin \
--user="$(gcloud config get-value core/account)"

Validate your setup with:

kubectl get nodes -o wide

Cloud DNS setup

You will need an internet domain and access to the registrar to change the name servers to Google Cloud DNS.

Create a managed zone named istio in Cloud DNS replace `example.com` with your domain:

gcloud dns managed-zones create \
--dns-name="example.com." \
--description="Istio zone" "istio"

Look up your zone's name servers:

gcloud dns managed-zones describe istio

Update your registrar's name server records with the records returned by the above command.

Wait for the name servers to change replace `example.com` with your domain:

watch dig +short NS example.com

Create a static IP address named istio-gateway-ip in the same region as your GKE cluster:

gcloud compute addresses create istio-gateway-ip --region europe-west3

Find the static IP address:

gcloud compute addresses describe istio-gateway-ip --region europe-west3

Create the following DNS records replace `example.com` with your domain and set your Istio Gateway IP:

DOMAIN="example.com"
GATEWAYIP="35.198.98.90"

gcloud dns record-sets transaction start --zone=istio

gcloud dns record-sets transaction add --zone=istio \
--name="${DOMAIN}" --ttl=300 --type=A ${GATEWAYIP}

gcloud dns record-sets transaction add --zone=istio \
--name="www.${DOMAIN}" --ttl=300 --type=A ${GATEWAYIP}

gcloud dns record-sets transaction add --zone=istio \
--name="*.${DOMAIN}" --ttl=300 --type=A ${GATEWAYIP}

gcloud dns record-sets transaction execute --zone istio

Verify that the wildcard DNS is working replace `example.com` with your domain:

watch host test.example.com

Install Istio with Helm

Download the latest Istio release:

curl -L https://git.io/getLatestIstio | sh -

Navigate to istio-x.x.x dir and copy the Istio CLI in your bin:

cd istio-x.x.x/
sudo cp ./bin/istioctl /usr/local/bin/istioctl

Apply the Istio CRDs:

kubectl apply -f ./install/kubernetes/helm/istio/templates/crds.yaml

Create a service account and a cluster role binding for Tiller:

kubectl apply -f ./install/kubernetes/helm/helm-service-account.yaml

Deploy Tiller in the kube-system namespace:

helm init --service-account tiller

Find the GKE IP ranges:

gcloud container clusters describe istio --zone=europe-west3-a \
| grep -e clusterIpv4Cidr -e servicesIpv4Cidr

You'll be using the IP ranges to allow unrestricted egress traffic for services running inside the service mesh.

Configure Istio with Prometheus, Jaeger, and cert-manager:

global:
  nodePort: false
  proxy:
    # replace with your GKE IP ranges
    includeIPRanges: "10.28.0.0/14,10.7.240.0/20"

sidecarInjectorWebhook:
  enabled: true
  enableNamespacesByDefault: false

gateways:
  enabled: true
  istio-ingressgateway:
    replicaCount: 2
    autoscaleMin: 2
    autoscaleMax: 3
    # replace with your Istio Gateway IP
    loadBalancerIP: "35.198.98.90"
    type: LoadBalancer

pilot:
  enabled: true
  replicaCount: 1
  autoscaleMin: 1
  autoscaleMax: 1
  resources:
    requests:
      cpu: 500m
      memory: 1024Mi

grafana:
  enabled: true
  security:
    enabled: true
    adminUser: admin
    # change the password
    adminPassword: admin

prometheus:
  enabled: true

servicegraph:
  enabled: true

tracing:
  enabled: true
  jaeger:
    tag: 1.7

certmanager:
  enabled: true

Save the above file as my-istio.yaml and install Istio with Helm:

helm upgrade --install istio ./install/kubernetes/helm/istio \
--namespace=istio-system \
-f ./my-istio.yaml

Verify that Istio workloads are running:

kubectl -n istio-system get pods

Configure Istio Gateway with LE TLS

Istio Let's Encrypt diagram

Create a Istio Gateway in istio-system namespace with HTTPS redirect:

apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: public-gateway
  namespace: istio-system
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "*"
    tls:
      httpsRedirect: true
  - port:
      number: 443
      name: https
      protocol: HTTPS
    hosts:
    - "*"
    tls:
      mode: SIMPLE
      privateKey: /etc/istio/ingressgateway-certs/tls.key
      serverCertificate: /etc/istio/ingressgateway-certs/tls.crt

Save the above resource as istio-gateway.yaml and then apply it:

kubectl apply -f ./istio-gateway.yaml

Create a service account with Cloud DNS admin role replace `my-gcp-project` with your project ID:

GCP_PROJECT=my-gcp-project

gcloud iam service-accounts create dns-admin \
--display-name=dns-admin \
--project=${GCP_PROJECT}

gcloud iam service-accounts keys create ./gcp-dns-admin.json \
--iam-account=dns-admin@${GCP_PROJECT}.iam.gserviceaccount.com \
--project=${GCP_PROJECT}

gcloud projects add-iam-policy-binding ${GCP_PROJECT} \
--member=serviceAccount:dns-admin@${GCP_PROJECT}.iam.gserviceaccount.com \
--role=roles/dns.admin

Create a Kubernetes secret with the GCP Cloud DNS admin key:

kubectl create secret generic cert-manager-credentials \
--from-file=./gcp-dns-admin.json \
--namespace=istio-system

Create a letsencrypt issuer for CloudDNS (replace email@example.com with a valid email address and my-gcp-projectwith your project ID):

apiVersion: certmanager.k8s.io/v1alpha1
kind: Issuer
metadata:
  name: letsencrypt-prod
  namespace: istio-system
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: email@example.com
    privateKeySecretRef:
      name: letsencrypt-prod
    dns01:
      providers:
      - name: cloud-dns
        clouddns:
          serviceAccountSecretRef:
            name: cert-manager-credentials
            key: gcp-dns-admin.json
          project: my-gcp-project

Save the above resource as letsencrypt-issuer.yaml and then apply it:

kubectl apply -f ./letsencrypt-issuer.yaml

Create a wildcard certificate replace `example.com` with your domain:

apiVersion: certmanager.k8s.io/v1alpha1
kind: Certificate
metadata:
  name: istio-gateway
  namespace: istio-system
spec:
  secretname: istio-ingressgateway-certs
  issuerRef:
    name: letsencrypt-prod
  commonName: "*.example.com"
  acme:
    config:
    - dns01:
        provider: cloud-dns
      domains:
      - "*.example.com"
      - "example.com"

Save the above resource as of-cert.yaml and then apply it:

kubectl apply -f ./of-cert.yaml

In a couple of seconds cert-manager should fetch a wildcard certificate from letsencrypt.org:

kubectl -n istio-system logs deployment/certmanager -f

Certificate issued successfully
Certificate istio-system/istio-gateway scheduled for renewal in 1438 hours

Recreate Istio ingress gateway pods:

kubectl -n istio-system delete pods -l istio=ingressgateway

Note that Istio gateway doesn't reload the certificates from the TLS secret on cert-manager renewal. Since the GKE cluster is made out of preemptible VMs the gateway pods will be replaced once every 24h, if your not using preemptible nodes then you need to manually kill the gateway pods every two months before the certificate expires.

Expose services outside the service mesh

In order to expose services via the Istio Gateway you have to create a Virtual Service attached to Istio Gateway.

Create a virtual service in istio-system namespace for Grafana replace `example.com` with your domain:

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: grafana
  namespace: istio-system
spec:
  hosts:
  - "grafana.example.com"
  gateways:
  - public-gateway.istio-system.svc.cluster.local
  http:
  - route:
    - destination:
        host: grafana
    timeout: 30s

Save the above resource as grafana-virtual-service.yaml and then apply it:

kubectl apply -f ./grafana-virtual-service.yaml

Navigate to http://grafana.example.com in your browser and you should be redirected to the HTTPS version.

Check that HTTP2 is enabled:

curl -I --http2 https://grafana.example.com

HTTP/2 200 
content-type: text/html; charset=UTF-8
x-envoy-upstream-service-time: 3
server: envoy