interview-prep

Crisp answer: The AWS VPC CNI plugin assigns real VPC IP addresses to pods. Every pod gets an IP from the node's subnet, making pods first-class VPC citizens — directly routable within the VPC without any overlay network.

How it works:

Each EC2 node has a primary ENI for the node itself and can attach additional ENIs. Each ENI can hold multiple secondary private IP addresses. The VPC CNI pre-warms a pool of secondary IPs on each node so pods can start instantly without waiting for IP assignment.

Node (m5.large):
  Primary ENI:    10.0.1.10  (node IP)
  Secondary IPs:  10.0.1.20  → assigned to pod-1
                  10.0.1.21  → assigned to pod-2
                  10.0.1.22  → assigned to pod-3
                  10.0.1.23  → pre-warmed, waiting for next pod

  Secondary ENI:  10.0.1.30  → assigned to pod-4
                  10.0.1.31  → assigned to pod-5
                  ...

Maximum pods per node:

Each instance type has a limit on ENIs and secondary IPs per ENI:

m5.large:  3 ENIs × 10 IPs = 30 IPs
            minus 1 per ENI for the ENI itself = 27 pods max
            plus the node IP = 29 usable

# Check the limit:
aws ec2 describe-instance-types \
  --instance-types m5.large \
  --query 'InstanceTypes[].NetworkInfo.{MaxENI:MaximumNetworkInterfaces,MaxIPs:Ipv4AddressesPerInterface}'

The IP exhaustion problem:

Because every pod uses a real VPC IP, large clusters can exhaust subnet address space:

Subnet: 10.0.1.0/24 = 256 IPs (251 usable after AWS reserves 5)
20 nodes × 27 pods = 540 IPs needed → subnet too small

Solutions:
1. Use larger subnets (/20 = 4096 IPs, /18 = 16384 IPs)
2. Enable prefix delegation (assign /28 blocks instead of individual IPs)
3. Use custom networking (assign pods to a different CIDR than nodes)

Prefix delegation (recommended for large clusters):

# Enable prefix delegation on VPC CNI
kubectl set env daemonset aws-node -n kube-system ENABLE_PREFIX_DELEGATION=true
kubectl set env daemonset aws-node -n kube-system WARM_PREFIX_TARGET=1

# With prefix delegation, each ENI slot holds a /28 (16 IPs) instead of 1 IP
# m5.large: 3 ENIs × 9 prefix slots × 16 IPs = 432 pods per node

Pod-to-pod communication:

Because all pods have VPC IPs, pod-to-pod traffic is routed at the VPC level — no overlay tunneling. Traffic between pods on different nodes goes through the VPC routing, not through a virtual tunnel.

# Verify pod IPs are real VPC IPs
kubectl get pods -o wide
# POD-IP 10.0.1.45  ← real VPC IP, not 192.168.x.x overlay

# Check VPC CNI version and config
kubectl describe daemonset aws-node -n kube-system
kubectl get cm amazon-vpc-cni -n kube-system -o yaml

Security groups for pods:

With VPC CNI, pods can have their own security groups (not just the node SG):

# Enable security groups for pods
kubectl set env daemonset aws-node -n kube-system ENABLE_POD_ENI=true

# Create a SecurityGroupPolicy (CRD provided by VPC CNI)
apiVersion: vpcresources.k8s.aws/v1beta1
kind: SecurityGroupPolicy
metadata:
  name: db-access
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: api
  securityGroups:
    groupIds:
      - sg-0abc123  # SG that allows PostgreSQL access

This lets you assign fine-grained AWS security groups to specific pods rather than applying the same SG to all pods on a node.

What to say in the interview:

"The AWS VPC CNI is the key difference between EKS and self-managed Kubernetes with an overlay network. Every pod gets a real VPC IP from the node's subnet, which means pods are directly routable within the VPC and you can use security groups and VPC flow logs on pod traffic. The main operational consideration is IP address planning — you need large enough subnets because every pod consumes a VPC IP. For large clusters I enable prefix delegation which assigns /28 blocks per ENI slot and dramatically increases pod density per node."


My notes