GKE Networking Explained: Pod IPs, VPC-Native Clusters, Services, and NetworkPolicy

Every pod in a GKE cluster gets its own real IP address inside your Google Cloud VPC. That one architectural decision is what makes everything else work: pods on different nodes can communicate directly, Services give stable access points in front of constantly changing pod IPs, and NetworkPolicy lets you precisely control which workloads can reach each other. This page explains how it all fits together, from IP allocation and DNS to traffic routing and security policies.

GKE networking in simple terms

If Kubernetes networking feels confusing at first, it helps to anchor the core ideas before diving into the mechanics.

  • Each pod gets its own IP. Unlike traditional VMs where one host might share an IP across many services, every pod gets a unique routable IP address, even if hundreds of pods run on the same node.
  • Pods can talk to each other across nodes. A pod on node A can reach a pod on node B directly, without anything translating the address in between.
  • Services give stable access in front of changing pods. Pods restart and get new IPs all the time. A Service gives you one consistent address that always routes to healthy pods behind it.
  • DNS helps workloads find each other by name. Instead of hardcoding IPs, your app says “talk to my-api” and CoreDNS resolves that to the right Service IP automatically.
  • NetworkPolicy restricts who can talk to what. Without it, every pod in the cluster can reach every other pod. NetworkPolicy lets you define precise allow/deny rules between workloads.
  • GKE maps all of this onto your Google Cloud VPC. Pod IPs are first-class VPC citizens, visible to firewall rules, Cloud Monitoring, and VPC Flow Logs.

How GKE networking works

Here is the end-to-end flow from cluster creation to a pod receiving a request:

  1. You create a cluster with defined IP ranges. When you run gcloud container clusters create, you specify (or let GKE auto-assign) a node subnet, a pod secondary CIDR, and a service secondary CIDR. These three ranges cannot overlap and cannot be changed later.

  2. Nodes receive IPs from the primary subnet. Each GKE node VM gets a standard primary IP from your node subnet, the same way any Compute Engine VM would.

  3. Nodes reserve a pod IP block from the secondary range. Each node also gets a slice of the pod secondary range as an alias IP range. Every pod scheduled on that node receives an IP from its node’s pod slice.

  4. Services receive stable ClusterIPs from the service range. When you create a Service, Kubernetes assigns it a ClusterIP from the services secondary CIDR. This IP never changes for the life of the Service.

  5. kube-proxy or Dataplane V2 routes traffic to pods. When your app sends traffic to a ClusterIP, the kernel intercepts it and rewrites the destination to one of the healthy pod IPs behind the Service, based on rules programmed by kube-proxy (iptables) or Dataplane V2 (eBPF).

  6. CoreDNS resolves service names. Every pod’s /etc/resolv.conf points to the CoreDNS Service IP. When your code connects to my-api, CoreDNS returns the ClusterIP for the my-api Service in your namespace.

  7. NetworkPolicy optionally restricts traffic paths. If the cluster was created with network policy enforcement enabled, the Calico (or Dataplane V2) dataplane enforces allow/deny rules at layer 3 and 4 before traffic reaches the destination pod.

The Kubernetes networking contract

Kubernetes does not prescribe one specific networking implementation. Instead, it defines a contract that any compliant implementation must satisfy:

  1. Every pod gets its own IP address.
  2. Every pod can communicate directly with every other pod on any node, without network address translation (NAT).
  3. Every node can communicate with every pod, and every pod can communicate with the node it runs on.
  4. The IP address a pod sees for itself is the same IP that other pods use to reach it. No address remapping occurs.

These rules mean the cluster looks like a flat layer-3 network from the application’s perspective. No application code needs to know which node a pod lives on. You address a Service in front of the pods, and the cluster handles routing.

Analogy

Think of each pod as an employee with a direct phone extension. Kubernetes guarantees every extension is unique and anyone in the building can dial it without going through a switchboard that changes the number. Services are like department reception lines: they ring whichever available employee picks up first, and the number stays the same even as staff turn over.

VPC-native clusters and alias IP ranges

GKE implements the Kubernetes networking contract on top of Google Cloud VPCs using alias IP ranges. This is what makes a cluster “VPC-native,” and it has been the default since GKE 1.21.

Each GKE node has two types of IP addresses:

  • A primary IP address drawn from the node subnet (the address the VM itself uses).
  • A secondary alias IP range reserved for the pods scheduled on that node.

When GKE places a pod on a node, it assigns the pod an IP from that node’s alias range. Because the VPC understands alias ranges natively, traffic to a pod IP is routed directly to the right node: no custom routes, no IP masquerade, no NAT.

