container-resource-tuning
GitHub提供容器内存和CPU限制推荐,诊断OOM和CPU节流问题,并根据不同技术栈给出调整建议。
Trigger Scenarios
Install
npx skills add nixopus/nixopus --skill container-resource-tuning -g -y
SKILL.md
Frontmatter
{
"name": "container-resource-tuning",
"metadata": {
"version": "1.0"
},
"description": "Size container memory and CPU limits, diagnose OOM kills and CPU throttling, and recommend resource adjustments by ecosystem. Use when containers are being OOM-killed, running slowly, or when setting initial resource limits for a deployment."
}
Container Resource Tuning
Default Resource Recommendations
Starting points by ecosystem. Adjust based on actual usage.
| Ecosystem | Memory limit | CPU shares | Notes |
|---|---|---|---|
| Node.js | 512MB | 0.5 | V8 GC is memory-hungry; Next.js SSR needs more |
| Node.js (Next.js SSR) | 1024MB | 1.0 | Server-side rendering is CPU and memory intensive |
| Python (Django/Flask) | 512MB | 0.5 | Per-worker; multiply by worker count |
| Python (FastAPI) | 256MB | 0.5 | Async, lower per-process memory |
| Go | 256MB | 0.5 | Static binary, efficient memory use |
| Rust | 128MB | 0.25 | Minimal runtime overhead |
| Java (Spring Boot) | 1024MB | 1.0 | JVM needs headroom; set -Xmx to 75% of limit |
| PHP (FrankenPHP) | 512MB | 0.5 | Per-request memory; depends on payload |
| Ruby (Rails) | 512MB | 0.5 | Per-worker; Puma workers multiply this |
| Elixir (Phoenix) | 256MB | 0.5 | BEAM VM is efficient; handles concurrency well |
| .NET (ASP.NET) | 512MB | 0.5 | Similar to Node.js profile |
| Static (Caddy/nginx) | 64MB | 0.25 | Minimal; just serving files |
Diagnosing OOM Kills
When container_inspect shows oom_killed: true:
- Check current limit:
container_inspect→ memory limit - Check peak usage:
container_stats→ memory usage and limit - Check what's consuming memory:
container_exec ["ps", "aux", "--sort=-%mem"]→ top processes- Node.js:
container_exec ["node", "-e", "console.log(process.memoryUsage())"]
Common causes
| Ecosystem | Cause | Fix |
|---|---|---|
| Node.js | V8 heap exceeds limit | Set NODE_OPTIONS=--max-old-space-size=<MB> to 75% of container limit |
| Node.js | Memory leak (heap grows unbounded) | Profile with --inspect; check for event listener leaks, unbounded caches |
| Java | JVM default heap exceeds container limit | Set -Xmx to 75% of container memory limit |
| Python | Large dataset loaded into memory | Use streaming/chunked processing; increase limit if data size is fixed |
| Any | Too many worker processes | Reduce worker count: Gunicorn --workers, Puma workers, PM2 instances |
Right-sizing after OOM
- Increase memory limit by 50% from current value
- Deploy and monitor
container_statsfor 10 minutes - If peak usage is consistently below 60% of limit: limit is right
- If peak usage exceeds 80%: increase again or investigate the memory consumer
- If peak usage is below 30%: reduce limit to save resources
Diagnosing CPU Throttling
When the app is slow but not OOM-killed:
- Check CPU usage:
container_stats→ CPU percentage - Check host load:
get_machine_stats→ system load average - Check for CPU-bound work:
container_exec ["ps", "aux", "--sort=-%cpu"]→ top CPU consumers
Common causes
| Symptom | Cause | Fix |
|---|---|---|
| CPU at 100% of limit | App is compute-bound | Increase CPU shares or optimize hot paths |
| CPU at 100%, response times spike | Not enough CPU for request volume | Scale horizontally (more instances) or increase CPU |
| Low CPU but slow responses | Waiting on I/O (database, external API) | Not a CPU issue — check database latency |
| Host load > 2x cores | Server overloaded | Multiple containers competing — reduce total load or upgrade server |
JVM-Specific Tuning
Java apps need explicit JVM flags to respect container limits:
JAVA_TOOL_OPTIONS=-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0
UseContainerSupport(default since Java 10): JVM reads cgroup memory limitsMaxRAMPercentage=75.0: heap uses 75% of container memory, leaving room for native memory and GC
Node.js-Specific Tuning
NODE_OPTIONS=--max-old-space-size=384
For a 512MB container, set old space to ~75% (384MB). V8 needs headroom for GC, native code, and buffers.
For production, also set:
UV_THREADPOOL_SIZE=4(default) — increase for I/O-heavy appsNODE_CLUSTER_WORKERS— if using cluster mode, each worker needs its own memory budget
Python-Specific Tuning
Gunicorn workers multiply memory usage:
gunicorn app:app --workers 2 --worker-class uvicorn.workers.UvicornWorker
Rule of thumb: workers = (2 * CPU cores) + 1, but in containers with limited CPU, use 2-4 workers max.
Each worker uses roughly the same memory as a single process. 4 workers × 256MB = 1GB total.
Compose Resource Limits
services:
app:
deploy:
resources:
limits:
memory: 512M
cpus: '0.5'
reservations:
memory: 256M
cpus: '0.25'
limits: hard ceiling — container is OOM-killed if exceededreservations: guaranteed minimum — Docker ensures this is available
Monitoring After Changes
After adjusting resources:
container_stats— check memory and CPU usage over timeget_container_logs— scan for OOM warnings or performance errorshttp_probe— verify response times are acceptable- If
restart_countdrops to 0 and memory stays below 80%: tuning is correct
Related Skills
post-deploy-verification— Check container stability after resource changesfailure-diagnosis— Exit code 137 (OOM kill) diagnosiscompose-setup— Resource limits in docker-compose.yml
Version History
- cf05d97 Current 2026-08-20 14:51


