# How to Use Gateway API to Route Traffic in Kubernetes Clusters DigitalOcean Kubernetes (DOKS) is a Kubernetes service with a fully managed control plane, high availability, and autoscaling. DOKS integrates with standard Kubernetes toolchains and DigitalOcean’s load balancers, volumes, CPU and GPU Droplets, API, and CLI. [Gateway API](https://gateway-api.sigs.k8s.io/) is a Kubernetes-native way to manage ingress traffic using standardized routing resources. It serves as an alternative to traditional ingress controllers like [nginx](https://docs.digitalocean.com/products/kubernetes/getting-started/operational-readiness/install-nginx-ingress-controller/index.html.md) and supports advanced routing features like header-based matching and traffic weighting. DigitalOcean Kubernetes (DOKS) provides a managed Gateway API implementation using [Cilium](https://docs.cilium.io/en/stable/network/servicemesh/gateway-api/gateway-api/). The Gateway API is enabled by default on clusters with [VPC-native networking](https://docs.digitalocean.com/products/kubernetes/details/features/index.html.md#vpc-native-networking) running Kubernetes version 1.33 or later. When you create a Gateway, DOKS automatically provisions a DigitalOcean Network Load Balancer to handle incoming traffic. Alternatively, you can provision an [HTTP or internal load balancer](#use-http-or-internal-load-balancers). **Note**: DOKS also supports third-party Gateway API implementations. To use a different controller, create a custom GatewayClass with your controller’s name and reference it in your Gateway manifest. See the [Gateway API implementations list](https://gateway-api.sigs.k8s.io/implementations/) for available options. ## Preserve Third-Party Gateway CRDs DOKS installs and manages Gateway Custom Resource Definitions (CRDs) for Gateway, GatewayClass, HTTPRoute, TLSRoute, GRPCRoute, and ReferenceGrant by default. However, if you have Gateway CRDs from a third-party controller, then DOKS preserves those CRDs if one of the following conditions are met: - **Manual opt-out**: Gateway CRDs include the `doks.digitalocean.com/install-policy: "external"` annotation. To add the annotation, run the following command for each CRD, replacing `` with `gateways`, `gatewayclasses`, `httproutes`, `tlsroutes`, `grpcroutes`, and `referencegrants`: ```shell kubectl annotate crd .gateway.networking.k8s.io doks.digitalocean.com/install-policy="external" ``` - **Automatic detection**: Gateway CRDs include a `gateway.networking.k8s.io/bundle-version` annotation with a version newer than the version bundled with DOKS. ## Prerequisites To use Gateway API on DOKS, you need: - A DOKS cluster with [VPC-native networking](https://docs.digitalocean.com/products/kubernetes/details/features/index.html.md#vpc-native-networking) running Kubernetes 1.33 or later. To confirm Gateway API is enabled on the cluster, run the following command: ```shell kubectl get gatewayclass cilium ``` The output looks similar to the following: ``` NAME CONTROLLER ACCEPTED AGE cilium io.cilium/gateway-controller True 7d ``` If the `cilium` GatewayClass exists and shows `ACCEPTED: True`, Gateway API is enabled on your cluster. - [`kubectl`](https://kubernetes.io/docs/tasks/tools/) connected to your cluster. See [Connect to a DOKS Cluster](https://docs.digitalocean.com/products/kubernetes/how-to/connect-to-cluster/index.html.md). - A backend service running in your cluster that you want to route traffic to. ## Create a Gateway A Gateway resource defines an entry point for traffic into your cluster. When you create a Gateway, DOKS automatically provisions a DigitalOcean Load Balancer. The following example creates a Gateway that listens for HTTP traffic on port 80. The `gatewayClassName` field must be set to `cilium`, the DOKS-provided GatewayClass: ```yaml apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: example-gateway namespace: default spec: gatewayClassName: cilium listeners: - name: http protocol: HTTP port: 80 ``` For HTTPS traffic, see [Configure TLS Termination](#configure-tls-termination). You can also customize the load balancer type and settings using [annotations](#configure-load-balancer-settings). Apply the manifest: ```shell kubectl apply -f gateway.yaml ``` It typically takes 1-2 minutes for DOKS to provision the load balancer and assign an external IP address. To check the Gateway status, run the following command: ```shell kubectl get gateway example-gateway ``` The output looks similar to the following: ``` NAME CLASS ADDRESS PROGRAMMED AGE example-gateway cilium 203.0.113.10 True 2m ``` The `ADDRESS` column shows the external IP address of the provisioned load balancer. The `PROGRAMMED: True` status indicates that the Gateway is ready to accept traffic. You can also verify that the load balancer is created by checking for the associated Kubernetes service: ```shell kubectl get svc -l io.cilium.gateway/owning-gateway=example-gateway ``` Next, define the HTTP traffic routing rule as described in the following section. ## Define HTTP Traffic Routing An HTTPRoute resource defines how HTTP traffic reaching the Gateway routes to your backend services. HTTPRoutes reference a parent Gateway and specify rules for matching and routing requests, and advanced routing rules such as path-based or header-based routing. The following example creates an HTTPRoute that routes all traffic from the Gateway to a backend service named `my-service` on port 80: ```yaml apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: example-route namespace: default spec: parentRefs: - name: example-gateway rules: - backendRefs: - name: my-service port: 80 ``` Apply the manifest: ```shell kubectl apply -f httproute.yaml ``` ### Route Traffic Based on Path or Headers You can configure more advanced routing rules to direct traffic based on request properties. The following examples show path-based and header-based routing: ## Path-based routing The following example routes requests to `/api` to one service and requests to `/web` to another: ```yaml apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: path-based-route namespace: default spec: parentRefs: - name: example-gateway rules: - matches: - path: type: PathPrefix value: /api backendRefs: - name: api-service port: 8080 - matches: - path: type: PathPrefix value: /web backendRefs: - name: web-service port: 80 ``` ## Header-based routing The following example routes requests with a specific header to a different service: ```yaml apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: header-based-route namespace: default spec: parentRefs: - name: example-gateway rules: - matches: - headers: - type: Exact name: X-Version value: v2 backendRefs: - name: api-v2-service port: 8080 ``` For more advanced routing patterns like traffic splitting and request redirects, see the [Gateway API HTTPRoute documentation](https://gateway-api.sigs.k8s.io/api-types/httproute/). Next, configure the TLS termination, as described in the following section. ## Configure TLS Termination You can terminate TLS at either the DigitalOcean Load Balancer or at the Gateway (Cilium) level. Choose the approach that best fits your needs: - **Load Balancer termination**: Uses DigitalOcean-managed certificates and offloads TLS processing from your cluster. - **Gateway termination**: Keeps TLS certificates within your cluster as Kubernetes Secrets. If you need to terminate TLS at your backend pods, instead of the Gateway, you can use `tls.mode: Passthrough` in the Gateway manifest. See the [Gateway API TLS documentation](https://gateway-api.sigs.k8s.io/guides/tls/) for details. ## At the Load Balancer To terminate TLS at the load balancer, pass certificate annotations through the `.spec.infrastructure.annotations` field on the Gateway: ```yaml apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: https-gateway namespace: default spec: gatewayClassName: cilium infrastructure: annotations: service.beta.kubernetes.io/do-loadbalancer-certificate-id: "your-certificate-id" service.beta.kubernetes.io/do-loadbalancer-protocol: "https" listeners: - name: https protocol: HTTPS port: 443 tls: mode: Terminate certificateRefs: - name: example-cert ``` To use a [Let’s Encrypt certificate](https://docs.digitalocean.com/products/kubernetes/how-to/configure-load-balancers/index.html.md#ssl-certificates) by name instead of ID, use the `do-loadbalancer-certificate-name` annotation: ```yaml infrastructure: annotations: service.beta.kubernetes.io/do-loadbalancer-certificate-name: "your-certificate-name" service.beta.kubernetes.io/do-loadbalancer-protocol: "https" ``` For more information about SSL certificates on load balancers, see [SSL Certificates](https://docs.digitalocean.com/products/kubernetes/how-to/configure-load-balancers/index.html.md#ssl-certificates). ## At the Gateway To terminate TLS at the Gateway, configure the load balancer for TLS passthrough and specify the certificate in the Gateway’s TLS configuration: ```yaml apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: gateway-tls namespace: default spec: gatewayClassName: cilium infrastructure: annotations: service.beta.kubernetes.io/do-loadbalancer-tls-passthrough: "true" listeners: - name: https protocol: HTTPS port: 443 tls: mode: Terminate certificateRefs: - name: my-tls-secret kind: Secret ``` The TLS certificate must be stored in a Kubernetes Secret in the same namespace as the Gateway. To do this, add the following to your `Secret` config file: ```yaml apiVersion: v1 kind: Secret metadata: name: my-tls-secret namespace: default type: kubernetes.io/tls data: tls.crt: tls.key: ``` ## Configure Load Balancer Settings You can configure additional load balancer settings by adding annotations to the Gateway’s `.spec.infrastructure.annotations` field. These annotations are the same as the ones you can configure for [Load Balancer service for your cluster](https://docs.digitalocean.com/products/kubernetes/how-to/configure-load-balancers/index.html.md). The following example configures a load balancer with a custom name and health check settings: ```yaml apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: custom-lb-gateway namespace: default spec: gatewayClassName: cilium infrastructure: annotations: service.beta.kubernetes.io/do-loadbalancer-name: "my-gateway-lb" service.beta.kubernetes.io/do-loadbalancer-healthcheck-path: "/health" service.beta.kubernetes.io/do-loadbalancer-healthcheck-protocol: "http" listeners: - name: http protocol: HTTP port: 80 ``` **Note**: The Gateway API specification limits the `.spec.infrastructure.annotations` field to 8 annotations. If you need more annotations, [use a Load Balancer service](https://docs.digitalocean.com/products/kubernetes/how-to/add-load-balancers/index.html.md) directly with an ingress controller instead of the Gateway API to manage ingress traffic. ## Use HTTP or Internal Load Balancers By default, Gateway API provisions network load balancers, which route TCP and UDP traffic at the network layer. You can provision HTTP load balancers or internal load balancers instead by setting the appropriate annotations in the Gateway manifest. ## HTTP Load Balancer HTTP load balancers operate at the application layer and can perform HTTP-specific functions. To use an HTTP load balancer: ```yaml apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: http-lb-gateway namespace: default spec: gatewayClassName: cilium infrastructure: annotations: service.beta.kubernetes.io/do-loadbalancer-type: "REGIONAL" listeners: - name: http protocol: HTTP port: 80 ``` ## Internal Load Balancer Internal load balancers are only accessible from within your VPC network. To use an internal load balancer: ```yaml apiVersion: gateway.networking.k8s.io/v1 kind: Gateway metadata: name: internal-gateway namespace: default spec: gatewayClassName: cilium infrastructure: annotations: service.beta.kubernetes.io/do-loadbalancer-network: "INTERNAL" listeners: - name: http protocol: HTTP port: 80 ``` For more information about load balancer types, see [Load Balancer Type](https://docs.digitalocean.com/products/kubernetes/how-to/configure-load-balancers/index.html.md#load-balancer-type). ## View Gateway Status To view the status of your Gateways: ```shell kubectl get gateways ``` The output looks similar to the following: ``` NAME CLASS ADDRESS PROGRAMMED AGE example-gateway cilium 203.0.113.10 True 5m ``` The `True` status of the `PROGRAMMED:` column indicates the Gateway is ready to route traffic. The `ADDRESS` column shows the load balancer’s external IP address. You can also use `kubectl describe gateway ` to view detailed information, or `kubectl get httproutes` to list routes. ## Additional Resources For more information about Gateway API, see: [Gateway API Documentation](https://gateway-api.sigs.k8s.io/): Official Kubernetes Gateway API specification and guides. [Cilium Gateway API Documentation](https://docs.cilium.io/en/stable/network/servicemesh/gateway-api/gateway-api/): Cilium’s implementation of the Gateway API. [HTTPS Traffic Routing in Kubernetes using Gateway API and Cilium](https://www.digitalocean.com/community/tutorials/https-traffic-routing-gateway-api-cilium): Tutorial on setting up HTTPS routing with Gateway API. [Kubernetes Gateway API Tutorial](https://www.digitalocean.com/community/tutorials/kubernetes-gateway-api-tutorial-cilium-ingress-alternative): Tutorial on replacing Ingress with Cilium Gateway for HTTP traffic.