The practical effects are significant:

  • Pod IPs are first-class VPC citizens. Firewall rules, VPC Flow Logs, and Cloud Monitoring all see real pod IPs, not just node IPs.
  • You can target firewall rules at pod CIDR ranges or individual pod IPs, not just nodes.
  • The pod range is separate from the node range, preventing accidental overlap.
  • Pod IPs are reachable from other VPCs connected by VPC peering without extra configuration.

When creating a cluster, you can specify secondary ranges explicitly or let GKE allocate them automatically:

gcloud container clusters create my-cluster \
  --region=europe-west2 \
  --network=my-vpc \
  --subnetwork=my-subnet \
  --cluster-secondary-range-name=pods \
  --services-secondary-range-name=services \
  --enable-ip-alias
Plan before you create

Pod and service CIDR ranges are permanent. They cannot be changed without recreating the cluster. A /20 pod range gives 4,096 addresses and supports roughly 100–130 nodes. A /24 gives only 256 addresses and will cap your cluster’s growth early. See Subnets in GCP for guidance on secondary range sizing.

VPC-native vs routes-based clusters#

GKE originally used a routes-based model where each node had a VPC route entry pointing to its pod CIDR. This approach had real limitations: Google Cloud VPCs cap the number of routes per network, and routes-based pod IPs were not visible to VPC-level tooling.

VPC-nativeRoutes-based
Pod IP routingAlias IP ranges, native VPCStatic VPC routes per node
Firewall rules on pod IPsYesLimited
VPC Flow Logs for podsYesNo
Route limit scalingNo route per node neededLimited by VPC route quota
Default sinceGKE 1.21Legacy

Routes-based clusters are no longer recommended. If you are creating a new GKE cluster, VPC-native is what you get by default.

Tip

If you are inheriting an older cluster, check whether it is VPC-native by running gcloud container clusters describe CLUSTER_NAME —format=“value(ipAllocationPolicy.useIpAliases)”. A result of true means VPC-native. Routes-based clusters cannot be migrated in place.

Services and how traffic flows

Pods are ephemeral. They restart, reschedule, and scale up and down constantly. Their IP addresses change with them. A Service solves this by providing a stable virtual IP (the ClusterIP) and DNS name that maps to a dynamic set of pod IPs selected by a label selector.

GKE supports the standard Kubernetes Service types:

TypeWhat it does
ClusterIPExposes the Service on a cluster-internal IP only. The default type.
NodePortOpens a static port on every node and forwards traffic to the Service. Rarely used directly in production.
LoadBalancerProvisions a Google Cloud Load Balancer automatically. Use for public-facing Services.
ExternalNameMaps the Service to an external DNS name via a CNAME record.

When traffic is sent to a ClusterIP, the kernel intercepts it before it leaves the source pod. kube-proxy has programmed iptables rules to rewrite the destination to one of the healthy pod IPs behind the Service. The rewrite happens in the kernel, before the packet hits the network.

Choosing a Service type

Use ClusterIP for internal traffic between services. Use LoadBalancer when you need to expose a Service to users or external systems. Avoid NodePort in production — it exposes a high port on every node and is harder to secure. For HTTP/HTTPS routing across multiple services, use an Ingress controller instead.

Dataplane V2 vs kube-proxy#

Enabling Dataplane V2 (--enable-dataplane-v2) replaces kube-proxy entirely with an eBPF-based implementation built on the Cilium project.

kube-proxy (iptables)Dataplane V2 (eBPF)
Traffic interceptioniptables rules in kerneleBPF hooks earlier in the stack
CPU at scaleHigher (iptables rule fan-out)Lower
Flow observabilityLimitedRich per-flow metrics
FQDN-based policiesNoYes
NetworkPolicy loggingNoYes

Dataplane V2 is a strong choice for clusters at scale or when you need detailed network observability. It is also the default enforcement mechanism for NetworkPolicy in GKE Autopilot.

For internal-only Services, the LoadBalancer type provisions an Internal TCP/UDP Load Balancer in your VPC, keeping traffic entirely off the public internet.

DNS and service discovery

GKE runs CoreDNS as the cluster DNS server. Every pod’s /etc/resolv.conf is configured to point at the CoreDNS ClusterIP, so DNS queries from any pod go to CoreDNS automatically.

CoreDNS answers queries using a predictable naming scheme:

<service-name>.<namespace>.svc.cluster.local

Examples:

  • my-api in the production namespace resolves as my-api.production.svc.cluster.local.
  • From a pod in the same namespace, the short name my-api works because /etc/resolv.conf includes production.svc.cluster.local in its search path.
  • From a pod in a different namespace, you need at least my-api.production or the fully qualified name.

Pods also get DNS records in the format:

<pod-ip-dashes>.<namespace>.pod.cluster.local

A pod with IP 10.4.2.5 in the default namespace is reachable at 10-4-2-5.default.pod.cluster.local.

