Docker / Compose and reliable runtime contracts / Lesson 11
Resource limits, logs, and bounded failure
Plan CPU, memory, process count, and log retention as independent parts of the application budget.
On this page
Lesson goals
- Explain CPU throttling, memory enforcement, and process limits.
- Correlate runtime evidence without inventing universal sizing formulas.
A limit is a boundary, not a capacity estimate
Containers do not inherently reserve a safe share of every host resource. A busy process can compete for CPU, memory, process ids, disk, and network. Start from measured application needs and host capacity, including headroom for the engine and operating system. A hard memory limit may stop a leaking process but does not make it memory-efficient. A CPU limit can increase latency through throttling even when memory remains available.
Declare separate controls for separate resources
The model below is an illustrative budget for the simple fixture, not a production sizing recommendation. mem_limit is a hard memory boundary, mem_reservation expresses a softer constraint, cpus constrains CPU allocation, and pids_limit bounds process creation. Enforcement depends on the host, cgroups, engine mode, and supported platform. Read the effective settings and workload behavior before claiming that any YAML key guarantees identical isolation everywhere.
services:
api:
image: parcel-api:lab
cpus: 0.5
mem_limit: 256m
mem_reservation: 128m
pids_limit: 64
The model states an intended half-CPU allocation and a 256 MiB-style Docker memory suffix boundary, with a lower reservation and 64-process cap. It does not prove the service fits those limits or that a particular host enforces them. Load tests and effective container inspection are required in a separately authorized environment.
Interpret symptoms before changing budgets
A killed process, slow request, failed health check, and process-creation error point toward different resource paths. OOMKilled is useful evidence for container memory enforcement, while CPU throttling usually slows work rather than producing the same kill signal. A high process count can prevent worker creation despite spare memory. Correlate state, resource trends, host pressure, and timestamps; increasing every limit can move the incident to the host without fixing the cause.
Bound logs without losing incident evidence
The fixture sends HTTP request logs to stderr. A logging driver collects stdout/stderr according to daemon and container settings; application file logs are a separate path. Rotation limits reduce indefinite disk growth but can discard evidence before an incident is investigated. Define retention, redaction, shipping, and access controls together. A container restart does not guarantee logs were safely archived, and logs can include secrets if the application prints them.
services:
api:
image: parcel-api:lab
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
String-valued options request rotation around the configured size and retain a bounded number of files for this container. The settings are not a strict total-host storage guarantee and do not cover application files or external collectors. Changing a default driver policy does not retroactively prove all existing containers adopted it.
Measure steady state and failure behavior
Observe warmed-up memory, bursts, request concurrency, CPU throttling, log rate, and recovery under the selected limits. Include startup and shutdown rather than measuring only idle behavior. Reserve enough capacity for diagnostics and dependencies while avoiding unlimited growth. A useful report records the exact image, effective limits, workload, and host mode, then explains which bottleneck the evidence supports. Never infer production throughput from the tiny synthetic service alone.
Common errors and fixes
Exit 137 is treated as proof of a memory leak.
- Why it happens
- A termination code was interpreted without OOM and timing evidence.
- How to fix it
- Correlate OOMKilled, effective limits, memory growth, and termination events.
- Prevent it next time
- Preserve resource telemetry and distinguish leak, burst, and forced stop.
Health checks fail only under CPU pressure.
- Why it happens
- Throttling delays the application or probe beyond its timeout.
- How to fix it
- Review measured CPU demand, probe cost, and deadlines together.
- Prevent it next time
- Load-test health behavior within the intended resource envelope.
The host disk fills despite container memory limits.
- Why it happens
- Memory limits do not cap log files, volume data, or build-cache storage.
- How to fix it
- Identify the actual storage owner and apply its reviewed retention policy.
- Prevent it next time
- Budget disk and logs separately from RAM and CPU.
Check your understanding
1. Would doubling memory fix CPU-throttled request latency?
Show worked solution
Not when CPU allocation is the limiting resource. Compare throttling and utilization evidence with request timings before changing memory. A larger memory budget may consume host headroom while leaving the CPU boundary unchanged; resource fixes should follow the bottleneck supported by measurements.
2. Why can aggressive log rotation harm incident response?
Show worked solution
It may remove the first error before operators inspect the container. Match retention to expected investigation delay and log volume, and ship necessary evidence to controlled durable storage. Keep sensitive-field redaction and access restrictions in that design rather than retaining unlimited raw logs on the host.
Key takeaways
- CPU, memory, processes, logs, and durable data need separate budgets.
- Limits bound consequences; measurements identify the correct remedy.