← Learnings

Why my Kubernetes cluster's IP ranges could break my home Wi-Fi

A cluster's private IP ranges look like the cloud's business. Once a VPN hands them to your laptop, they're your Wi-Fi's business too.

How does a cloud range end up on my laptop?

My GKE cluster has no public IPs, so the team reaches it through a Tailscale subnet router: a small VM in the VPC that advertises its private ranges to every laptop on the tailnet.

Each advertised range becomes a route on your laptop, a line in its routing table saying send these addresses into the tunnel. macOS accepts them by defaultsrc.

What if the laptop already routes that range?

It usually does: your home Wi-Fi is one route, and on Linux Docker's bridge is another. My first picks put the nodes on 10.0.0.0/24, the same /24 as my home network, and the Services on 172.17.0.0/16, Docker's first rangesrc.

YOUR LAPTOP'S ROUTING TABLE DESTINATION LEAVES VIA ENDS UP AT 10.0.0.0/24 en0 · Wi-Fi the living-room router 10.0.0.0/24 utun · Tailscale a GKE node, via the VPC SAME DESTINATION, SAME LENGTH: A TIE
FIG 1 · TWO ANSWERS TO ONE QUESTION

The OS picks between overlapping routes by longest-prefix match: the most specific winssrc. Two identical /24s are equally specific, and Tailscale doesn't document which one macOS keeps.

Longest-prefix match can only choose between routes of different sizes.

Either way something breaks. If the Wi-Fi route wins, packets for a GKE node go to the living-room router. If the tunnel wins, packets for the router go into the tunnel.

ASIDE

On a Mac, Docker's bridge lives inside Docker Desktop's VMsrc, so the 172.17 clash hits containers: they treat a cloud 172.17 address as local and never send it out.

Which ranges are safe?

The ones nobody's laptop already uses. I skip:

  1. 192.168.0.0/16: home routers, and Docker's overflow poolsrc.
  2. 10.0.x and 10.1.x: one large ISP's home gateway sits at 10.0.0.1src.
  3. 172.16.0.0/12: Docker's default poolssrc.
  4. 100.64.0.0/10: the CGNAT block Tailscale numbers its devices fromsrc.

I moved to 10.64.0.0/24 for nodes, 10.65.0.0/16 for Pods and 10.66.0.0/20 for Services.

Why get it right on day one?

GKE won't let you change the Services range after creationsrc. Pod ranges added later reach only new node poolssrc, and the node subnet can grow but never shrinksrc. A wrong Services range means a new cluster.

A private range stops being private once a VPN writes it into someone's routing table. Pick yours as if every laptop on the team gets a vote.