Testing the Kubernetes Gateway API with the Istio-based service mesh add-on for Azure Kubernetes Service
Back in July 2022 the Kubernetes Gateway API graduated to beta. The Istio control plane supports Gateway API resources, and this support is eventually going to be the default API in the future.
This article assumes you installed the Istio Service Mesh AKS add-on. A detailed example is available in my previous medium article.
Note: you can skip the classic Istio ingress gateway installation because it is not necessary when using Gateway API. However, if you install also the classic Istio ingress gateway you will have some extra pods but it will not prevent the Gateway API from working correctly.
Install the Gateway API custom resource definitions
To test Gateway API you need to install the necessary custom resource definitions:
kubectl get crd gateways.gateway.networking.k8s.io &> /dev/null || \
{ kubectl kustomize "github.com/kubernetes-sigs/gateway-api/config/crd?ref=v0.6.1" | kubectl apply -f -; }
This command will install the following crds:
gatewayclasses.gateway.networking.k8s.io
gateways.gateway.networking.k8s.io
grpcroutes.gateway.networking.k8s.io
httproutes.gateway.networking.k8s.io
referencegrants.gateway.networking.k8s.io
tcproutes.gateway.networking.k8s.io
tlsroutes.gateway.networking.k8s.io
udproutes.gateway.networking.k8s.io
Deploy a workload
You will deploy the echoserver
container to have a simple workload to test:
kubectl apply -f - <<EOF
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: echoserver
namespace: default
spec:
replicas: 1
selector:
matchLabels:
run: echoserver
template:
metadata:
labels:
run: echoserver
spec:
containers:
- name: echoserver
image: gcr.io/google_containers/echoserver:1.10
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: echoserver
namespace: default
spec:
ports:
- port: 8080
protocol: TCP
targetPort: 8080
selector:
run: echoserver
EOF
Expose the workload with Gateway API
With the classic Istio ingress gateway you would create a gateways.networking.istio.io
resource with a spec.selector
to match an existing Istio ingress gateway deployment. The information in the Gateway resource would be used to create a piece of Envoy configuration in the already running Istio ingress gateway pods.
Now you will use instead the gateways.gateway.networking.k8s.io
resource. This will create a dedicated Deployment
and Service
for this gateway:
kubectl apply -f - <<EOF
---
apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
name: echoserver
namespace: default
labels:
istio.io/rev: asm-1-17
annotations:
service.beta.kubernetes.io/azure-load-balancer-health-probe-request-path: "/healthz/ready"
service.beta.kubernetes.io/port_80_health-probe_protocol: http
service.beta.kubernetes.io/port_80_health-probe_port: "15021"
spec:
gatewayClassName: istio
listeners:
- name: http
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: All
EOF
To write the above Gateway
definition, I started from the Istio bookinfo sample, and I added some important Azure specific details:
- The label
istio.io/rev: asm-1-17
enablesGateway
injection correctly for the Istio based service mesh add-on. TheDeployment
template comes with the annotationsidecar.istio.io/inject: “true”
to make sure the pods are injected regardless of the labels on the namespace. However, the add-on uses Istio revisioned control plane so theistio.io/rev
label is necessary to enable the pod injection. The Istio Pod injection is necessary because in theDeployment
template the container image is set toimage: auto
and the Istio Pod injector adds the correct image reference. - The Gateway annotations are propagated to the Kubernetes
Service
oftype: LoadBalancer
that will expose theGateway
pods with an Azure Load Balancer. I added the necessaryService
annotations from the Azure LoadBalancer documentation to point the health checks, to the/healthz/ready
Envoy endpoint on port 15021, that is the endpoint meant to check the health status of theGateway
.
After applying the Gateway
you will see a new Deployment
and a new Service
both called echoserver-istio
. This is a key difference from the classic Istio ingress gateway operating model:
- Classic Istio ingress gateway: the istio ingress gateway
Deployment
andService
are provisioned at the installation time and the pods run with an empty configuration untilGateway
andVirtualService
resources are created to generate the necessary Envoy configuration - Gateway API: when the
Gateway
resource is created, the Istio control plane creates theDeployment
andService
.
When using the classic Istio ingress gateway the VirtualService
resource describes how a request is routed to a service. When using Gateway API you must use instead the HTTPRoute
resource. Here the simplest configuration to send all the requests to the backend:
kubectl apply -f - <<EOF
---
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: echoserver
namespace: default
spec:
parentRefs:
- name: echoserver
namespace: default
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: echoserver
port: 8080
EOF
The configuration is now complete and you can use curl
to test if you can reach the echoserver
Pod exposed correctly with Gateway API:
curl $(kubectl get service echoserver-istio -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
Conclusion
Istio supports Kubernetes Gateway API, and to use it on AKS you just need to add the necessary custom resource definitions.
You can use Kubernetes Gateway API to create Istio Gateways, or some of the other Gateway API implementations.
The Gateway
resource needs the correct istio.io/rev
label and the Azure Load Balancer annotations to configure the health checks.
Because Gateway API will be the default API for traffic management in Istio in the long term future, and it is also used in Istio Ambient for the Waypoint proxies, I strongly suggest to learn how it works and to get familiar with the Kubernetes Gateway API concepts.