Getting Envoy Gateway working with kind without cloud-provider-kind
EXTERNAL-IP: <pending>. The official workaround is cloud-provider-kind, a
binary that watches the cluster and assigns real IPs from the Docker bridge
network.
The problem with cloud-provider-kind:
- It must run as a persistent background process alongside the cluster
- It’s not portable (no asdf plugin, no standard package)
- On systems without systemd (OpenRC, etc.) there’s no clean way to manage it as a service
I wanted to have a simple to bootstrap dev environment for henge , a platform to pushes config to edge devices.
The solution
Envoy Gateway provides an EnvoyProxy custom resource that lets you configure
how it creates the proxy service. Switching the service type to NodePort and
fixing the nodePort to a known value means kind’s extraPortMappings can map
it to a host port — no background process required.
1. kind config
Map the fixed NodePort to a host port in
infra/kind/kind-config.yaml
:
| |
containerPort is the port on the kind node (Docker container). hostPort is
the port on your machine. Pick a hostPort that isn’t already in use.
2. EnvoyProxy resource
Create
infra/kind/envoy-proxy.yaml
:
| |
The StrategicMerge patch type uses Kubernetes’s merge key mechanism — for
Service ports the merge key is port, so this merges with the existing port 80
entry rather than replacing all ports. The value field expects a YAML object,
not a JSON string (that was a gotcha we hit).
3. GatewayClass
Create
infra/kind/gateway-class.yaml
:
| |
4. Gateway
Reference the EnvoyProxy resource from your Gateway via
infrastructure.parametersRef:
| |
5. HTTPRoute
For SSE connections, set timeouts.request: 0s to prevent the proxy closing
long-lived connections.
Henge uses long running SSE connections without heartbeats to deploy config updates. Without this setting, it could look like the connection has closed when it hasn’t.
| |
The port chain
localhost:9876
→ kind node port 30080 (kind extraPortMappings)
→ Envoy Gateway NodePort (fixed via EnvoyProxy StrategicMerge patch)
→ Service port 80 (internal cluster routing)
→ Pod port 8080 (application)
Gotchas
install.yaml does not create a GatewayClass. Envoy Gateway v1.8.0’s
install manifest sets up the controller but does not create a GatewayClass.
Without it, the Gateway stays in Waiting for controller indefinitely. Create
it separately and apply it after the controller is running.
The GatewayClass takes a few seconds to reach Accepted: True. Apply it and
wait before applying the Gateway. If the Gateway is applied while the
GatewayClass is still Unknown, it will be accepted once the class is ready —
but worth checking kubectl get gatewayclass before proceeding.
extraPortMappings
cannot be changed without recreating the cluster. kind nodes are Docker
containers, and Docker container port mappings are fixed at creation time —
there’s no way to add or change them on a running container. If you change the
containerPort in kind config, you must run kind delete cluster and recreate
it. This is why fixing the nodePort matters — a random NodePort would require
tearing down and recreating the cluster every time it changed.
