# Kubernetes Gateway API ## 1. Why Gateway API Exists When applications run in Kubernetes, users must be able to access them from outside, and services inside the cluster must communicate with each other. For a long time, Kubernetes used **Ingress** to expose applications. Ingress worked, but as systems grew larger and teams increased, many real problems appeared. To solve these problems, Kubernetes introduced the **Gateway API**. {/* TODO: Add architecture comparison diagram showing Ingress vs Gateway API role separation */} {/* TODO: Add diagram showing Gateway API multi-team model (infra provider → GatewayClass, cluster operator → Gateway, app developer → HTTPRoute/TLSRoute) */} ## 2. Understanding Traffic in Kubernetes Before learning Gateway API, we must understand how traffic moves. ### 2.1 North–South Traffic North–South traffic means: - Traffic coming **into** the cluster from outside - Traffic going **out** of the cluster Examples: - User opens a website in a browser - Mobile app calls an API in Kubernetes - External system connects to a service This is **external traffic**. ### 2.2 East–West Traffic East–West traffic means: - Traffic **inside** the cluster - Service talking to another service Examples: - Frontend calls backend - Order service calls payment service This is **internal traffic**. **Important Note:** - **Ingress and Gateway API** → handle **North–South traffic** - **Service Mesh** → handles **East–West traffic** ## 3. What Is Ingress? Ingress is a Kubernetes object that: - Exposes services outside the cluster - Routes traffic using hostnames and paths Example: ``` / → frontend service /api → backend service ``` Ingress worked well for: - Small clusters - Single-team setups - Basic routing ## 4. Problems with Ingress (Why Change Was Needed) As Kubernetes moved to production at scale, the following issues became apparent: - **Everything in one file** - Load balancer config, TLS config, routing rules - all mixed together. - **Annotations everywhere** - Important logic hidden in annotations. - **Hard to read and debug** - Large, complex Ingress manifests are difficult to maintain. - **No clear ownership** - Application teams could modify infrastructure settings, creating risk in multi-team clusters. - **Different behavior per controller** - The same YAML can behave differently with NGINX, ALB, and other controllers. - **Security concerns and retirement** - The widely-used Ingress NGINX controller is being retired and will no longer receive updates or security patches after March 2026, making it unsuitable for long-term production use. See the official retirement announcement: [https://kubernetes.io/blog/2025/11/11/ingress-nginx-retirement/](https://kubernetes.io/blog/2025/11/11/ingress-nginx-retirement/) Ingress was simple, but not safe or scalable for large environments. ## 5. What Is Gateway API? Gateway API is a **new Kubernetes networking API** designed to fix the limitations of Ingress. It provides: - Clear separation of responsibilities - Standard behavior across implementations - Safer configuration for production - Support for advanced routing Gateway API separates concerns across three roles: | Role | Resource | Responsibility | | ----------------------- | ------------------------ | ----------------------------------------- | | Infrastructure Provider | `GatewayClass` | Defines available gateway implementations | | Cluster Operator | `Gateway` | Configures load balancers, TLS, listeners | | Application Developer | `HTTPRoute` / `TLSRoute` | Defines application routing rules | ## 6. Implementation Guide The Gateway API is a set of standard APIs, but the cluster still needs an **implementation** (a controller) to act on them. This guide uses [Envoy Gateway](https://gateway.envoyproxy.io/). ### Prerequisites - An active E2E Kubernetes cluster with `kubectl` access. - `helm` installed. - At least one IP reserved in your cluster's LoadBalancer pool - the Gateway is exposed through a `LoadBalancer` Service and consumes one pool IP. See [Assigning an External IP](/docs/myaccount/kubernetes/guides/kubernetes-services/#assigning-an-external-ip-for-loadbalancer-service-on-e2e-kubernetes). ### Step 1: Install the Gateway API CRDs and Envoy Gateway The Gateway API CRDs are **not** installed on an E2E cluster by default. The Envoy Gateway Helm chart installs both the CRDs and the controller: ```bash helm install eg oci://docker.io/envoyproxy/gateway-helm \ --version v1.6.1 \ -n envoy-gateway-system \ --create-namespace ``` Wait for it to become available: ```bash kubectl wait --timeout=5m -n envoy-gateway-system \ deployment/envoy-gateway --for=condition=Available ``` ### Step 2: Create a GatewayClass The `GatewayClass` tells Kubernetes which controller manages your Gateways. Save as `gatewayclass.yaml`: ```yaml apiVersion: gateway.networking.k8s.io/v1 kind: GatewayClass metadata: name: envoy-gateway-class spec: controllerName: gateway.envoyproxy.io/gatewayclass-controller ``` ```bash kubectl apply -f gatewayclass.yaml kubectl get gatewayclass ``` The `ACCEPTED` column should read `True`. ### Step 3: Create a Gateway The `Gateway` provisions the actual load balancer and listeners. Save as `gateway.yaml`: ```yaml apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: api-gateway namespace: default spec: gatewayClassName: envoy-gateway-class listeners: - name: http protocol: HTTP port: 80 allowedRoutes: namespaces: from: All ``` ```bash kubectl apply -f gateway.yaml kubectl get gateway ``` Envoy Gateway creates a `LoadBalancer` Service for this Gateway, and E2E's MetalLB assigns it an IP from your reserved pool. Once an IP is attached, the Gateway's `ADDRESS` is populated and `PROGRAMMED` reads `True`. ### Step 4: Deploy a Backend and Route Traffic Deploy a sample app and expose it with an `HTTPRoute`. Save as `app.yaml`: ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: backend-1 spec: replicas: 1 selector: matchLabels: app: backend-1 template: metadata: labels: app: backend-1 spec: containers: - name: backend-1 image: nginxdemos/hello:plain-text ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: backend-1 spec: selector: app: backend-1 ports: - port: 80 targetPort: 80 --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: host-route spec: parentRefs: - name: api-gateway namespace: default hostnames: - app.yourdomain.com rules: - matches: - path: type: PathPrefix value: / backendRefs: - name: backend-1 port: 80 ``` ```bash kubectl apply -f app.yaml kubectl get httproute ``` ### Step 5: Test Point a DNS A record for `app.yourdomain.com` at the Gateway's `ADDRESS`, or test directly with a `Host` header: ```bash GATEWAY_IP=$(kubectl get gateway api-gateway -o jsonpath='{.status.addresses[0].value}') curl -H "Host: app.yourdomain.com" http://$GATEWAY_IP/ ``` A request whose host matches the `HTTPRoute` is served by `backend-1`; a request with an unknown host returns `404` from the Gateway. ## 7. Adding HTTPS To terminate TLS, add an `https` listener with a `certificateRefs` entry to the `Gateway`, and provision the referenced certificate with cert-manager. For an end-to-end example that combines a TLS-enabled Gateway, cert-manager, and HTTPRoutes, see the [Argo CD guide](/docs/myaccount/kubernetes/guides/argocd/), which uses this same Gateway API setup. ---