Analogy

CoreDNS works like an internal phone directory that your cluster updates automatically. When a new Service is created it gets a listing. When a Service is removed the listing disappears. Your application just looks up the name and trusts the directory to return the right number — as long as it checks the directory freshly rather than reading from a month-old printout.

DNS caching gotcha

CoreDNS returns TTLs of around 5 seconds for Services. If your application caches DNS results longer than this it may keep routing to a removed or rescheduled pod IP. Use a DNS-aware HTTP client library or ensure your app respects the TTL in responses.

When understanding GKE networking matters

You do not need to memorise every detail of GKE networking on day one. But it becomes important fast in these situations:

  • Troubleshooting pod-to-pod connectivity. When a service cannot reach another service, the likely cause is a misconfigured NetworkPolicy, a wrong namespace reference in DNS, or a Service selector that does not match the pod labels.
  • Designing secure multi-service applications. If you have a frontend, API, and database in one cluster, NetworkPolicy is how you prevent the frontend from talking directly to the database.
  • Planning IP ranges for production. Getting this wrong before cluster creation is expensive. Estimate max nodes, max pods per node, and services count, then work backwards to choose subnets.
  • Exposing applications internally or externally. Choosing between ClusterIP, LoadBalancer, Ingress controllers, and internal load balancers depends on who needs access and from where.
  • Choosing between Standard and Autopilot. GKE Autopilot manages node configuration for you but still uses the same VPC-native networking model, with NetworkPolicy enforcement on by default.
  • Connecting GKE to hybrid environments. If your cluster needs to reach on-premises systems or services in other VPCs, you need to know whether pod IPs are advertised over Cloud VPN or Cloud Interconnect and configure Cloud Router BGP advertisement accordingly.
  • Using Private GKE clusters. Private clusters remove public IPs from nodes, but pods are still assigned VPC-routable IPs. Private does not mean isolated. NetworkPolicy is still needed for pod-level control.

NetworkPolicy: restricting pod-to-pod traffic

By default, the Kubernetes networking contract means every pod can talk to every other pod in the cluster. For most production workloads, this is too permissive. NetworkPolicy is a Kubernetes resource that defines rules controlling which pods can send traffic to which other pods, and on which ports.

Two things are worth understanding before looking at examples:

  1. NetworkPolicy only works if enforcement is active. On GKE Standard clusters, you must enable it at cluster creation with --enable-network-policy. GKE Autopilot enforces it by default.
  2. NetworkPolicy operates at layer 3 and 4 only. It sees IP addresses and ports, not HTTP paths or TLS certificates. For layer-7 controls you need a service mesh like Anthos Service Mesh or Istio.
Silent failure risk

If you apply NetworkPolicy YAML to a Standard cluster that was created without —enable-network-policy, the objects appear to be created successfully but have zero effect. No error is shown. Traffic continues flowing as if the policies do not exist. Always verify enforcement is active before relying on NetworkPolicy for security.

The recommended starting point is a deny-all ingress policy per namespace, which blocks all inbound traffic to every pod in the namespace unless a more specific policy explicitly allows it:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all-ingress
  namespace: production
spec:
  podSelector: {}        # matches all pods in the namespace
  policyTypes:
    - Ingress
  # no ingress rules = deny all ingress

Allowing traffic from a specific source. This example allows frontend pods to reach api pods on port 8080:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-to-api
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: api
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: frontend
      ports:
        - protocol: TCP
          port: 8080

Isolating a database pod. This example accepts connections only from api pods and allows outbound DNS:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: database-isolation
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: database
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: api
      ports:
        - protocol: TCP
          port: 5432
  egress:
    - ports:
        - protocol: UDP
          port: 53   # allow DNS lookups
Layer 7 controls

NetworkPolicy operates at layer 3/4 (IP addresses and ports). It does not inspect HTTP paths, TLS certificates, or application-layer content. For that level of control, pair NetworkPolicy with other GKE security controls and a service mesh.

GKE networking vs traditional VM networking

If you are coming from a background with traditional VM infrastructure, GKE networking has a different mental model in a few important ways:

Traditional VM networkingGKE pod networking
IP assignmentOne IP per host, mostly staticOne IP per pod, dynamic and ephemeral
Addressing workloadsHost IP + portService ClusterIP or DNS name
ScalingAdd VMs, update DNSPods scale horizontally; Services absorb the change
Traffic controlFirewall rules at host levelNetworkPolicy at pod/namespace level plus VPC firewall rules
Service discoveryManual DNS entries or load balancer configCoreDNS resolves service names automatically
ObservabilityPer-VM logsPer-pod logs and per-pod VPC Flow Logs with VPC-native clusters

