After realizing that there wasn't a comprehensive tutorial on integrating GCP's Ingress load balancer with Istio Service Mesh in a Google Kubernetes Engine (GKE) cluster, I decided to create one myself. I hope this guide saves you hours of searching and helps streamline your kubernetes networking.
Note: This tutorial expects you have already setup your DNS records (example A
, CNAME
records) pointing to the external IP used by GCP's Ingress
load balancer.
So let's start by defining our GCP Ingress
Load Balancer.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
name: gcp-load-balancer
namespace: istio-ingress # the k8s ns where your istio-ingressgateway helm chart is deployed
spec:
rules:
- host: '*.example.domain.com'
http:
paths:
# This section specifies the backend service to which the traffic matching the rule should be routed.
- backend:
service:
# This is the name of the Kubernetes service that will handle the traffic. Here, it points to the istio-ingressgateway service
name: istio-ingressgateway
port:
number: 80
path: /
pathType: Prefix
GCP's BackendConfig
used by the Ingress
named gcp-load-balancer
to check if the defined service is healthy.
apiVersion: cloud.google.com/v1
kind: BackendConfig
metadata:
name: load-balancer-backendconfig
namespace: istio-ingress
spec:
healthCheck:
checkIntervalSec: 30
port: 15021 # will match port defined in istio helm chart, check below
requestPath: /healthz/ready
type: HTTP
For this example I'm using Istio's ingress gateway helm chart with default values (as can be seen here) except for the following overrides:
defaults:
...
service:
type: NodePort # change to NodePort since the load balancer is GCP's ingress defined above
ports:
- name: status-port
port: 30276
protocol: TCP
targetPort: 15021 # this needs to match PORT defined in BackendConfig above
- name: http
port: 80
protocol: TCP
targetPort: 80
- name: https
port: 443
protocol: TCP
targetPort: 443
annotations: {
# Add backend for gcp-load-balancer healthcheck
cloud.google.com/backend-config: '{"default": "load-balancer-backendconfig"}',
}
...
Now we want to serve a simple example k8s Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: status-app
name: status-app
namespace: status
spec:
revisionHistoryLimit: 1
selector:
matchLabels:
app: status-app
template:
metadata:
labels:
app: status-app
spec:
containers:
- args:
- ok
- name: nodejs-server-port-80
# this is just a simple nodejs server that returns status 200 and string "ok"
image: cooervo/server-with-args
ports:
- containerPort: 80
The corresponding Service
:
apiVersion: v1
kind: Service
metadata:
labels:
app: status-app
name: status-app
namespace: status
spec:
ports:
- name: http
port: 80
targetPort: 80
selector:
app: status-app
type: ClusterIP # type ClusterIp since external access is handled by gcp-load-balancer and the istio-ingressgateway
Now add Istio's Gateway
which uses wildcard hosts since the specific paths will be handled by Istio's VirtualServices
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: default-gateway
namespace: istio-ingress
spec:
selector:
istio: ingressgateway
servers:
- hosts:
- '*.example.domain.com'
port:
name: http
number: 80
protocol: HTTP
Finally, let's add an Istio VirtualService
for handling the status.example.domain.com
path.
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: status-app
namespace: status
spec:
gateways:
# the gateway defined above
- istio-ingress/default-gateway
hosts:
- status.example.domain.com
http:
- match:
- uri:
prefix: /
route:
- destination:
# host value is {service}.{namespace}.svc.cluster.local
host: status-app.status.svc.cluster.local
port:
number: 80
That's all once you have deployed all the above resources the status
example app should be accessible when visiting http://status.example.domain.com
Attaching a TLS certificate
Using cert-manager
certificates with the Ingress
load balancer is posible.
Firstly, install cert-manager
with your prefer method I used the official helm chart.
Create a ClusterIssuer
as follows:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt
spec:
acme:
email: my-email@domain.com
privateKeySecretRef:
name: letsencrypt
server: https://acme-v02.api.letsencrypt.org/directory
solvers:
- dns01:
cloudDNS:
project: your-gcp-project
selector:
dnsZones:
- '*.example.domain.com'
Now you can create a wildcard certificate to use in your http load balancer:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: wildcard-cert
namespace: istio-ingress
spec:
dnsNames:
- '*.example.domain.com'
issuerRef:
kind: ClusterIssuer
name: letsencrypt
secretName: wildcard-cert
Finally attach it in your Ingress
by adding the following block:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
...
# the name of the ClusterIssuer defined above
cert-manager.io/cluster-issuer: letsencrypt
name: gcp-load-balancer
namespace: istio-ingress
spec:
rules:
...
tls:
- hosts:
- '*.example.domain.com'
secretName: wildcard-cert
You should be able to visit https://status.example.domain.com
the TLS wildcard certificate will be used to encrypt connections to your kubernetes services.