Container Constraints: MongoDB in Kubernetes
Container Constraints
Running MongoDB in Kubernetes introduces constraints that do not exist on bare metal. The container runtime enforces CPU and memory limits. Kubernetes manages storage volumes. The scheduler decides where pods run. Each of these interactions can cause performance problems that look like MongoDB bugs but are actually infrastructure misconfigurations.
Memory Limits and WiredTiger
WiredTiger’s cache size defaults to 50% of available RAM minus 1 GB. In a container, “available RAM” is the container’s memory limit, not the host’s physical RAM. If the container has a 16 GB memory limit, WiredTiger sets its cache to 7 GB.
But the container needs memory beyond the WiredTiger cache: the connection pool, query execution buffers, aggregation pipeline memory, the operating system page cache, and the MongoDB server process itself. A 16 GB container with a 7 GB WiredTiger cache leaves 9 GB for everything else. This is usually sufficient.
The danger: if the MongoDB process exceeds the container’s memory limit, the OOM killer terminates the process. This is a hard crash with no graceful shutdown.
# Kubernetes pod spec
containers:
- name: mongodb
image: mongo:7.0
resources:
requests:
memory: "16Gi"
cpu: "4"
limits:
memory: "16Gi" # Hard limit - OOM kill above this
cpu: "4"
command: ["mongod"]
args:
- "--wiredTigerCacheSizeGB=7" # Explicitly set, do not rely on auto-detection
- "--bind_ip_all"
Never rely on WiredTiger’s auto-detection in containers. Set --wiredTigerCacheSizeGB explicitly to leave headroom:
| Container memory limit | Recommended cacheSizeGB | Headroom for OS + server |
|---|---|---|
| 8 GB | 3 GB | 5 GB |
| 16 GB | 7 GB | 9 GB |
| 32 GB | 14 GB | 18 GB |
| 64 GB | 28 GB | 36 GB |
The formula: cacheSizeGB = (containerMemoryGB * 0.5) - 1. If running aggregations with allowDiskUse: false (in-memory), reduce cache further to leave room for the 100 MB per-pipeline memory limit.
CPU Limits and CFS Throttling
Kubernetes uses the Linux Completely Fair Scheduler (CFS) to enforce CPU limits. When a container exceeds its CPU limit within a 100ms period, the kernel throttles the container by pausing it until the next period. This manifests as latency spikes.
MongoDB is multi-threaded. A 4-CPU limit means MongoDB can use 4 cores. But during a checkpoint (every 60 seconds), WiredTiger spawns multiple threads for flushing data to disk. If the checkpoint temporarily needs 6 cores and the limit is 4, the CFS throttles MongoDB. All operations pause for the throttling duration (potentially tens of milliseconds).
// Detect CFS throttling from the application side
// Symptom: periodic p99 latency spikes every ~100ms
// Correlates with container CPU throttling metrics:
// container_cpu_cfs_throttled_periods_total
// container_cpu_cfs_throttled_seconds_total
The fix: set CPU requests equal to limits (guaranteed QoS class in Kubernetes) and size CPUs for peak usage, not average:
resources:
requests:
cpu: "8" # Same as limit for Guaranteed QoS
memory: "16Gi"
limits:
cpu: "8" # Sized for checkpoint peaks
memory: "16Gi"