Cloud Networking in Production · Address Planning
Pods Stopped Scheduling
Kubernetes and serverless workloads can consume a subnet's addresses fast. Size subnets for them, and use prefix delegation or secondary ranges.
Scenario
Example team: an EKS cluster runs in three private /24 subnets, one per availability zone, created when the cluster had 6 nodes. With the AWS VPC CNI, every pod gets a real VPC IP address. Black Friday scaling takes the cluster to 40 nodes.
What you see in production
New pods stay Pending or fail with failed to assign an IP address to container. The autoscaler adds nodes, which makes it worse: each new node reserves warm IPs too. Lambda functions attached to the same subnets start failing with ENI errors. CPU and memory are fine; the cluster has run out of addresses.
The naive code
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
cidr = "10.20.0.0/16"
private_subnets = ["10.20.1.0/24", "10.20.2.0/24", "10.20.3.0/24"] # 251 usable each
}
Reproduce it
Count the addresses a growing cluster needs per zone (nodes + pods + the CNI's warm pool), against what a subnet really offers:
import ipaddress
AWS_RESERVED = 5 # network, router, DNS, future use, broadcast
def usable(cidr):
return ipaddress.ip_network(cidr).num_addresses - AWS_RESERVED
def needed(nodes, pods_per_node, warm_per_node):
return nodes + nodes * pods_per_node + nodes * warm_per_node
zones = 3
for nodes in [6, 20, 40]:
per_zone = -(-nodes // zones) # ceiling division
need = needed(per_zone, pods_per_node=25, warm_per_node=8)
for cidr in ["10.20.1.0/24", "10.20.16.0/20"]:
status = "ok" if need <= usable(cidr) else "EXHAUSTED"
print(f"{nodes:2} nodes: {per_zone:2}/zone need {need:4} IPs, {cidr:14} has {usable(cidr):4} -> {status}")
Output
6 nodes: 2/zone need 68 IPs, 10.20.1.0/24 has 251 -> ok 6 nodes: 2/zone need 68 IPs, 10.20.16.0/20 has 4091 -> ok 20 nodes: 7/zone need 238 IPs, 10.20.1.0/24 has 251 -> ok 20 nodes: 7/zone need 238 IPs, 10.20.16.0/20 has 4091 -> ok 40 nodes: 14/zone need 476 IPs, 10.20.1.0/24 has 251 -> EXHAUSTED 40 nodes: 14/zone need 476 IPs, 10.20.16.0/20 has 4091 -> ok
Root cause
With VPC-native pod networking (AWS VPC CNI, Azure CNI with VNet IPs, GKE alias IPs), pods consume addresses from the VPC like VMs do. Subnet sizes chosen for "a few dozen servers" can't hold hundreds of pods plus warm pools, and a subnet can't be resized after creation. Other address consumers share the same subnets: load balancer nodes, Lambda/Functions VNet integration, endpoints.
The fix
- Size subnets for the workload. For Kubernetes use
/19or/20per zone at least; keep small subnets for things that really are small. - Give pods their own range. On AWS, add a secondary VPC CIDR from
100.64.0.0/10(carrier-grade NAT space, not routable on the internet) and use custom networking so pods take IPs from it while nodes stay in the primary range. - Use prefix delegation to assign
/28prefixes to node ENIs, which raises pods per node and reduces API calls (it needs contiguous free/28blocks, so fragmented subnets still run out). - Or use an overlay where pods don't use VPC addresses at all (Azure CNI Overlay, Cilium overlay, GKE with secondary ranges sized for pods).
resource "aws_vpc_ipv4_cidr_block_association" "pods" {
vpc_id = aws_vpc.main.id
cidr_block = "100.64.0.0/16" # pod-only range, never routed outside the VPC
}
On Azure, choose Azure CNI Overlay for large clusters; on GKE, plan the pod and service secondary ranges before creating the cluster, since they are hard to change later.
Trade-offs
- Bigger subnets use more of the VPC range up front, so plan the VPC as a
/16or larger. - Pod-only
100.64.0.0/10ranges aren't reachable from outside the VPC without NAT; that is usually what you want. - Overlays save addresses but add encapsulation and make pods invisible to VPC-level tools such as security groups and flow logs.
Detect it in production
- Alarm on available IPs per subnet (AWS publishes
AvailableIpAddressCounton every subnet; CloudWatch/VPC IPAM can track utilisation). - Kubernetes events
FailedCreatePodSandBoxwith IP assignment errors; aws-node (VPC CNI) metrics for IP pool usage. - Capacity reviews include IP headroom, not just CPU and memory.
Key points
- VPC-native pods consume subnet addresses; small subnets run out long before compute does.
- AWS reserves 5 addresses per subnet and subnets can't be resized, so size for growth.
- Use secondary
100.64.0.0/10ranges with custom networking, prefix delegation or an overlay.
Practice questions
Why do EKS clusters with the AWS VPC CNI run out of IP addresses?
Answer
Every pod gets a VPC IP from the node's subnet, and nodes keep warm IPs ready. A subnet sized for VMs can't hold hundreds of pods, and subnets can't be resized.
What is EKS custom networking with a 100.64.0.0/10 secondary CIDR used for?
Answer
It places pods in subnets from a separate secondary VPC range (often 100.64.0.0/16) while nodes stay in the primary range, giving pods plenty of addresses without consuming routable corporate space.
How many addresses does AWS reserve in each subnet, and what are they?
Answer
Five: the network address, the VPC router (+1), the DNS server (+2), one reserved for future use (+3) and the last (broadcast) address.
Open in the app to mark lessons complete, take notes and track your progress.