Your First Route
Now that Nantian Gateway is running, let’s create a Gateway resource and an HTTPRoute to proxy traffic to a backend service. This is the core workflow you’ll use every time you expose a service through the gateway.
By the end of this guide, you’ll have a working HTTP route that accepts requests on port 10080 and forwards them to a sample application.
Overview
Section titled “Overview”The Kubernetes Gateway API defines three resources that work together:
- GatewayClass: Defines a class of gateway controllers. Nantian Gateway creates one automatically during installation with the controller name
gateway.networking.k8s.io/nantian-gw. - Gateway: A request for a point where traffic can be translated to Services within the cluster. You create this to tell the gateway to start listening on a port.
- HTTPRoute: Defines rules for matching HTTP traffic and forwarding it to backend services. This is where you specify paths, headers, and destination services.
The flow is: GatewayClass defines which controller handles the request, Gateway opens a listener port, and HTTPRoute maps incoming requests to backend pods.
Step 1: Deploy a sample backend
Section titled “Step 1: Deploy a sample backend”First, create a simple echo server that responds to HTTP requests. This gives us something to route traffic to.
Create a file called echo-server.yaml:
apiVersion: v1kind: Namespacemetadata: name: echo---apiVersion: apps/v1kind: Deploymentmetadata: name: echo-server namespace: echospec: replicas: 2 selector: matchLabels: app: echo-server template: metadata: labels: app: echo-server spec: containers: - name: echo-server image: ealen/echo-server:latest ports: - containerPort: 80 env: - name: PORT value: "80"---apiVersion: v1kind: Servicemetadata: name: echo-server namespace: echospec: selector: app: echo-server ports: - protocol: TCP port: 80 targetPort: 80Apply it:
kubectl apply -f echo-server.yamlExpected output:
namespace/echo createddeployment.apps/echo-server createdservice/echo-server createdVerify the echo server is running:
kubectl get pods -n echoExpected output:
NAME READY STATUS RESTARTS AGEecho-server-xxxxxxxxx-xxxxx 1/1 Running 0 30secho-server-xxxxxxxxx-xxxxx 1/1 Running 0 25sStep 2: Create a Gateway
Section titled “Step 2: Create a Gateway”Now create a Gateway resource that tells Nantian Gateway to listen for HTTP traffic. The Gateway references the GatewayClass that was created during installation.
Create a file called gateway.yaml:
apiVersion: gateway.networking.k8s.io/v1kind: Gatewaymetadata: name: my-gateway namespace: echospec: gatewayClassName: nantian-gw listeners: - name: http protocol: HTTP port: 80 allowedRoutes: namespaces: from: SameApply it:
kubectl apply -f gateway.yamlExpected output:
gateway.gateway.networking.k8s.io/my-gateway createdCheck the Gateway status:
kubectl get gateway -n echoExpected output:
NAME CLASS ADDRESS PROGRAMMED AGEmy-gateway nantian-gw <pending> True 10sThe PROGRAMMED column should show True once the control plane has processed the Gateway. The ADDRESS column may show <pending> until the data plane allocates an address, which is normal for non-cloud environments.
You can also inspect the Gateway in detail:
kubectl describe gateway my-gateway -n echoLook for the Status section. A healthy Gateway shows:
Status: Addresses: Conditions: Last Transition Time: ... Message: ... Observed Generation: 1 Reason: Programmed Status: True Type: Programmed Listeners: Attached Routes: 0 Conditions: Last Transition Time: ... Message: ... Observed Generation: 1 Reason: Programmed Status: True Type: Programmed Name: httpStep 3: Create an HTTPRoute
Section titled “Step 3: Create an HTTPRoute”Now create an HTTPRoute that matches incoming requests and forwards them to the echo server.
Create a file called httproute.yaml:
apiVersion: gateway.networking.k8s.io/v1kind: HTTPRoutemetadata: name: echo-route namespace: echospec: parentRefs: - name: my-gateway rules: - matches: - path: type: PathPrefix value: / backendRefs: - name: echo-server port: 80Apply it:
kubectl apply -f httproute.yamlExpected output:
httproute.gateway.networking.k8s.io/echo-route createdCheck the route status:
kubectl get httproute -n echoExpected output:
NAME HOSTNAMES AGEecho-route 10sMake sure the route is accepted by describing it:
kubectl describe httproute echo-route -n echoThe Status section should show:
Status: Parents: Conditions: Last Transition Time: ... Message: ... Observed Generation: 1 Reason: Accepted Status: True Type: Accepted Controller Name: gateway.networking.k8s.io/nantian-gw Parent Ref: Kind: Gateway Name: my-gateway Namespace: echoThe Accepted condition tells you the control plane validated the route and pushed it to the data plane.
Step 4: Test the traffic
Section titled “Step 4: Test the traffic”The data plane listens on port 10080 inside the cluster. Depending on how you set up your Kind cluster, you have a few ways to reach it.
Option A: Port mapping (Kind with extraPortMappings)
Section titled “Option A: Port mapping (Kind with extraPortMappings)”If you used the standard Kind config with port mappings, the gateway is reachable on your host at port 18080:
curl http://localhost:18080/Option B: Port forwarding
Section titled “Option B: Port forwarding”If you didn’t set up port mappings, port-forward to the data plane service:
kubectl port-forward -n nantian-gw svc/nantian-gw-dataplane 8080:10080Then in another terminal:
curl http://localhost:8080/Option C: Within the cluster
Section titled “Option C: Within the cluster”Run a temporary pod inside the cluster to test:
kubectl run curl-test --image=curlimages/curl:latest -it --rm --restart=Never -- \ curl -s http://nantian-gw-dataplane.nantian-gw.svc:10080/Expected response
Section titled “Expected response”The echo server returns a JSON response with details about the request:
{ "host": { "hostname": "localhost", "ip": "::ffff:10.244.x.x", "ips": [] }, "http": { "method": "GET", "baseUrl": "", "originalUrl": "/", "protocol": "http" }, "request": { "params": { "0": "/" }, "query": {}, "cookies": {}, "body": {}, "headers": { "host": "localhost:18080", "user-agent": "curl/8.x.x", "accept": "*/*" } }, "environment": { "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "HOSTNAME": "echo-server-xxxxxxxxx-xxxxx", "NODE_VERSION": "x.x.x" }}The response confirms that the request traveled through the Nantian Gateway data plane and reached the echo server backend. The HOSTNAME field shows which echo server pod handled the request, and the host header reflects the original request.
Step 5: Try path-based routing
Section titled “Step 5: Try path-based routing”Let’s add a second route to demonstrate path matching. Deploy another backend:
apiVersion: apps/v1kind: Deploymentmetadata: name: whoami namespace: echospec: replicas: 1 selector: matchLabels: app: whoami template: metadata: labels: app: whoami spec: containers: - name: whoami image: traefik/whoami:latest ports: - containerPort: 80---apiVersion: v1kind: Servicemetadata: name: whoami namespace: echospec: selector: app: whoami ports: - protocol: TCP port: 80 targetPort: 80Apply it and update the HTTPRoute to add a path rule:
apiVersion: gateway.networking.k8s.io/v1kind: HTTPRoutemetadata: name: echo-route namespace: echospec: parentRefs: - name: my-gateway rules: - matches: - path: type: PathPrefix value: /whoami backendRefs: - name: whoami port: 80 - matches: - path: type: PathPrefix value: / backendRefs: - name: echo-server port: 80Apply the updated route:
kubectl apply -f httproute.yamlNow test the routing:
# Requests to /whoami go to the whoami servicecurl http://localhost:18080/whoami
# Everything else goes to the echo servercurl http://localhost:18080/helloThe gateway inspects the request path and forwards it to the matching backend. Routes are evaluated in order, so the more specific /whoami prefix is checked before the catch-all / rule.
Cleanup
Section titled “Cleanup”When you’re done experimenting, remove the resources:
kubectl delete namespace echoOr to keep the namespace but remove the Gateway API resources:
kubectl delete httproute echo-route -n echokubectl delete gateway my-gateway -n echoWhat’s next
Section titled “What’s next”You’ve deployed a Gateway and HTTPRoute and verified traffic flows through the data plane. Here are some next steps:
- Installation options: Learn about Helm customization, Kustomize overlays, and production deployment.
- TLS configuration: Set up TLS listeners and mTLS for secure traffic.
- Observability: Enable metrics scraping and set up Grafana dashboards.
- Architecture: Read the architecture overview to understand the control plane and data plane split.
- API reference: Browse the Gateway API resources and custom CRDs.