Experimenting with Gateway API using kind
Source: Kubernetes Blog
Overview
This guide will walk you through setting up a local experimental environment with Gateway API on kind. It’s intended for learning and testing, not for production use.
What you’ll do
- Set up a local Kubernetes cluster using kind (Kubernetes in Docker)
- Deploy cloud-provider-kind, which provides both LoadBalancer Services and a Gateway API controller
- Create a Gateway and HTTPRoute to route traffic to a demo application
- Test your Gateway API configuration locally
Prerequisites
Ensure the following tools are installed on your machine:
- Docker – required to run kind and cloud‑provider‑kind
- kubectl – Kubernetes command‑line tool
- kind – Kubernetes in Docker
- curl – needed to test the routes
Create a kind cluster
Create a single‑node cluster:
kind create cluster
Install cloud-provider-kind
cloud‑provider‑kind supplies two key components:
- A LoadBalancer controller that assigns addresses to LoadBalancer‑type Services
- A Gateway API controller that implements the Gateway API specification
It also automatically installs the Gateway API CRDs.
Run it as a Docker container on the same host:
VERSION="$(basename $(curl -s -L -o /dev/null -w '%{url_effective}' https://github.com/kubernetes-sigs/cloud-provider-kind/releases/latest))"
docker run -d --name cloud-provider-kind --rm --network host \
-v /var/run/docker.sock:/var/run/docker.sock \
registry.k8s.io/cloud-provider-kind/cloud-controller-manager:${VERSION}
Note: On some systems you may need elevated privileges to access the Docker socket.
Verify it’s running:
docker ps --filter name=cloud-provider-kind
docker logs cloud-provider-kind
Experimenting with Gateway API
cloud‑provider‑kind automatically creates a GatewayClass named cloud-provider-kind. You’ll use this class to create your Gateway.
Deploy a Gateway
The following manifest will:
- Create a namespace
gateway-infra - Deploy a Gateway listening on port 80
- Accept HTTPRoutes with hostnames matching
*.exampledomain.example - Allow routes from any namespace to attach to the Gateway
---
apiVersion: v1
kind: Namespace
metadata:
name: gateway-infra
---
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: gateway
namespace: gateway-infra
spec:
gatewayClassName: cloud-provider-kind
listeners:
- name: default
hostname: "*.exampledomain.example"
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: All
Apply the manifest:
kubectl apply -f gateway.yaml # (or pipe the manifest directly)
Verify the Gateway is programmed and has an address:
kubectl get gateway -n gateway-infra gateway
Expected output
NAME CLASS ADDRESS PROGRAMMED AGE
gateway cloud-provider-kind 172.18.0.3 True 5m6s
The PROGRAMMED column should be True, and the ADDRESS field should contain an IP.
Deploy a demo application
Deploy a simple echo app that listens on port 3000 and returns request details.
apiVersion: v1
kind: Namespace
metadata:
name: demo
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/name: echo
name: echo
namespace: demo
spec:
ports:
- name: http
port: 3000
protocol: TCP
targetPort: 3000
selector:
app.kubernetes.io/name: echo
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/name: echo
name: echo
namespace: demo
spec:
selector:
matchLabels:
app.kubernetes.io/name: echo
template:
metadata:
labels:
app.kubernetes.io/name: echo
spec:
containers:
- image: registry.k8s.io/gateway-api/echo-basic:v20251204-v1.4.1
name: echo-basic
env:
- name: POD_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
- name: NAMESPACE
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
Apply the manifest:
kubectl apply -f demo-app.yaml
Create an HTTPRoute
Route traffic from the Gateway to the echo app.
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: echo
namespace: demo
spec:
parentRefs:
- name: gateway
namespace: gateway-infra
hostnames: ["some.exampledomain.example"]
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: echo
port: 3000
Apply the manifest:
kubectl apply -f httproute.yaml
Test your route
Fetch the Gateway’s IP address and issue a request with the appropriate hostname:
GW_ADDR=$(kubectl get gateway -n gateway-infra gateway -o jsonpath='{.status.addresses[0].value}')
curl --resolve some.exampledomain.example:80:${GW_ADDR} http://some.exampledomain.example
You should receive a JSON response similar to:
{
"path": "/",
"host": "some.exampledomain.example",
"method": "GET",
"proto": "HTTP/1.1",
"headers": {
"Accept": ["*/*"],
"User-Agent": ["curl/8.15.0"]
},
"namespace": "demo",
"ingress": "",
"service": "",
"pod": "echo-dc48d7cf8-vs2df"
}
If you see this output, your Gateway API setup is working.
Troubleshooting
Check the Gateway status
kubectl get gateway -n gateway-infra gateway -o yaml
Look for conditions:
Accepted: TrueProgrammed: True.status.addressespopulated with an IP
Check the HTTPRoute status
kubectl get httproute -n demo echo -o yaml
Inspect status.parents for conditions such as:
ResolvedRefs: False(reason:BackendNotFound) – the Service may be missing or misnamedAccepted: False– the route couldn’t attach to the Gateway (check namespace permissions or hostname)
Example error snippet:
status:
parents:
- conditions:
- lastTransitionTime: "2026-01-19T17:13:35Z"
message: backend not found
observedGeneration: 2
reason: BackendNotFound
status: "False"
type: ResolvedRefs
controllerName: kind.sigs.k8s.io/gateway-controller
Check controller logs
docker logs -f cloud-provider-kind
Logs include details from both the LoadBalancer and Gateway API controllers.
Cleanup
When you’re done experimenting:
Remove Kubernetes resources
kubectl delete namespace gateway-infra
kubectl delete namespace demo
Stop cloud‑provider‑kind
docker stop cloud-provider-kind # container auto‑removes due to --rm
Delete the kind cluster
kind delete cluster
Next steps
- Production Deployments: Review Gateway API implementations to find a controller that meets your production requirements.
- Learn More: Explore the Gateway API docs for advanced features like TLS, traffic splitting, and header manipulation.
- Advanced Routing: Try path‑based routing, header matching, request mirroring, and other capabilities using the official user guides.
A final word of caution
This kind‑based setup is for development and learning only. For real workloads, always use a production‑grade Gateway API implementation.