Istio + Gateway API + NodePort

Ryan Graham
3 min readSep 10, 2024

--

Bully Istio into using a specific NodePort

This is fairly niche. In most cases you’ll probably want to use a ClusterIP service with a TargetGroupBinding (service endpoints are VPC CNI addresses for the Istio Proxy deployment pods) or a LoadBalancer service with AWS Load Balancer Controller. But if you _really_ want a NodePort, like maybe you have a network overlay and you don’t want to run AWS LBC, this is how you can do it.

  1. Install Gateway API CRDS
  2. Helm release istiod and istio-base
  3. Annotate Gateway manifest with Istio service type
  4. Add Service manifest that specifies NodePort settings

Install Gateway API CRDs

You can do this the easy way with kubectl or just drop the whole standard-install.yaml file into FluxCD like I do.

❯ kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.1.0/standard-install.yaml

Once done you should have the new CRDs…

❯ kubectl get crd
[...]
gateways.gateway.networking.k8s.io

Helm release Istio controllers

I drop both of these into FluxCD as well. There is a gateway chart too, but it seems unnecessary for this configuration.

apiVersion: v1
kind: Namespace
metadata:
name: istio-system
---
apiVersion: source.toolkit.fluxcd.io/v1beta2
kind: HelmRepository
metadata:
name: istio
namespace: istio-system
spec:
interval: 1h
url: https://istio-release.storage.googleapis.com/charts
---
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: istio-base
namespace: istio-system
spec:
interval: 6h
chart:
spec:
chart: base
version: "1.23.x"
sourceRef:
kind: HelmRepository
name: istio
---
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: istio-istiod
namespace: istio-system
spec:
interval: 6h
chart:
spec:
chart: istiod
version: "1.23.x"
sourceRef:
kind: HelmRepository
name: istio
dependsOn:
- name: istio-base

Create a Gateway with service-type annotation

If you don’t specify this annotation, Istio will create a Service with type LoadBalancer as soon as it sees the Gateway object. There are a lot of settings you can merge into the service yourself in the next step, but Type is not one of them.

apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
name: gateway-public
namespace: istio-system
annotations:
networking.istio.io/service-type: NodePort
spec:
gatewayClassName: istio
listeners:
- name: http
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: All

Override the service with your own NodePort settings

At this point Istio has already created its proxy deployment and service (name: gateway-public-istio), but we can give our service manifest the same name and merge in new ports.

apiVersion: v1
kind: Service
metadata:
annotations:
networking.istio.io/service-type: NodePort
labels:
gateway.istio.io/managed: istio.io-gateway-controller
gateway.networking.k8s.io/gateway-name: gateway-public
istio.io/gateway-name: gateway-public
name: gateway-public-istio
namespace: istio-system
spec:
selector:
gateway.networking.k8s.io/gateway-name: gateway-public
type: NodePort
ports:
- appProtocol: tcp
name: status-port
nodePort: 32751
port: 15021
protocol: TCP
targetPort: 15021
- appProtocol: http
name: http
nodePort: 30080
port: 80
protocol: TCP
targetPort: 80

Now your service should have a NodePort on 30080.

❯ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
gateway-public-istio NodePort 10.100.97.151 <none> 15021:32751/TCP,80:30080/TCP
istiod ClusterIP 10.100.103.254 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP

Summary

If for some bizarre reason you really do need Istio and Gateway API and a NodePort, I hope this helps. At the very least it will be a future reference for me when I forget.

--

--

No responses yet