Production GKE Platform — From Zero to Production›07 · Load balancing: Services, Ingress & Gateway API

Lesson 07 of 18 · Part 2 — Build the platform

Load balancing: Services, Ingress & Gateway API

Expose workloads on GKE with Google Cloud load balancers: passthrough L4 for Services, container-native L7 through Ingress or the Gateway API, internal versus external, managed certificates, health checks, Cloud Armor, and how to choose.

Practitioner → Advanced
Key wordsGKE load balancingService type LoadBalancerpassthrough Network Load Balancerinternal load balancercontainer-native load balancingNEGGKE IngressGateway APIGKE Gateway controllerGatewayClassHTTPRouteCertificate ManagerGoogle-managed certificatesCloud Armorhealth checks

The options

You create You get Layer Use for
Service type LoadBalancer Passthrough Network Load Balancer (external), or internal with an annotation L4 TCP/UDP Non-HTTP protocols, client IP preserved, simple TCP services
Ingress (class gce / gce-internal) External or internal Application Load Balancer L7 HTTP(S) Existing setups, simple host/path routing
Gateway + HTTPRoute (GKE Gateway controller) Global or regional, external or internal Application Load Balancer L7 New platforms: shared gateways, team-owned routes, traffic splitting, multi-cluster

No controller to install: GKE runs the load-balancer integration for you.

A load balancer is the receptionist of a big office. An L4 receptionist just sends each visitor to a free desk. An L7 receptionist reads the visitor's letter ("billing question", "new order") and sends them to the right department. With container-native load balancing, the receptionist walks visitors straight to the person's desk instead of to the floor's door.

L4: Services

apiVersion: v1
kind: Service
metadata:
  name: ledger
  namespace: payments
  annotations:
    networking.gke.io/load-balancer-type: "Internal"   # omit for an external load balancer
spec:
  type: LoadBalancer
  selector: { app: ledger }
  ports:
    - port: 443
      targetPort: 8443
  • Internal load balancers get an IP from the subnet's primary range: reachable from the VPC, Shared VPC and hybrid links.
  • externalTrafficPolicy: Local keeps the client IP and avoids a second hop, at the cost of uneven spreading.

Container-native load balancing (NEGs)

For L7, GKE creates network endpoint groups that contain Pod IPs, so the load balancer health-checks and sends traffic to Pods directly. It's the default for Ingress and Gateway in VPC-native clusters. Make sure readiness probes reflect real readiness, and use terminationGracePeriodSeconds plus a short preStop sleep so Pods leave the NEG before they stop serving.

L7: the Gateway API

Enable the Gateway API on the cluster (--gateway-api standard), then choose a GatewayClass:

GatewayClass Load balancer
gke-l7-global-external-managed Global external Application Load Balancer
gke-l7-regional-external-managed Regional external Application Load Balancer
gke-l7-rilb Regional internal Application Load Balancer
gke-l7-global-external-managed-mc and other -mc classes Multi-cluster gateways across a fleet (lesson 14)

The platform team owns the Gateway in an infra namespace; application teams attach routes from their own namespaces:

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: web
  namespace: infra
spec:
  gatewayClassName: gke-l7-global-external-managed
  listeners:
    - name: https
      protocol: HTTPS
      port: 443
      tls:
        mode: Terminate
        options:
          networking.gke.io/cert-manager-certs: shop-example-com   # Certificate Manager certificate
      allowedRoutes:
        namespaces:
          from: Selector
          selector:
            matchLabels: { gateway-access: "true" }
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: shop
  namespace: shop
spec:
  parentRefs:
    - name: web
      namespace: infra
  hostnames: [ "shop.example.com" ]
  rules:
    - matches:
        - path: { type: PathPrefix, value: /api }
      backendRefs:
        - name: shop-api
          port: 8080
          weight: 90
        - name: shop-api-canary
          port: 8080
          weight: 10

Per-backend settings use GKE policy CRDs attached to Services: HealthCheckPolicy (path, port, interval), GCPBackendPolicy (timeouts, connection draining, Cloud Armor policy, IAP), GCPGatewayPolicy (SSL policy on the Gateway).

Ingress (for existing setups)

Ingress with class gce builds an external Application Load Balancer; gce-internal an internal one. Settings live in BackendConfig (health checks, Cloud Armor, timeouts) and FrontendConfig (SSL policy, HTTP→HTTPS redirect) CRDs; certificates come from the ManagedCertificate CRD or pre-shared certificates. It works and is widely deployed; plan new routing on Gateway.

Certificates, TLS and protection

  • Certificate Manager (works with Gateway): Google-managed certificates with DNS authorisation, wildcard support and certificate maps for many hostnames.
  • Google-managed certificates (ManagedCertificate) for Ingress: simple, but the DNS record must already point at the load balancer.
  • SSL policies set the minimum TLS version and cipher profile.
  • Cloud Armor on external Application Load Balancers: WAF rules (preconfigured OWASP rule sets), rate limiting, geo and IP allow/deny, adaptive protection against L7 DDoS.
  • Internal-only apps behind Identity-Aware Proxy (IAP) get Google sign-in in front of them without code changes.

Choosing

  1. HTTP(S) to the internet? Gateway, global external class, Certificate Manager, Cloud Armor.
  2. HTTP(S) for internal clients? Gateway, gke-l7-rilb.
  3. TCP/UDP, or the client IP must reach the Pod? Service LoadBalancer (internal or external).
  4. Several clusters behind one address? Multi-cluster Gateway (lesson 14).

Try it: one Gateway, two teams

  1. Enable the Gateway API on a lab cluster and create namespace infra with a Gateway of class gke-l7-regional-external-managed listening on HTTP port 80 (the regional class needs a proxy-only subnet in the region).
  2. Deploy two apps in namespaces shop and blog (label both namespaces gateway-access=true) with an HTTPRoute each, on different paths.
  3. Wait for kubectl get gateway web -n infra to show an address, then curl both paths.
  4. Add a 90/10 weight split to a canary Deployment and count responses in a loop.
  5. Remove the namespace label from blog and watch its route lose acceptance in kubectl describe httproute.

Going deeper: operating load balancers

  • Load balancers take minutes to create; changes go through the controller, so read the events and status of the Gateway or Ingress first when something doesn't work.
  • Regional internal and regional external Application Load Balancers need a proxy-only subnet in the region; plan its range with the rest of the IP plan.
  • Keep health checks aligned with readiness probes, and allow the Google health-check source ranges in firewall rules and network policies.
  • Count your forwarding rules and backend services against project quotas when many teams create load balancers.

Recap

  • Service LoadBalancer gives L4 passthrough (external or internal); Ingress and Gateway give L7 Application Load Balancers.
  • Container-native load balancing (NEGs) sends traffic straight to Pods; readiness and graceful shutdown matter.
  • The Gateway API separates platform-owned Gateways from team-owned Routes and supports weights and multi-cluster.
  • Use Certificate Manager, SSL policies, Cloud Armor and IAP at the edge.

This site is a public version of my personal engineering knowledge hub. It intentionally excludes confidential company information and internal operational details.