Home / Kubernetes

GKE Gateway API: Replace Ingress for Multi-Service Routing | 2026

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.

ConceptExplanationWhen to use
GatewayClassCluster-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.
GatewayNamespace-scoped resource provisioning the actual Google Cloud Load Balancer listener (port, protocol, TLS certificate).Managed by SRE or platform team per cluster or namespace.
HTTPRouteApplication-level routing rule binding to a Gateway, matching paths, headers, or methods, and forwarding to backend Services.Managed by individual development teams per microservice.
GCPBackendPolicyGKE-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).

FeaturethisServicealtAaltB
Role SeparationGateway API: GatewayClass / Gateway / HTTPRoute (3 roles)Ingress: Single resource (admin + app mixed)Service LoadBalancer: No L7 routing
Cross-Namespace RoutingSupported natively via parentRefNot supportedNot supported
Traffic WeightingHTTPRoute backendRefs weight fieldOnly via NGINX annotationsNot supported
gRPC RoutingGRPCRoute (native support)Via annotations (limited)Not supported
PortabilityStandard 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

Featuremetriccost1kcost10kcost100kcost1m
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

References

Browse all tutorials