Skip to content

⚙️ Resource Limits

Why Limit Resources?

Without limits, a single container can consume all your CPU and memory. Imagine your MySQL container running a full table scan, eating up all the host's memory, causing Nginx to be OOM-killed — the entire service goes down.

Resource limits act as a "speed limiter" for each container, preventing a single container from dragging down the entire machine.

CPU Limits

bash
# --cpus: limit to at most 1.5 CPU cores
docker run -d --cpus=1.5 myapp

# --cpu-shares: proportional CPU allocation (default 1024)
docker run -d --cpu-shares=512 light-task    # Low priority
docker run -d --cpu-shares=2048 heavy-task   # High priority (4x weight)

# --cpuset-cpus: pin to specific CPU cores
docker run -d --cpuset-cpus="0,1" myapp      # Use only cores 0 and 1

# View container CPU usage
docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"
NAME        CPU %     MEM USAGE / LIMIT
nginx       0.50%     12.3MiB / 512MiB
mysql       45.20%    1.2GiB / 2GiB
redis       0.10%     3.8MiB / 128MiB

Memory Limits

bash
# Limit to at most 512MB memory
docker run -d --memory=512m myapp

# Set both soft and hard limits (soft triggers GC, hard triggers OOM kill)
docker run -d --memory=512m --memory-swap=1g myapp
# memory-swap = memory + swap, so swap is allocated 512m

# Disable swap (recommended for production)
docker run -d --memory=512m --memory-swap=512m --oom-kill-disable myapp
# ⚠️ Use --oom-kill-disable with caution: when memory is insufficient, the container won't be killed but may crash the host

# Check for OOM events
docker inspect --format='{{.State.OOMKilled}}' myapp
false

# View container memory usage
docker stats --no-stream myapp
NAME    CPU %   MEM USAGE / LIMIT   MEM %   NET I/O       BLOCK I/O
myapp   2.30%   256MiB / 512MiB     50.00%  1.2MB / 800kB 0B / 0B

> ⚠️ Note: > ⚠️ Lesson learned: Java applications are especially prone to OOM — the JVM defaults to using 1/4 of system memory. When setting --memory for Java containers, remember to also set -Xmx in the application, otherwise the JVM may request memory beyond the container limit.

Disk I/O and Restart Policies

bash
# Limit disk write rate (10MB/s read, 5MB/s write)
docker run -d --device-read-bps=/dev/sda:10mb --device-write-bps=/dev/sda:5mb myapp

# Restart policies (always, on-failure, unless-stopped)
docker run -d --restart=always myapp              # Auto-restart on crash
docker run -d --restart=unless-stopped myapp      # Auto-restart unless manually stopped
docker run -d --restart=on-failure:5 myapp        # Restart up to 5 times

# Configure resource limits in docker-compose.yml
cat > docker-compose.yml << 'EOF'
services:
  web:
    image: nginx:alpine
    deploy:
      resources:
        limits:
          cpus: "1.0"
          memory: 256M
        reservations:
          cpus: "0.5"
          memory: 128M
    restart: unless-stopped

  api:
    build: ./api
    deploy:
      resources:
        limits:
          cpus: "2.0"
          memory: 1G
    restart: unless-stopped
EOF