In Kubernetes, Ingress was once the standard solution for exposing services to external traffic. However, as microservices and multi-tenant scenarios have grown more complex, the limitations of Ingress have become increasingly apparent: its reliance on controller-specific annotations hinders portability, while its limited routing expressiveness makes fine-grained traffic splitting and cross-namespace referencing difficult. The Gateway API—a next-generation service networking standard developed by Kubernetes SIG-Network—was designed to replace Ingress. By employing role separation (among infrastructure providers, cluster operators, and application developers) and utilizing strongly-typed Custom Resource Definitions (CRDs), the Gateway API makes gateway configuration portable, composable, and extensible.
This guide walks you through the installation of the Gateway API and the configuration of your first traffic route, using a standard, actively maintained version.
Prerequisites: Cluster and Tools
Before you begin, ensure the following: you have an accessible Kubernetes cluster (version 1.25 or higher is recommended), `kubectl` is correctly configured to point to that cluster, and you possess `cluster-admin` privileges (required for installing CRDs and controllers).
The Gateway API itself consists solely of resource definitions (CRDs)—specifically API objects such as `GatewayClass`, `Gateway`, and `HTTPRoute`. To enable these objects to actually drive traffic through the data plane, a controller implementation is required. You can think of this relationship as an "interface" versus an "implementation": the Gateway API serves as the standard interface, while projects like Envoy Gateway, NGINX Gateway Fabric, and Cilium provide the concrete implementations.
Step 1: Install the Gateway API Standard CRDs
Gateway API CRDs are not installed by default in a Kubernetes cluster and must be deployed manually. Official channels include a "Standard Channel" and an "Experimental Channel." For production environments, it is recommended to start with the Standard Channel, which contains stable, production-ready core resources such as `GatewayClass`, `Gateway`, `HTTPRoute`, and `GRPCRoute`. Run the following command to install the standard CRDs (using v1.4.0 as an example; you can check the official Releases page for the latest stable version):
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.4.0/standard-install.yaml
Once the installation is complete, verify that the core CRDs are ready by running:
kubectl get crd gateways.gateway.networking.k8s.io httproutes.gateway.networking.k8s.io
If both CRDs appear in the output, the Gateway API resource definitions have been successfully registered in your cluster.
Step 2: Select and Install a Controller
The controller is the core component that translates Gateway API declarative configurations into actual traffic handling. Popular choices as of 2026 include Envoy Gateway, NGINX Gateway Fabric, and Cilium. Each has its own focus; the best choice depends on your cluster's current state and your team's familiarity with these tools.
Envoy Gateway is a reference implementation of the Gateway API that uses Envoy Proxy as its data plane. It features an active community and comprehensive documentation, making it an ideal choice if you want a standardized Gateway API experience without being locked into vendor-specific CRDs. Install it via Helm:
helm install eg oci://docker.io/envoyproxy/gateway-helm \
--version v1.6.3 \
-n envoy-gateway-system \
--create-namespace
Wait for the controller to be ready:
kubectl wait --namespace envoy-gateway-system \
--for=condition=ready pod \
--selector=control-plane=envoy-gateway \
--timeout=90s
NGINX Gateway Fabric is well-suited for teams already using NGINX as an ingress solution. It utilizes NGINX as its data plane, allowing for a smooth migration of existing NGINX configuration models and tuning expertise. It can also be installed via Helm:
helm install ngf oci://ghcr.io/nginx/charts/nginx-gateway-fabric \
--create-namespace -n nginx-gateway
Cilium is a suitable choice for clusters that already use Cilium as their CNI (Container Network Interface). Cilium’s Gateway API support is built directly into its own data plane, eliminating the need to deploy separate proxy components and resulting in a more streamlined architecture. However, you must ensure that `kubeProxyReplacement=true` and `l7Proxy=true` (the latter is enabled by default) are configured in Cilium, and that the controller is activated by setting `gatewayAPI.enabled=true` via Helm.
Step 3: Creating GatewayClass and Gateway
Once the controller is ready, the next step is to define "who handles the traffic" and "where to listen for it."
A `GatewayClass` declares which controller implementation should be used. Taking Envoy Gateway as an example, a default `GatewayClass` (named `eg`) is typically included upon installation; you can verify this by running `kubectl get gatewayclass`. If one does not exist, you will need to create it manually:
yaml
apiVersion: gateway.networking.k8s.io/v1
kind: GatewayClass
metadata:
name: eg
spec:
controllerName: gateway.envoyproxy.io/gatewayclass-controller
A `Gateway` defines the ports and protocols to listen on. A minimal HTTP listener configuration looks like this:
yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: my-gateway
namespace: default
spec:
gatewayClassName: eg
listeners:
- name: http
protocol: HTTP
port: 80
Once created, the controller will automatically provision the necessary data plane workloads (such as Envoy Proxy Pods) and their corresponding Services for this Gateway. Use `kubectl get gateway my-gateway` to confirm that the `PROGRAMMED` or `ADDRESS` status indicates that it is ready.
Step 4: Routing Traffic to Backend Services with HTTPRoute
While a `Gateway` serves as the "entry point," an `HTTPRoute` defines the "routing rules." It forwards requests to backend Services based on hostnames and paths. Assuming there is already a Service named `my-app` in the cluster listening on port 80, the following `HTTPRoute` routes all requests destined for `www.example.com` to that Service:
yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: my-route
namespace: default
spec:
parentRefs:
- name: my-gateway
hostnames:
- "www.example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: my-app
port: 80
`parentRefs` binds this route to the Gateway created earlier. `matches` defines the matching criteria, while `backendRefs` points to the Service that actually handles the requests.
Step 5: Verify that traffic is flowing correctly
The most direct way to verify this is by sending a request to the Gateway's address. First, retrieve the address exposed by the Gateway:
kubectl get gateway my-gateway -o jsonpath='{.status.addresses[0].value}'
If the address is an IP, use `curl` with a specified `Host` header to access it:
curl --header "Host: www.example.com" http://<GATEWAY_IP>/
If the address is a hostname (as is the case with some load balancers on cloud platforms), replace `http://<GATEWAY_IP>` with `http://<GATEWAY_HOSTNAME>`.
If the request returns a response from the backend application, it confirms that the entire path—from the Gateway through the `HTTPRoute` to the Service—is correctly configured and functional.
Common Issues and Troubleshooting
The Gateway remains in a `PROGRAMMED: False` state. Check the `Events` and `Conditions` fields by running `kubectl describe gateway <name>`. Common causes include an improperly installed controller, a mismatch between the `controllerName` in the `GatewayClass` and the actual installed controller, or a failure of the controller Pod to start correctly.
After creating an `HTTPRoute`, requests still return a 404 error. Verify that the Gateway name and namespace specified in `parentRefs` are accurate, ensure that the `hostnames` match the request's `Host` header exactly (including any trailing dots), and confirm that the Service referenced in `backendRefs` exists and is in a "Running" state.
Incompatibility between CRD versions and the controller is a common issue. Resource fields can vary between different versions of the Gateway API; therefore, you should always consult the controller's documentation to identify the supported Gateway API version range before installation. For instance, Cilium 1.19 requires CRDs from Gateway API v1.4.1. A version mismatch is a frequent root cause for scenarios where CRDs are installed and the controller is running, yet routes fail to take effect.
Underlying Network: Gateway API traffic ultimately relies on a stable network.
While the Gateway API addresses traffic orchestration within a Kubernetes cluster, the cluster must still serve external traffic. If the underlying cloud server's network experiences significant packet loss during evening peak hours, external users will encounter timeouts and retries—even if your Gateway and `HTTPRoute` configurations are flawless.
Jtti’s cloud server solutions provide a stable network foundation for exposing Kubernetes clusters. With nodes in Hong Kong and the U.S. connected via premium CN2 GIA lines—optimized for direct access across major carriers—packet loss remains consistently below 0.5% during peak hours. This stability ensures that long-lived connections between the Gateway data plane (e.g., Envoy Proxy) and external clients are not frequently interrupted by jitter on cross-border links, allowing your `HTTPRoute` rules to deliver a seamless user experience. Every instance comes with dedicated bandwidth, preventing network throughput from being throttled by "noisy neighbors" when multiple Gateway instances are running in parallel. Enterprise-grade NVMe SSDs ensure high-performance I/O for tasks like pulling container images and writing logs, preventing disk bottlenecks from delaying the synchronization of Gateway controller configurations or the propagation of routing tables. Furthermore, a recurring lifetime discount policy ensures that the long-term costs of operating your Kubernetes infrastructure remain entirely predictable.
Installing the Gateway API is straightforward: install the CRDs, select a controller, create a Gateway, and configure your `HTTPRoute` resources. What truly determines whether it can run stably in a production environment is the version compatibility between the controller and the CRDs, the precise binding of routing rules, and the ability of the underlying network to reliably deliver traffic—processed by the Gateway—to the end users. Once these four steps are complete, followed by an end-to-end verification using `curl`, you will have a traffic entry point that is more modern and portable than Ingress.
EN
CN