The Kubernetes Gateway API is the successor of the Kubernetes Ingress API and is currently in beta state. More and more projects add support for the Gateway API like Istio.
In today’s blog post, I walk you through how to configure Istio using the Kubernetes Gateway API. At the time of writing, I am running my Azure Kubernetes Service cluster with Kubernetes version 1.25.6. The Istio version is 1.17.2 and the Gateway API version is 0.6.2.
I cover the following scenarios with my Gateway API configuration for Istio. First, the Istio ingress gateway gets created in the istio-system namespace. Same as with the standard Istio installation. Second, the routing configuration is placed into a dedicated namespace called istio-config to separate the Istio installation from the configuration of the service routing. The last scenario is the automatic redirection of HTTP traffic to HTTPS.
Install Kubernetes Gateway API CRDs
Before we can use the Gateway API on an Azure Kubernetes Service cluster, we must install the Gateway API CRDs. In total, we install four custom resource definitions, short CRDs. The GatewayClass, Gateway, HTTPRoute, and ReferenceGrant.
GATEWAY_API_TAG='v0.6.2' kubectl apply -f "https://raw.githubusercontent.com/kubernetes-sigs/gateway-api/$GATEWAY_API_TAG/config/crd/standard/gateway.networking.k8s.io_gatewayclasses.yaml" kubectl apply -f "https://raw.githubusercontent.com/kubernetes-sigs/gateway-api/$GATEWAY_API_TAG/config/crd/standard/gateway.networking.k8s.io_gateways.yaml" kubectl apply -f "https://raw.githubusercontent.com/kubernetes-sigs/gateway-api/$GATEWAY_API_TAG/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml" kubectl apply -f "https://raw.githubusercontent.com/kubernetes-sigs/gateway-api/$GATEWAY_API_TAG/config/crd/standard/gateway.networking.k8s.io_referencegrants.yaml"
When you follow the Istio documentation and use the kustomize command, you only install three CRDs. The ResourceGrant CRD is not part of the kustomize template but required to fulfill our second scenario.
Set up the Istio ingress gateway
After the CRD installation, we proceed with the definition to configure the Istio ingress gateway. The gateway configuration is kept simple and consists of the two required spec sections gatewayClassName and listeners.
apiVersion: gateway.networking.k8s.io/v1beta1 kind: Gateway metadata: name: gw-api namespace: istio-system spec: gatewayClassName: istio listeners: ...
For the gatewayClassName, we use istio as this is the name of the GatewayClass resource in our case.
❯ kubectl get gatewayclasses.gateway.networking.k8s.io NAME CONTROLLER ACCEPTED AGE istio istio.io/gateway-controller True 9d
We define two listeners, one for HTTP and one for HTTPS traffic.
... - name: http hostname: "*.danielstechblog.de" port: 80 protocol: HTTP allowedRoutes: namespaces: from: Same kinds: - group: gateway.networking.k8s.io kind: HTTPRoute ...
The one for HTTP traffic restricts the route configuration to the same namespace in which the Istio ingress gateway gets deployed. We will talk about the why in the section about the HTTP to HTTPS traffic redirection. Also, the route configuration is restricted to the kind HTTPRoute.
Allowed routes can be configured beside the value Same with two other values. All to allow route configuration from every namespace or Selector to allow them only from namespaces with a specific label as seen in the HTTPS listener configuration below.
... - name: https hostname: "*.danielstechblog.de" port: 443 protocol: HTTPS allowedRoutes: namespaces: from: Selector selector: matchLabels: ingress-configuration: "true" kinds: - group: gateway.networking.k8s.io kind: HTTPRoute tls: mode: Terminate certificateRefs: - kind: Secret group: "" name: istio-ingress-cert namespace: istio-system
The HTTPS listener configuration has an additional tls section for the HTTPS configuration. Which mode should be used, Terminate or Passthrough? Furthermore, we specify at least one certificate reference. Per default, the certificate reference uses the same namespace as the ingress gateway.
Currently, the Istio ingress gateway deployed by the Kubernetes Gateway API runs only with one replica. We must deploy a horizontal pod autoscaler and a pod disruption budget resource having the same configuration as the default Istio ingress gateway.
apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: gw-api spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: gw-api-istio minReplicas: 3 maxReplicas: 6 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 80 --- apiVersion: policy/v1 kind: PodDisruptionBudget metadata: name: gw-api spec: minAvailable: 50% selector: matchLabels: istio.io/gateway-name: gw-api
Adding those additional resources ensures a highly available ingress gateway.
Configure HTTP routing
Let us start with the routing configuration for the HTTP to HTTPS redirect.
apiVersion: gateway.networking.k8s.io/v1beta1 kind: HTTPRoute metadata: name: http-to-https-redirect namespace: istio-system spec: parentRefs: - name: gw-api namespace: istio-system hostnames: - "*.danielstechblog.de" rules: - filters: - type: RequestRedirect requestRedirect: scheme: https statusCode: 301 port: 443
The routing configuration is attached with a parent reference to the respective ingress gateway. Under the rules section, the actual configuration happens how traffic is handled.
In the case of the redirect, we use a filter of type RequestRedirect. Even we use the scheme https, we must specify the port, 443, as otherwise, the redirect uses port 80.
❯ curl -sIL http://gwapi.danielstechblog.de HTTP/1.1 301 Moved Permanently location: https://gwapi.danielstechblog.de:80/ date: Thu, 18 May 2023 21:02:14 GMT server: istio-envoy transfer-encoding: chunked
Now the explanation of why we restrict the routing configuration of the HTTP listener to the istio-system namespace or in general, to a dedicated namespace. For instance, using All or placing the redirect routing configuration into the same namespace as the other configurations and using the Selector option would allow HTTP traffic to the services directly instead of redirecting traffic from HTTP to HTTPS.
❯ curl -sIL http://gwapi.danielstechblog.de HTTP/1.1 200 OK date: Thu, 18 May 2023 20:56:17 GMT content-length: 107 content-type: text/html; charset=utf-8 x-envoy-upstream-service-time: 8 server: istio-envoy
Using a dedicated namespace lets the redirect work as intended.
❯ curl -sIL http://gwapi.danielstechblog.de HTTP/1.1 301 Moved Permanently location: https://gwapi.danielstechblog.de:443/ date: Thu, 18 May 2023 20:51:18 GMT server: istio-envoy transfer-encoding: chunked HTTP/2 200 date: Thu, 18 May 2023 20:51:18 GMT content-length: 107 content-type: text/html; charset=utf-8 x-envoy-upstream-service-time: 5 server: istio-envoy
After putting the redirect into place, we continue our routing configuration, enabling our application to receive traffic.
apiVersion: gateway.networking.k8s.io/v1beta1 kind: HTTPRoute metadata: name: go-webapp namespace: istio-config spec: parentRefs: - name: gw-api namespace: istio-system hostnames: - "*.danielstechblog.de" rules: - backendRefs: - name: go-webapp-gw-api namespace: go-webapp port: 80
The routing configuration for our application is deployed, as mentioned in the scenarios, to a namespace called istio-config. We use a backend reference under the rules section to direct traffic to our application. Directing traffic to the root path / does not require anything else in this case.
Besides the routing configuration, we need a ReferenceGrant resource in the application namespace, as the routing configuration lives in a different namespace than our application.
apiVersion: gateway.networking.k8s.io/v1beta1 kind: ReferenceGrant metadata: name: go-webapp namespace: go-webapp spec: from: - group: gateway.networking.k8s.io kind: HTTPRoute namespace: istio-config to: - group: "" kind: Service name: go-webapp-gw-api
A reference grant allows the backend reference from a routing configuration that lives in a different namespace. We can specify in the to section if we want to allow the backend reference to all Kubernetes service objects or only a specific one like go-webapp-gw-api in the example above.
Can I run Istio in both modes in parallel?
Istio supports running both modes in parallel. As long as we have specified the Istio ingress gateway in our IstioOperator template, we will get it deployed and can add an Istio ingress gateway via the Kubernetes Gateway API besides the default one.
In the screenshot above we see an Istio installation using both modes in parallel on the same Kubernetes cluster.
The application served by the Istio ingress gateway deployed via the Gateway API is presented on the left side and returns a red page. Vice versa, on the right side, we see the application served by the default Istio ingress gateway, returning a blue page.
Setting up and configuring the Istio ingress gateway via the Kubernetes Gateway API is straightforward. Yes, some quirks need to be considered like the horizontal pod autoscaler and the pod disruption budget. But the Gateway API looks very promising to be the standard in the future for ingress configuration as well as for the service mesh configuration which is currently driven by the GAMMA initiative. Hence, you should give it a try and get familiar with the Kubernetes Gateway API whether you are using Istio or not.
You can find my configuration examples in my GitHub repository.
Additional resources about the Kubernetes Gateway API are linked below.