The key shift is that you stop thinking about where a workload runs and start thinking about what label it carries. Services and NetworkPolicy both use label selectors, so as pods scale up or reschedule, traffic rules and routing adjust automatically without manual intervention.

For a broader comparison of how GKE fits into the wider Google Cloud compute landscape, see GKE vs Cloud Run.

Common mistakes with GKE networking

  1. Not planning pod and service CIDRs before cluster creation. These ranges are permanent. A /24 pod range gives 256 addresses and caps you at roughly 8 nodes at 30 pods each. Size generously. A /20 costs the same as a /24 but gives you room to grow without recreating the cluster.
  2. Enabling NetworkPolicy after cluster creation on Standard and expecting it to work. The enforcement engine is a cluster creation flag. Applying NetworkPolicy YAML to a cluster without it produces objects that appear to succeed but do absolutely nothing. GKE Autopilot enforces NetworkPolicy by default, which is one reason it is a good choice for teams unfamiliar with this gotcha.
  3. Assuming Services and pods are the same thing. Pod IPs change constantly. If your code hardcodes a pod IP, it will break the next time that pod restarts. Always communicate via Service names or ClusterIPs.
  4. Misunderstanding what private clusters actually prevent. A private cluster removes public IPs from nodes. It does not isolate pods from each other. Pod-to-pod isolation still requires NetworkPolicy.
  5. Forgetting DNS TTLs and client caching. CoreDNS returns TTLs of around 5 seconds for Services. If your application caches DNS longer than this it may route to stale IPs after a Service change. Use a DNS-aware HTTP client or honour TTLs in your resolver configuration.
  6. Assuming pod IPs are reachable from on-premises without configuration. VPC-native pod IPs are routable within the VPC and across VPC peering, but they are not advertised to on-premises networks over hybrid connectivity by default. Configure Cloud Router to advertise the pod secondary range via BGP if pods need to be reachable from on-premises.
  7. Overusing NodePort in production. NodePort works, but it exposes a port on every node, bypasses the standard load balancing path, and is harder to secure. Use a LoadBalancer Service or an Ingress controller for production traffic.
  8. Treating NetworkPolicy as layer-7 security. NetworkPolicy controls TCP/UDP ports and IP addresses. It cannot inspect HTTP headers, paths, or TLS certificates. For that level of control, you need a service mesh.

Frequently asked questions

What is the GKE networking model?

GKE gives every pod its own real IP address drawn from your Google Cloud VPC. Pods on different nodes can communicate directly without NAT. Services provide stable virtual IPs in front of changing pod IPs, CoreDNS handles service discovery by name, and NetworkPolicy lets you restrict which pods can talk to which. The whole model is built on top of VPC-native clusters using alias IP ranges.

What is a VPC-native cluster in GKE?

A VPC-native cluster assigns pod IP addresses from a secondary IP range (alias IP range) attached to the node subnet. Because the VPC understands these ranges natively, pod IPs are routable within the VPC without custom routes or IP masquerade. This means firewall rules, VPC Flow Logs, and Cloud Monitoring can all see real pod IPs. VPC-native has been the default since GKE 1.21.

What is the difference between a pod IP and a Service IP?

A pod IP is assigned to a specific pod instance and changes whenever that pod is rescheduled or restarted. A Service IP (ClusterIP) is a stable virtual address that never changes. When traffic is sent to a Service IP, kube-proxy or Dataplane V2 rewrites the destination to one of the current healthy pod IPs behind the Service. You should almost always address Services rather than pod IPs directly in your application code.

Does GKE use kube-proxy or Dataplane V2?

By default GKE uses kube-proxy in iptables mode to manage Service routing. If you enable Dataplane V2 with --enable-dataplane-v2 at cluster creation time, GKE replaces kube-proxy with an eBPF-based implementation powered by Cilium. Dataplane V2 is more efficient at scale, provides richer flow-level observability, and supports FQDN-based network policies and NetworkPolicy logging.

Can I change my pod CIDR ranges after creating a GKE cluster?

No. The pod and service secondary IP ranges are fixed at cluster creation time. They cannot be changed without recreating the cluster. Plan your IP ranges before creating the cluster. A /20 pod range provides 4,096 addresses and supports roughly 100-130 nodes at the default 110 pods-per-node limit. A /24 gives only 256 addresses, which is too small for most production clusters.

Do NetworkPolicies block traffic automatically?

No. NetworkPolicy objects have no effect unless the cluster was created with --enable-network-policy (which activates Calico-based enforcement on Standard clusters). GKE Autopilot enforces NetworkPolicy by default. Even with enforcement active, a pod with no NetworkPolicy selecting it remains open to all traffic. You must apply an explicit deny-all policy first, then add allow rules for the traffic you actually want.

Last verified: 23 March 2026 Cloud services change frequently. Verify details against official documentation before making infrastructure decisions.