GCP ACE: GKE Networking — Ingress and NetworkPolicy
Earlier in this series, exposing a workload meant a LoadBalancer Service — one external IP, one Service, no routing logic. That’s fine for a single app. Real deployments usually need to route different paths or hostnames to different Services behind one IP, and to restrict which Pods can talk to which. That’s Ingress and NetworkPolicy.
Ingress — one IP, many Services
GKE Ingress is GKE’s built-in, managed Ingress controller. When you create an Ingress object, the controller provisions an actual HTTP(S) Application Load Balancer and configures it to route traffic to your Services based on the rules you wrote — no manual load balancer setup.
Two Ingress types in GKE:
| Type | What it creates |
|---|---|
| External | A classic Application Load Balancer — internet-facing and deployed globally on Google’s edge network |
| Internal | An internal Application Load Balancer, reachable only from within your VPC, backed by NEGs |
Note the word classic: external GKE Ingress doesn’t create the newer global external Application Load Balancer (EXTERNAL_MANAGED) — that’s one of the things Gateway API gives you. And because the internal variant is Envoy-based, the region needs a proxy-only subnet before an internal Ingress can be created (the same requirement covered in the load balancing article).
Ingress vs. a LoadBalancer Service: a LoadBalancer Service exposes exactly one Service on one external IP with no routing rules. An Ingress sits a layer above Services — one external IP, with a URL map that routes /api to one Service and / to another, by path or by host.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
spec:
rules:
- http:
paths:
- path: /*
pathType: ImplementationSpecific
backend:
service:
name: my-products
port:
number: 60000
- path: /discounted
pathType: ImplementationSpecific
backend:
service:
name: my-discounted-products
port:
number: 80
This routes everything to my-products:60000, except /discounted, which goes to my-discounted-products:80. Under the hood, the controller builds a URL map with one path rule per entry, each pointing at a backend service whose NEGs hold the actual Pod IPs.
One detail worth flagging for current and future exam versions: GKE Ingress is in maintenance mode. Google now recommends the Gateway API for new HTTP(S) exposure — it’s the only option of the two that supports certificates managed by Certificate Manager. Ingress still appears on exam questions as the classic answer, but don’t be surprised to see Gateway API show up as the “more modern” correct answer on newer question sets.
NetworkPolicy — Pod-level firewalling
By default, every Pod in a cluster can talk to every other Pod, with no restriction. A NetworkPolicy adds firewall rules at the Pod level — useful for namespace-level tenant isolation or basic defense in depth (so a compromised Pod in one namespace can’t freely reach a database Pod in another).
Enabling enforcement on GKE depends on your dataplane:
- GKE Dataplane V2 (default for Autopilot, and recommended for Standard): network policy enforcement works out of the box — nothing to enable.
- Standard clusters still on Calico: enable both the add-on and enforcement, in order:
gcloud container clusters update CLUSTER_NAME --update-addons=NetworkPolicy=ENABLED
gcloud container clusters update CLUSTER_NAME --enable-network-policy
Enabling only the add-on enforces nothing by itself — both commands are required. Turning on enforcement also recreates the cluster’s nodes, which can disrupt running workloads, so plan it like a maintenance operation.
Example policy restricting ingress traffic by source:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-non-pod-traffic
spec:
podSelector: {} # applies to every Pod in the namespace
ingress:
- from:
- ipBlock:
cidr: '0.0.0.0/0'
except: ['10.95.0.0/17'] # the cluster's Pod IP range
Google’s own guidance: prefer podSelector and namespaceSelector over ipBlock for selecting sources, because Pod IP ranges are ephemeral and will drift out from under a hardcoded CIDR. ipBlock rules also behave differently depending on whether the cluster runs Dataplane V2 or Calico — another reason to default to label-based selectors.
Exam Takeaways
- GKE Ingress provisions an actual HTTP(S) load balancer and routes by path/host to multiple Services — a
LoadBalancerService exposes exactly one Service, with no routing. - GKE Ingress has External (creates a classic Application Load Balancer) and Internal (VPC-only, NEG-backed, needs a proxy-only subnet) variants.
spec.podSelectorpicks which Pods a NetworkPolicy applies to;{}means every Pod in the namespace.- GKE Ingress is in maintenance mode; Google recommends Gateway API for new work, and only Gateway API supports Certificate Manager–managed certificates.
- By default, all Pods in a cluster can reach each other — NetworkPolicy is what restricts that.
- GKE Dataplane V2 (default on Autopilot) enforces NetworkPolicy natively; Standard clusters on Calico need both
--update-addons=NetworkPolicy=ENABLEDand--enable-network-policy. - Enabling NetworkPolicy enforcement recreates cluster nodes — expect disruption, not a zero-downtime toggle.
- Prefer
podSelector/namespaceSelectoroveripBlockin a NetworkPolicy — Pod IPs are ephemeral.