Skip to main content

Runtime Performance Optimization

By default, a single container can consume all host CPU and memory, starving other containers. Setting resource limits prevents one misbehaving container from taking down your entire host.

Resource Limits​

Memory Limits​

# Limit container to 512 MB of RAM
docker run -d --memory=512m my-app:1.0.0

# Memory + swap (set equal to disable swap)
docker run -d --memory=512m --memory-swap=512m my-app:1.0.0

In Compose:

services:
api:
image: my-api:1.0.0
deploy:
resources:
limits:
memory: 512M
reservations:
memory: 256M
OOM Killer

If a container exceeds its memory limit, Docker kills it immediately (OOM). Check with:

docker inspect CONTAINER --format '{{.State.OOMKilled}}'

CPU Limits​

# Limit to 1.5 CPU cores
docker run -d --cpus=1.5 my-app:1.0.0

# CPU shares (relative weight, default 1024)
docker run -d --cpu-shares=512 my-app:1.0.0

In Compose:

services:
api:
image: my-api:1.0.0
deploy:
resources:
limits:
cpus: "1.5"
reservations:
cpus: "0.5"
FlagBehaviorUse Case
--cpus=NHard limit to N coresPrevent CPU monopoly
--cpu-shares=NRelative weight (only under contention)Fair sharing
--memory=NHard limit, OOM kill if exceededPrevent memory monopoly
--memory-reservation=NSoft limit, best-effortPlanning, not enforcement

Monitoring Resources​

Live Monitoring​

# Live resource usage for all containers
docker stats

# Custom format
docker stats --format 'table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.MemPerc}}'

# One-shot snapshot (no streaming)
docker stats --no-stream

Historical Data​

# Check if container was OOM-killed
docker inspect CONTAINER --format '{{.State.OOMKilled}}'

# Check restart count (high = crash loop)
docker inspect CONTAINER --format '{{.RestartCount}}'

# Check current resource config
docker inspect CONTAINER --format '{{json .HostConfig.Memory}}'
docker inspect CONTAINER --format '{{json .HostConfig.NanoCpus}}'

Process Limits​

Prevent fork bombs and runaway process spawning:

docker run -d --pids-limit=256 my-app:1.0.0

In Compose:

services:
api:
image: my-api:1.0.0
pids_limit: 256

Restart Policies​

Configure how Docker handles container crashes:

PolicyBehaviorUse Case
noNever restart (default)One-off tasks
on-failureRestart only on non-zero exitMost services
on-failure:5Restart on failure, max 5 attemptsPrevent infinite loops
unless-stoppedAlways restart unless explicitly stoppedProduction services
alwaysAlways restart, even after rebootCritical infrastructure
services:
api:
image: my-api:1.0.0
restart: unless-stopped

Optimizing Container Startup​

Use Health Checks to Signal Readiness​

services:
api:
image: my-api:1.0.0
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 10s
timeout: 5s
retries: 3
start_period: 30s

The start_period gives the container time to initialize before health checks begin failing.

Graceful Shutdown​

Ensure your application handles SIGTERM properly. Docker sends SIGTERM on stop, then SIGKILL after the timeout (default 10 seconds):

# Give the app 30 seconds to shut down gracefully
docker stop -t 30 my-app

Key Takeaways​

  • Set memory and CPU limits to prevent any single container from monopolizing host resources.
  • Monitor with docker stats and check OOMKilled after unexplained restarts.
  • Use --pids-limit to prevent fork bombs.
  • Set restart: unless-stopped for production services.
  • Use start_period in health checks to avoid false failures during startup.

What's Next​