GCP ACE: Introduction to Cloud Service Mesh on GKE
Everything networking-related so far in this series — Services, Ingress, multi-cluster Services, the multi-cluster Gateway — routes traffic based on where a Pod is and what port it listens on. None of it looks inside the traffic, encrypts it automatically, or lets you make fine-grained routing decisions based on request content. That’s what a service mesh adds, and Cloud Service Mesh is Google’s managed implementation, built on Istio.
What a service mesh actually adds
A Kubernetes Service gives you a stable address and basic load balancing. A service mesh sits a layer underneath that, injecting a lightweight network proxy (a sidecar) next to every workload container. Every bit of traffic in or out of that Pod passes through its sidecar first — which means the mesh can, without any application code changes:
- Encrypt service-to-service traffic automatically (mutual TLS — covered in depth in the next article).
- Route traffic based on request content — headers, paths, weights between versions — not just destination.
- Retry failed requests, time out slow ones, and inject circuit breakers, all at the infrastructure layer.
- Give you uniform telemetry (latency, error rates, traffic volume) for every service, without instrumenting each application individually.
Provisioning: managed vs. in-cluster
Cloud Service Mesh offers a managed control plane: Google runs the control plane itself and handles its reliability, upgrades, scaling, and security. You still configure the mesh with the familiar Istio APIs, but on current fleets nothing istiod-shaped runs in your cluster — the control plane is Google’s globally managed TRAFFIC_DIRECTOR implementation (more on that below). This is the default recommendation; you no longer run and patch your own control plane.
Enabling it at the fleet level, once:
gcloud container fleet mesh enable --project FLEET_PROJECT_ID
Turning on automatic management for a specific registered cluster:
gcloud container fleet mesh update \
--management automatic \
--memberships MEMBERSHIP_NAME \
--project FLEET_PROJECT_ID \
--location MEMBERSHIP_LOCATION
Fleet-default enablement — so every new cluster registered afterward gets the managed mesh automatically, without a per-cluster step:
# mesh.yaml
management: automatic
gcloud container fleet mesh enable --project FLEET_PROJECT_ID \
--fleet-default-member-config mesh.yaml
This only applies going forward — clusters already registered before you set the fleet default have to be synced separately.
Verifying:
gcloud container fleet mesh describe --project FLEET_PROJECT_ID
The control plane state should read ACTIVE, and the implementation field shows ISTIOD or TRAFFIC_DIRECTOR. This isn’t a minor detail to skim past: Google formally announced the deprecation of managed ISTIOD (and the in-cluster control plane) on September 28, 2026 — support for both ends on March 1, 2028. Managed fleets still on ISTIOD must modernize to TRAFFIC_DIRECTOR before then, either customer-triggered or Google-driven. In-cluster installations can’t be modernized in place; they have to migrate to the managed control plane on a new cluster. TRAFFIC_DIRECTOR has been the default for every new fleet since July 1, 2024 (and provisioning ISTIOD for new fleets ended September 8, 2024), so if you see ISTIOD in the output today, it almost always means a fleet that’s been running since before that cutover and hasn’t modernized yet.
How a Pod actually joins the mesh: sidecar injection
Enabling Cloud Service Mesh on a cluster doesn’t automatically put every Pod into the mesh — injection is opt-in, per namespace:
kubectl label namespace NAMESPACE istio.io/rev- istio-injection=enabled --overwrite
The istio.io/rev- clears any revision-specific label first, so the plain istio-injection=enabled label takes effect. Existing workloads in a newly-labeled namespace don’t automatically get a sidecar — they need to be restarted (a rolling restart of the Deployment, for instance) before the injection webhook actually adds the proxy container to them.
How a request actually flows through the mesh
For a Pod with an injected sidecar, every request — inbound and outbound — is transparently intercepted by that Pod’s own sidecar proxy before it reaches (or leaves) the application container:
- Service A’s sidecar intercepts an outbound call meant for Service B.
- It consults the mesh’s traffic rules (covered in the next article — VirtualServices, DestinationRules) to decide exactly where that request should actually go.
- It opens a connection to Service B’s sidecar — encrypted with mutual TLS if that’s configured — not directly to Service B’s application container.
- Service B’s sidecar receives it, decrypts it, applies any authorization checks, and only then hands it to Service B’s actual application code.
The application containers on both ends never see any of this — they just make or receive plain HTTP/gRPC calls as if the mesh weren’t there. That transparency is the entire design point: existing app code doesn’t need to change to get mTLS, retries, or traffic-shaping.
Dashboards and support
Cloud Service Mesh integrates with Google Cloud’s observability stack rather than requiring a separate monitoring setup: service-level metrics (latency, request volume, error rate — the so-called “golden signals”) for every meshed service show up in the Cloud Console, correlated by service, not just by Pod or node. This is also where you’d check mesh health and configuration state day to day, alongside the gcloud container fleet mesh describe command above for a quick CLI check.
Exam Takeaways
- A service mesh works by injecting a sidecar proxy into every Pod — all traffic passes through the sidecar, not directly to/from the application container.
- Cloud Service Mesh’s managed control plane means Google runs and upgrades the control plane for you —
TRAFFIC_DIRECTORis the current implementation and has been the default for new fleets since July 1, 2024; managedISTIODand the in-cluster control plane were deprecated September 28, 2026, with support ending March 1, 2028. - Enabling the mesh is fleet-level (
gcloud container fleet mesh enable), then per-cluster management is turned on withgcloud container fleet mesh update --management automatic. - A fleet-default mesh config (
--fleet-default-member-config) only affects clusters registered after it’s set — existing clusters need manual sync. - Sidecar injection is opt-in per namespace via the
istio-injection=enabledlabel — and existing Pods in that namespace need a restart to actually receive a sidecar. - Application containers are unaware of the mesh — all mTLS, retries, and routing decisions happen in the sidecar, transparently.
gcloud container fleet mesh describeis the quick CLI health check; the Cloud Console surfaces per-service golden-signal metrics without extra instrumentation.