A container without limits can take the whole machine down. Setting limits takes thirty seconds and almost nobody does it, so here is the short version with the parts that are usually wrong.
On the command line
In Compose
The four mistakes
Setting
Thinking
Assuming a CPU limit stops a busy loop from hurting. It does not stop the load average from climbing — the container still competes for I/O and for the run queue. CPU limits protect throughput, not latency.
Believing
How to pick the number
Run the thing unlimited for a day, watch
If your panel manages this, the same values go through the API rather than a recreate: in Panelica the limits are set per container and applied without rebuilding it, which matters because a recreate on a container whose data lives in an anonymous volume is how people lose data.
Rough starting points from the template catalogue on this install, for what they are worth: a voice server or an uptime monitor is happy at 128 MB, MinIO at 256 MB, a WordPress stack at 512 MB, n8n at 1 GB, and anything with a machine-learning model in it — Immich, Ollama — wants 2 GB before it will behave.
On the command line
Code:
docker run -d --name myapp \
--memory=512m \
--memory-swap=512m \
--cpus=1.5 \
--restart=unless-stopped \
myimage:latest
In Compose
Code:
services:
myapp:
image: myimage:latest
restart: unless-stopped
deploy:
resources:
limits:
memory: 512M
cpus: "1.5"
The four mistakes
Setting
--memory without --memory-swap. If you cap memory at 512 MB and leave swap alone, the container gets 512 MB of RAM plus an equal amount of swap by default. It will not get OOM-killed, it will get catastrophically slow, and you will spend an afternoon looking for a network problem. Setting both to the same value means the limit is real.Thinking
--cpus is a percentage. It is cores. --cpus=1.5 means one and a half cores, --cpus=0.5 means half of one. On an 8-core box, --cpus=4 is half the machine, not four percent of it.Assuming a CPU limit stops a busy loop from hurting. It does not stop the load average from climbing — the container still competes for I/O and for the run queue. CPU limits protect throughput, not latency.
Believing
free inside the container. Without lxcfs in the picture, free and top inside a container report the host's memory, not the limit. Every monitoring agent that reads /proc/meminfo from inside will lie to you. Read the cgroup values instead:
Code:
cat /sys/fs/cgroup/memory.max # the actual ceiling
cat /sys/fs/cgroup/memory.current # current usage
How to pick the number
Run the thing unlimited for a day, watch
docker stats, take the peak and add 30%. Guessing low is worse than guessing high — a container that OOMs mid-write to its database has a much more interesting failure mode than one that idles with headroom.If your panel manages this, the same values go through the API rather than a recreate: in Panelica the limits are set per container and applied without rebuilding it, which matters because a recreate on a container whose data lives in an anonymous volume is how people lose data.
Rough starting points from the template catalogue on this install, for what they are worth: a voice server or an uptime monitor is happy at 128 MB, MinIO at 256 MB, a WordPress stack at 512 MB, n8n at 1 GB, and anything with a machine-learning model in it — Immich, Ollama — wants 2 GB before it will behave.