GKE VPC-native clusters let your pods get IP addresses directly from your VPC network, which is way more efficient and flexible than the older route-based networking.

Let’s see it in action. Imagine you have a GKE cluster and you want to deploy a service that needs specific IP addresses for its pods, perhaps for firewall rules or to integrate with on-premises systems.

Here’s a basic setup:

apiVersion: v1
kind: Namespace
metadata:
  name: my-app
---
apiVersion: networking.k8s.io/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: my-app
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80

When you deploy this, GKE automatically assigns IP addresses to the pods from the secondary IP ranges you’ve defined for your cluster’s subnet. You can then inspect these IPs:

kubectl get pods -n my-app -o wide

You’ll see output like:

NAME                           READY   STATUS    RESTARTS   AGE   IP            NODE          NOMINATED NODE   READINESS GATES
nginx-deployment-7f7f7f7f7f-abcde   1/1     Running   0          60s   10.100.1.5    gke-node-1    <none>           <none>
nginx-deployment-7f7f7f7f7f-fghij   1/1     Running   0          60s   10.100.1.6    gke-node-2    <none>           <none>

Notice the IPs 10.100.1.5 and 10.100.1.6. These aren’t just random IPs; they come from the alias IP ranges configured for your GKE cluster. This allows for direct communication between pods and other resources in your VPC without NAT.

The core problem VPC-native clusters solve is the IP address exhaustion and the complexity of NAT for pod communication. In older, route-based clusters, pods got IPs from a private range managed by GKE, and when they communicated outside the cluster, their source IP was NATted to the node’s IP. This made it hard to apply granular network policies based on pod IPs and complicated logging and troubleshooting.

With VPC-native, you define secondary IP ranges on your VPC subnet. When you create a GKE cluster, you associate these secondary ranges with the cluster. GKE then uses these ranges to allocate IPs to your pods. This means pods get IPs that are routable within your VPC, making them first-class citizens of your network.

Here’s how you set this up in Google Cloud:

  1. Create a VPC network and subnet:

    gcloud compute networks create my-vpc --subnet-mode=custom
    gcloud compute networks subnets create my-subnet \
      --network=my-vpc \
      --range=10.0.0.0/20 \
      --region=us-central1
    
  2. Add secondary IP ranges to the subnet: These will be used by your GKE pods.

    gcloud compute networks subnets update my-subnet \
      --region=us-central1 \
      --add-secondary-ranges= pods-range=10.100.1.0/20,services-range=10.100.2.0/24
    

    Here, pods-range is for your pod IPs, and services-range is for your Kubernetes Service IPs.

  3. Create a GKE cluster using these ranges:

    gcloud container clusters create my-vpc-native-cluster \
      --network=my-vpc \
      --subnetwork=my-subnet \
      --cluster-secondary-range-name=pods-range \
      --services-secondary-range-name=services-range \
      --enable-ip-alias \
      --region=us-central1
    

    The --enable-ip-alias flag is crucial here.

The magic happens because GKE works with the VPC network directly. When you create a pod, GKE requests an IP address from the secondary range you designated for pods. This IP is then assigned to the pod’s network interface. For external communication, instead of NAT, GKE uses VPC Network Address Translation (NAT) if you configure it, or routes the traffic directly if the destination is within the VPC or has a specific route.

A common point of confusion is the relationship between pod IP ranges and service IP ranges. The pod IP range is for the individual pods, allowing direct communication. The service IP range is for Kubernetes Services, providing a stable IP address for a group of pods. Both are configured as secondary ranges on the same subnet.

When you create a Kubernetes Service, GKE assigns an IP from the services-range you specified. This IP is then routed to the appropriate pod IPs within the cluster. This makes it possible to have firewall rules in your VPC that allow or deny traffic based on pod IPs, and to expose services with predictable IPs that are part of your VPC address space.

The key benefit is that your pods are now peers with other resources in your VPC. This means you can use VPC firewall rules to control traffic to and from your pods directly, without needing to manage iptables rules on nodes or rely on GKE’s internal network policies alone. It also simplifies hybrid cloud connectivity and on-premises integration, as your pod IPs are just standard VPC IPs.

What many people overlook is that the IP addresses assigned to your nodes also come from the primary range of the subnet, not the secondary ranges. The secondary ranges are exclusively for pods and services. This separation is important for network management and understanding IP allocation.

This setup fundamentally changes how you think about pod networking, moving from an overlay network concept to a direct integration with your cloud VPC.

The next challenge you’ll often face is understanding how to manage egress traffic from these pods, especially when you need to control the source IP address for external services.

Want structured learning?

Take the full Gke course →