Istio + Gateway API + NodePort
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.
- Install Gateway API CRDS
- Helm release istiod and istio-base
- Annotate Gateway manifest with Istio service type
- 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.