Cloud NAT
What does zop.dev create for Cloud NAT?
zop.dev's k8s/gcp/nat module attaches a standalone Cloud NAT router to an existing VPC. The account-setup bootstrap already creates 1, so this module exists for VPCs zop.dev did not create. NAT bills per hour per gateway plus per GB processed, and every private egress byte crosses it.
| Field | Value |
|---|---|
| Cloud | gcp |
Cloud NAT gives private workloads outbound internet access without public IPs. zop.dev can provision a standalone NAT router for an existing VPC when the bootstrap NAT is not enough.
A standalone router from the k8s/gcp/nat module
Standalone Cloud NAT router attached to an existing VPC (k8s/gcp/nat module).
Target VPC and router configuration
Target VPC/network; router and NAT configuration.Coverage for VPCs created outside account setup
The account-setup module already creates a Cloud NAT router; this standalone module covers pre-existing VPCs.
Why a second NAT module exists
The account-setup bootstrap already provisions a Cloud NAT router in the VPCs it creates, so in the common path this module never runs. It exists for the other path: clusters landing in a VPC that predates zop.dev, where private nodes still need outbound internet (image pulls, package mirrors, external APIs) without public IPs. Before applying it, check what the VPC already has: a second NAT gateway on a network that has one is not redundancy, it is a second hourly meter and a routing question nobody meant to ask.
The per-GB meter on egress
Cloud NAT bills two ways: per hour per gateway, and per GB of data processed. The hourly part is predictable; the per-GB part scales with behaviour. Every byte a private workload sends out crosses the NAT: a nightly job pushing large exports, a service streaming to an external API, a misconfigured pod pulling images in a crash loop. All of it lands on the processing meter. When the NAT line grows, the question is which workload’s egress changed, and VPC flow logs answer it faster than guessing.
Ports are the invisible limit
NAT works by lending each VM source ports for its outbound connections, and the port pool is finite. At scale, with many pods, many concurrent connections, and connection churn, port exhaustion appears as intermittently dropped or timed-out outbound connections while everything else looks healthy. The condition is diagnosable in NAT monitoring and tunable (ports per VM, additional NAT IPs), but only if someone knows to look; it is one of the classic invisible-until-production GCP failure modes, and worth checking early on any cluster running high-fanout workloads behind this router.