Why Resource Limits Matter
Without resource limits, a single runaway container can consume all available CPU and memory on a host, starving every other container and potentially crashing the machine. Resource limits are a safety net — they ensure fair allocation and predictable behavior in multi-container environments.
They're not optional in production.
Setting Memory Limits
# Limit to 512 MB RAM with no swap
docker run -d --memory 512m --memory-swap 512m my-app:latest--memory— hard memory limit. If the container exceeds this, the kernel OOM killer terminates the process.--memory-swap— total memory + swap. Setting it equal to--memorydisables swap for the container.--memory-reservation— soft limit; Docker tries to keep usage below this but won't enforce it hard.
# Soft limit: Docker reclaims if host is under pressure
docker run -d --memory 1g --memory-reservation 512m my-app:latestSetting CPU Limits
# Limit to 1.5 CPUs (1 CPU = 1,000,000 units)
docker run -d --cpus 1.5 my-app:latest
# Or use the low-level flags
docker run -d --cpu-period 100000 --cpu-quota 150000 my-app:latest
# Set relative CPU shares (default is 1024)
docker run -d --cpu-shares 512 # this container gets half the CPU weight of default containers
my-app:latest--cpus— the easiest way: specify how many CPU cores the container can use.--cpu-shares— relative weight during CPU contention (doesn't cap CPU when the host is idle).
Resource Limits in Docker Compose
services:
api:
image: my-app:latest
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
reservations:
cpus: '0.25'
memory: 128M
worker:
image: my-worker:latest
deploy:
resources:
limits:
cpus: '2.0'
memory: 1G
reservations:
cpus: '0.5'
memory: 256MNote: the deploy.resources syntax is the v3 Compose format. For Compose v2 without Swarm:
services:
api:
image: my-app:latest
mem_limit: 512m
memswap_limit: 512m
cpus: 1.0Monitoring Resource Usage
# Live resource stats for all containers
docker stats
# One-time snapshot (no stream)
docker stats --no-stream
# Inspect a container's configured limits
docker inspect my-container | grep -A 10 '"HostConfig"'Sample output from docker stats:
CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O
api_1 12.4% 210MiB / 512MiB 41% 1.2GB / 890MB
worker_1 68.1% 756MiB / 1GiB 73% 450MB / 2.1GBHandling OOM Kills
When a container exceeds its memory limit, the kernel OOM killer terminates it. Check if this happened:
docker inspect <container-id> --format '{{.State.OOMKilled}}'
# true = the container was OOM killedIf you're seeing OOM kills:
- 1Increase the memory limit
- 2Profile memory usage with
docker statsor application-level profiling - 3Look for memory leaks in your application
Right-Sizing Guidelines
Start with these baseline limits and adjust based on observed usage:
| Service Type | CPU | Memory |
|---|---|---|
| Lightweight API | 0.5 | 256M |
| Node.js API | 1.0 | 512M |
| Python ML worker | 2.0–4.0 | 2G–8G |
| PostgreSQL | 1.0–2.0 | 1G–4G |
| Redis | 0.5 | 256M–1G |
Always set limits above your p99 observed usage to avoid throttling under legitimate load spikes.
Resource Limits on PandaStack
When deploying containers on PandaStack, resource allocation is configured per deployment from [dashboard.pandastack.io](https://dashboard.pandastack.io). The platform enforces limits at the Kubernetes level, ensuring your container can't impact other tenants' workloads.
For managed databases (PostgreSQL, MySQL, Redis, MongoDB), PandaStack handles resource allocation — you choose a plan tier and the platform manages the underlying limits and scaling.
Deploy your container:
npm install -g @pandastack/cli
panda deploy --type container --repo your-org/your-repoSee [docs.pandastack.io](https://docs.pandastack.io) for resource configuration options.