Performance Tuning and Troubleshooting
Are you experiencing issues with containers in your production environment—high CPU usage? Memory overload? Slow I/O? You need a systematic troubleshooting approach.
1. What You'll Learn
- Methods for Identifying Performance Bottlenecks
- Common Failure Scenarios and Root Causes
- Container Debugging Toolchain
- Troubleshooting Network Latency
- Disk Space Management
2. A Story About an Early Morning Alert
(1) Pain Point: API latency skyrocketed from 50 ms to 5 s
API latency in the production environment skyrocketed from 50 ms to 5 s, leading to a flood of user complaints. Alice used docker stats to discover that while CPU usage wasn’t spiking, I/O wait times were extremely high, and the containers seemed to be “stuck.”
(2) A Systematic Approach to Troubleshooting
Alice used iostat to identify that the log driver was causing the disk I/O to reach its limit; after switching the log driver, the issue was resolved.
BASH
# Step 1: Check resource usage
docker stats --no-stream
# Step 2: Check host IO
iostat -x 1 5
# Step 3: Identify the bottleneck
docker system df -v
(3) Benefits: 5 seconds → 50 milliseconds, 10-minute recovery time
It took only 10 minutes from the alert to the resolution—systematic troubleshooting is 100 times more efficient than simply “trying a reboot.”
3. Performance Troubleshooting Decision Tree
(1) The Four Major Bottlenecks and Their Corresponding Tools
graph TB
START["Performance Issue"] --> CPU{"CPU High?"}
CPU -->|Yes| C1["docker stats<br/>top / htop"]
CPU -->|No| MEM{"High memory usage?"}
MEM -->|Yes| M1["docker stats<br/>/proc/meminfo"]
MEM -->|No| IO{"IO Waiting for Gao?"}
IO -->|Yes| I1["iostat -x<br/>docker system df"]
IO -->|No| NET{"Slow Internet?"}
NET -->|Yes| N1["iperf / ping<br/>tcpdump"]
(2) Common Troubleshooting Tools
| Tool | Function | Use Case |
|---|---|---|
docker stats |
Container Resource Usage | CPU/Memory/IO Overview |
docker system df |
Docker Disk Usage | Troubleshooting a Full Disk |
docker events |
Container Event Stream | OOM/Restart/Abnormal Exit |
docker logs |
Container Logs | Application Errors |
docker inspect |
Container Configuration | Status/Exit Code/Network |
iostat |
Disk I/O Statistics | I/O Bottlenecks |
iperf |
Network Bandwidth Test | Network Bottlenecks |
nsenter |
Enter Container Namespace | Advanced Debugging |
4. Troubleshooting CPU Bottlenecks
▶ Example: Monitoring Resources with docker stats (Difficulty: ⭐)
BASH
# Real-time stats for all containers
docker stats
# One-time snapshot
docker stats --no-stream
# Custom format
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}\t{{.BlockIO}}"
▶ Example: The stress container simulates CPU load (Difficulty: ⭐⭐)
BASH
# Run stress to simulate CPU load
docker run --rm --name stress-test \
--cpus=1 \
progrium/stress --cpu 1 --timeout 30s
# Monitor with docker stats (in another terminal)
docker stats stress-test --no-stream
5. Troubleshooting Memory Bottlenecks
(1) Common Memory Issues
| Symptom | Exit Code | Cause | Solution |
|---|---|---|---|
| OOM Kill | 137 | Exceeded the --memory limit | Increase the limit or optimize memory usage |
| Memory Leak | Gradual Increase | Application Bug | Analyzing a Heap Dump |
| High cache usage | 0 | File system cache | Normal behavior (can be reclaimed) |
▶ Example: Simulating a Container OOM (Difficulty: ⭐⭐⭐)
BASH
# Start container with 50 MB memory limit
docker run -d --name oom-test \
--memory=50m \
--restart=on-failure:3 \
progrium/stress --vm 1 --vm-bytes 100M --timeout 10s
# Watch for OOM events
docker events --filter event=oom --since 1m
# Check exit code
docker inspect oom-test --format='ExitCode: {{.State.ExitCode}}, OOMKilled: {{.State.OOMKilled}}'
6. Troubleshooting Disk I/O Bottlenecks
▶ Example: docker system df Disk Analysis (Difficulty: ⭐⭐)
BASH
# Show Docker disk usage
docker system df
# Detailed breakdown
docker system df -v
💻 Output:
TEXT
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 12 5 4.2GB 2.8GB (66%)
Containers 8 3 350MB 280MB (80%)
Local Volumes 5 3 1.2GB 500MB (41%)
Build Cache 45 0 800MB 800MB (100%)
▶ Example: Disk Cleanup Policy (Difficulty: ⭐⭐)
BASH
# Remove unused data (images, containers, volumes, build cache)
docker system prune
# More aggressive: remove all unused images (not just dangling)
docker system prune -a
# Remove build cache only
docker builder prune
# Remove volumes (WARNING: deletes data)
docker volume prune
(1) Comparison of Storage Drivers
| Drivers | Performance | Stability | Recommendation |
|---|---|---|---|
| overlay2 | High | ✅ Stable | ✅ Default recommendation |
| aufs | Chinese | ⚠️ Old kernel | ❌ Deprecated |
| devicemapper | Low | ⚠️ Complex configuration | ❌ Not recommended |
| zfs | Medium | ✅ Stable | Specific scenarios |
| btrfs | Medium | ⚠️ Unstable | ❌ Not recommended |
7. Network Troubleshooting
▶ Example: iperf Network Bandwidth Test (Difficulty: ⭐⭐⭐)
BASH
# Start iperf3 server in a container
docker run -d --name iperf-server --network host networkstatic/iperf3 -s
# Run iperf3 client from another container
docker run --rm --network host networkstatic/iperf3 -c localhost -t 10
# Test between two containers on different networks
docker run --rm --network app-net networkstatic/iperf3 -c db -t 5
▶ Example: Docker Events Event Tracing (Difficulty: ⭐⭐)
BASH
# Monitor container lifecycle events
docker events --filter type=container
# Filter for specific events
docker events --filter event=oom --filter event=die --filter event=restart
# Time-based filter
docker events --since "2024-01-15T03:00:00" --until "2024-01-15T04:00:00"
8. Advanced Debugging: nsenter
▶ Example: nsenter to enter a container namespace (Difficulty: ⭐⭐⭐)
BASH
# Get container's main PID
PID=$(docker inspect --format='{{.State.Pid}}' myapp)
# Enter the container's network namespace for debugging
nsenter -t $PID -n tcpdump -i eth0 -c 100 port 8080
# Enter the container's process namespace
nsenter -t $PID -p -m strace -p 1
💡 Tip: nsenter operates at a lower level than
docker exec—it enters the container’s Linux namespace directly, without requiring a shell inside the container. It’s suitable for debugging scratch or distroless images.
9. Troubleshooting Guide: Common Problems and Solutions
| Symptom | Troubleshooting Command | Common Causes | Solution |
|---|---|---|---|
| Frequent container restarts | docker ps -a + docker logs |
OOM / Application crashes | Increase memory / Fix bugs / Restart policy |
| Disk space full | docker system df -v |
Logs/images/volumes piling up | docker system prune + Log rotation |
| Network connection timed out | docker exec ping + nc |
Network configuration error | Check network/DNS/port |
| Slow Build | docker build --progress=plain |
Cache Expired | Adjust COPY Order |
| Container startup failed | docker logs + docker inspect |
Configuration error/missing dependencies | Fix configuration/check dependencies |
| High IO Wait | iostat -x |
Log driver/heavy writes | Switch log driver/optimize writes |
10. Complete Example: Troubleshooting and Resolving Container OOM Issues
BASH
# ============================================
# Complete walkthrough: OOM diagnosis and fix
# Covers: stats, events, logs, inspect, fix
# ============================================
# 1. Deploy the problematic container
docker run -d \
--name leaky-app \
--memory=100m \
--restart=on-failure:5 \
-p 8080:8080 \
myapp:1.0
# 2. Monitor resource usage
docker stats leaky-app --no-stream
# 3. Simulate memory leak (trigger OOM)
docker exec leaky-app python -c "
import itertools
data = []
for i in itertools.count():
data.append('x' * 1024 * 1024) # 1 MB each
if i % 10 == 0:
import time; time.sleep(0.1)
"
# 4. Capture OOM event
docker events --filter container=leaky-app --filter event=oom --since 1m
# 5. Check exit code and OOM status
docker inspect leaky-app --format='
ExitCode: {{.State.ExitCode}}
OOMKilled: {{.State.OOMKilled}}
Memory Limit: {{.HostConfig.Memory}}
'
# 6. Check application logs for memory patterns
docker logs --tail 100 leaky-app 2>&1 | grep -i "memory\|alloc\|oom"
# 7. Fix: increase memory limit
docker stop leaky-app && docker rm leaky-app
docker run -d \
--name leaky-app \
--memory=512m \
--restart=on-failure:5 \
--log-opt max-size=10m \
--log-opt max-file=3 \
-p 8080:8080 \
myapp:1.0
# 8. Set up monitoring alert
docker events --filter event=oom | while read event; do
echo "ALERT: OOM detected at $(date)" >> /var/log/docker-alerts.log
done
❓ FAQ
Q How do you troubleshoot container performance issues in a layered approach?
A A four-step method: ① Use
docker stats to view an overview of CPU, memory, and I/O; ② Select the appropriate tool based on the highest metric (CPU → top, memory → smem, I/O → iostat, network → iperf); ③ Pinpoint the specific container or process; ④ Analyze application logs to find the root cause.Q Which is better, overlay2 or aufs?
A overlay2 is better; it is Docker’s default and only recommended storage driver. aufs has been deprecated and is no longer supported in Docker 24 and later. overlay2 offers better performance, a simpler implementation, and more active community support.
Q How do I free up space when a container’s disk is full?
A
docker system df -v Check what’s taking up the most space → Clean up accordingly: ① Images: docker image prune -a; ② Build cache: docker builder prune; ③ Containers: docker container prune; ④ Volumes: docker volume prune (Proceed with caution—this will delete data); ⑤ All: docker system prune -a.Q How do I troubleshoot slow container I/O?
A ①
docker stats Check the BlockIO column; ② On the host iostat -x 1, check %util and await; ③ docker system df -v Check storage driver usage; ④ Common causes: the log driver has filled the disk, too many overlay2 layers, or a bind mount to a slow disk.Q How do I test network latency for containers?
A Use iperf3: server container
iperf3 -s, client container iperf3 -c server. Test throughput and latency. To test between containers, they must be on the same network or use the --network host option.📖 Summary
- Performance Troubleshooting Decision Tree: CPU → Memory → I/O → Network; troubleshoot layer by layer
docker statsReal-time monitoring,docker system dfDisk analysis- OOM troubleshooting: Use
docker eventsandinspectto verify the issue, then increase memory or fix the application - Disk Cleanup:
docker system pruneOne-click cleanup, log rotation to prevent accumulation - overlay2 is the only recommended storage driver
- nsenter: Enter the container namespace for advanced debugging
📝 Exercises
- Basic Exercise (Difficulty ⭐): Use the
stresscontainer to simulate CPU load, and usedocker statsto monitor changes in CPU usage. - Advanced Exercise (Difficulty ⭐⭐): Use
docker system df -vto analyze disk usage, rundocker system prune -ato clean up, and compare the difference in disk space before and after the cleanup. - Challenge (Difficulty: ⭐⭐⭐): Use iperf3 to test the network bandwidth between two containers and compare the performance differences between bridge networks and host networks.



