
GKE Gateway API: Replace Ingress for Multi-Service Routing | 2026
Kubernetes Ingress is a simple but limited L7 routing resource that conflates infrastructure provisioning and application routing into a single annotation-heavy YAML manifest. Gateway API is its role-oriented successor, separating infrastructure concerns (GatewayClass, Gateway) from application routing (HTTPRoute). On GKE, Gateway resources provision Google Cloud Load Balancers automatically. This guide demonstrates how to deploy both external and internal GKE Gateways, configure HTTPRoute path and header-based routing rules, apply BackendPolicy timeouts, and migrate from Ingress.
By Mateusz Chmielewski · Aug 29, 2026 · 14 min read
What is GKE Gateway API?
GKE Gateway API is Google's implementation of the Kubernetes Gateway API specification — a next-generation replacement for Ingress. It maps declarative Kubernetes resources (GatewayClass, Gateway, HTTPRoute) to Google Cloud Load Balancer infrastructure components automatically.
Kubernetes Ingress is like giving every developer a shared whiteboard in the lobby to write routing rules — it works, but everyone's notes compete for space and the board gets messy fast. Gateway API assigns separate roles: the platform team owns the lobby whiteboard template (GatewayClass), the SRE team configures the board size and access (Gateway), and developers only write their own service directions (HTTPRoute) on their personal sticky note section.
| Concept | Explanation | When to use |
|---|---|---|
| GatewayClass | Cluster-scoped resource specifying which GCP Load Balancer type to provision (e.g. `gke-l7-global-external-managed`, `gke-l7-rilb`). | Managed by platform/cluster-admin team. |
| Gateway | Namespace-scoped resource provisioning the actual Google Cloud Load Balancer listener (port, protocol, TLS certificate). | Managed by SRE or platform team per cluster or namespace. |
| HTTPRoute | Application-level routing rule binding to a Gateway, matching paths, headers, or methods, and forwarding to backend Services. | Managed by individual development teams per microservice. |
| GCPBackendPolicy | GKE-specific policy resource attaching GCP Load Balancer backend settings (timeout, health check, IAP) to a Service. | Apply for per-service timeout and health check tuning. |
Gateway API vs Ingress: Why Upgrade?
Kubernetes Ingress resources rely heavily on vendor-specific annotations to express advanced routing features (SSL termination, timeouts, redirects). These annotations differ between ingress controllers (NGINX, Kong, GKE), making manifests non-portable. All routing rules share one resource, creating team collaboration conflicts.
Gateway API expresses all routing rules in standard Kubernetes CRDs without controller-specific annotations. Each development team owns their HTTPRoute resources independently, without touching shared infrastructure Gateway resources. Combine with [Cloud Service Mesh on GKE](/tutorial/cloud-service-mesh-gke-mtls-traffic-splitting-authorization-policies) for pod mTLS or front with an [HA External Load Balancer](/tutorial/ha-external-https-load-balancer-gcp).
| Feature | thisService | altA | altB |
|---|---|---|---|
| Role Separation | Gateway API: GatewayClass / Gateway / HTTPRoute (3 roles) | Ingress: Single resource (admin + app mixed) | Service LoadBalancer: No L7 routing |
| Cross-Namespace Routing | Supported natively via parentRef | Not supported | Not supported |
| Traffic Weighting | HTTPRoute backendRefs weight field | Only via NGINX annotations | Not supported |
| gRPC Routing | GRPCRoute (native support) | Via annotations (limited) | Not supported |
| Portability | Standard CRDs (vendor-agnostic) | Annotation-based (vendor-specific) | N/A |
Prerequisites
- GKE cluster v1.24+ with Gateway API enabled (`--gateway-api=standard`)
- Terraform CLI v1.6+
- kubectl configured and authenticated
Step-by-Step Guide
Step 1: Enable Gateway API on GKE Cluster
Enable the Gateway API feature on an existing GKE Standard cluster via Terraform. Gateway API CRDs (GatewayClass, Gateway, HTTPRoute) and GKE Gateway controller must be enabled explicitly on the cluster.
# gke_cluster.tf — Enable Gateway API on GKE cluster
resource "google_container_cluster" "prod" {
name = "prod-gke-cluster"
location = "europe-west1"
project = var.project_id
gateway_api_config {
channel = "CHANNEL_STANDARD" # Enables GatewayClass resources
}
# ... other cluster config
}
Step 2: Deploy External Gateway for Internet Traffic
Create a Gateway resource mapping to the Global External Application Load Balancer GatewayClass. The Gateway resource provisions the underlying Google Cloud Load Balancer listener. A TLS certificate is attached via `certificateRefs` pointing to a Kubernetes Secret.
# external_gateway.yaml — Global External Application Load Balancer
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: external-gateway
namespace: infra
annotations:
networking.gke.io/certmap: ssl-cert-map # Optional: Certificate Manager map
spec:
gatewayClassName: gke-l7-global-external-managed
listeners:
- name: https
port: 443
protocol: HTTPS
tls:
mode: Terminate
certificateRefs:
- kind: Secret
name: tls-cert-secret
namespace: infra
- name: http-redirect
port: 80
protocol: HTTP
Step 3: Configure HTTPRoute for Path-Based Multi-Service Routing
Write HTTPRoute rules to route `/api/*` to the API service and `/static/*` to the frontend service from a shared gateway. HTTPRoute allows multiple teams to independently manage their service routing rules without modifying shared Ingress resources.
# http_route.yaml — Path-based routing from shared external Gateway
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: api-httproute
namespace: production
spec:
parentRefs:
- name: external-gateway
namespace: infra
hostnames:
- "api.company.com"
rules:
# Route /api/v1/* to API service
- matches:
- path:
type: PathPrefix
value: /api/v1
backendRefs:
- name: api-service
port: 8080
# Route /api/v2/* to new v2 API (canary 10%)
- matches:
- path:
type: PathPrefix
value: /api/v2
backendRefs:
- name: api-service-v2
port: 8080
weight: 90
- name: api-service-v3-canary
port: 8080
weight: 10
# Header-based routing for internal beta users
- matches:
- headers:
- name: X-Beta-User
value: "true"
backendRefs:
- name: api-service-beta
port: 8080
Step 4: Apply GCPBackendPolicy for Custom Health Checks and Timeouts
Attach GCPBackendPolicy to a Service to configure GCP Load Balancer backend settings like health check path and timeout. Default GCP Load Balancer health checks use `/` path with 30s timeout. Custom health check endpoints (`/healthz`) and per-service timeout tuning prevent false-positive health check failures.
# backend_policy.yaml — Custom backend health check and timeout
apiVersion: networking.gke.io/v1
kind: GCPBackendPolicy
metadata:
name: api-service-backend-policy
namespace: production
spec:
default:
timeoutSec: 30
connectionDraining:
drainingTimeoutSec: 60
healthCheck:
checkIntervalSec: 10
timeoutSec: 5
healthyThreshold: 2
unhealthyThreshold: 3
requestPath: /healthz
port: 8080
targetRef:
group: ""
kind: Service
name: api-service
Step 5: Deploy Internal Gateway for Private Microservice Routing
Create an Internal Gateway mapping to `gke-l7-rilb` GatewayClass to route private VPC-internal traffic. Internal Gateways provision Internal Application Load Balancers accessible only from VPC-internal resources — no public internet exposure.
# internal_gateway.yaml — Internal Application Load Balancer
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: internal-gateway
namespace: infra
annotations:
networking.gke.io/internal-load-balancer-allow-global-access: "true"
spec:
gatewayClassName: gke-l7-rilb
listeners:
- name: http
port: 80
protocol: HTTP
allowedRoutes:
namespaces:
from: All
---
# Internal HTTPRoute for backend services
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: internal-api-route
namespace: production
spec:
parentRefs:
- name: internal-gateway
namespace: infra
rules:
- backendRefs:
- name: internal-api-service
port: 8080
Verification & Health Check
Best Practices
- Use allowedRoutes.namespaces to Restrict Route Attachment
- Match Ingress Migration Rules Exactly
Common Mistakes
- {"errorCode":"HTTPROUTE_NOT_ACCEPTED","symptoms":"kubectl describe httproute shows Reason: NotAllowedByParent.","rootCause":"The Gateway listener's allowedRoutes configuration does not permit attachment from the HTTPRoute's namespace.","fixCommand":"kubectl edit gateway external-gateway -n infra","code":"# Add allowedRoutes to the Gateway listener\nlisteners:\n - name: https\n port: 443\n allowedRoutes:\n namespaces:\n from: All # Or use Selector for specific namespaces\n","language":"yaml","filename":"fix_gateway_routes.yaml","prevention":"Define allowedRoutes explicitly on every Gateway listener during initial setup."}
Cost Analysis
| Feature | metric | cost1k | cost10k | cost100k | cost1m |
|---|---|---|---|---|---|
| External Gateway (Global LB) Forwarding Rule ($0.05/hr) | $36.00/mo | $36.00/mo | $36.00/mo | $432.00/yr | |
| Internal Gateway (RILB) Forwarding Rule ($0.025/hr) | $18.00/mo | $18.00/mo | $18.00/mo | $216.00/yr | |
| LB Data Processing (100M reqs, avg 10KB) | $8.00/mo | $8.00/mo | $8.00/mo | $96.00/yr | |
| Total Gateway API Monthly Cost | ~$62.00/mo | ~$62.00/mo | ~$62.00/mo | ~$744.00/yr |