Docker: 性能调优与故障排查
最后更新:2026-08-26
生产环境容器出了问题——CPU 高?内存爆?IO 慢?你需要一套系统化的排查方法。
1. 你将学到
- 性能瓶颈定位方法
- 常见故障场景与根因
- 容器调试工具链
- 网络延迟排查
- 磁盘空间管理
2. 一个凌晨告警的故事
(1) 痛点:API 延迟从 50ms 飙到 5s
生产环境 API 延迟从 50ms 飙升到 5s,用户大量投诉。Alice 用 docker stats 发现 CPU 没爆但 IO 等待极高,容器像"卡住了"一样。
(2) 系统化排查的解法
Alice 用 iostat 定位到日志驱动把磁盘 IO 打满了,切换日志驱动后恢复。
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) 收益:5s→50ms,10 分钟恢复
从告警到修复只用了 10 分钟——系统化排查比"重启试试"高效 100 倍。
3. 性能排查决策树
(1) 四大瓶颈与对应工具
graph TB
START["Performance Issue"] --> CPU{"CPU 高?"}
CPU -->|Yes| C1["docker stats<br/>top / htop"]
CPU -->|No| MEM{"内存高?"}
MEM -->|Yes| M1["docker stats<br/>/proc/meminfo"]
MEM -->|No| IO{"IO 等待高?"}
IO -->|Yes| I1["iostat -x<br/>docker system df"]
IO -->|No| NET{"网络慢?"}
NET -->|Yes| N1["iperf / ping<br/>tcpdump"]
(2) 常用排查工具
| 工具 | 作用 | 场景 |
|---|---|---|
docker stats |
容器资源使用 | CPU/内存/IO 概览 |
docker system df |
Docker 磁盘占用 | 磁盘满排查 |
docker events |
容器事件流 | OOM/重启/异常退出 |
docker logs |
容器日志 | 应用错误 |
docker inspect |
容器配置 | 状态/退出码/网络 |
iostat |
磁盘 IO 统计 | IO 瓶颈 |
iperf |
网络带宽测试 | 网络瓶颈 |
nsenter |
进入容器命名空间 | 高级调试 |
4. CPU 瓶颈排查
▶ 示例:docker stats 监控资源(难度⭐)
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}}"
▶ 示例:stress 容器模拟 CPU 压力(难度⭐⭐)
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. 内存瓶颈排查
(1) 常见内存问题
| 现象 | 退出码 | 原因 | 解决 |
|---|---|---|---|
| OOM Kill | 137 | 超过 --memory 限制 | 增大限制或优化内存使用 |
| 内存泄漏 | 逐渐增长 | 应用 bug | 分析 heap dump |
| 缓存占用高 | 0 | 文件系统缓存 | 正常行为(可回收) |
▶ 示例:模拟容器 OOM(难度⭐⭐⭐)
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. 磁盘 IO 瓶颈排查
▶ 示例:docker system df 磁盘分析(难度⭐⭐)
BASH
# Show Docker disk usage
docker system df
# Detailed breakdown
docker system df -v
💻 输出:
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%)
▶ 示例:磁盘清理策略(难度⭐⭐)
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) 存储驱动对比
| 驱动 | 性能 | 稳定性 | 推荐 |
|---|---|---|---|
| overlay2 | 高 | ✅ 稳定 | ✅ 默认推荐 |
| aufs | 中 | ⚠️ 旧内核 | ❌ 已弃用 |
| devicemapper | 低 | ⚠️ 配置复杂 | ❌ 不推荐 |
| zfs | 中 | ✅ 稳定 | 特定场景 |
| btrfs | 中 | ⚠️ 不稳定 | ❌ 不推荐 |
7. 网络排查
▶ 示例:iperf 网络带宽测试(难度⭐⭐⭐)
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
▶ 示例:docker events 事件追踪(难度⭐⭐)
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. 高级调试:nsenter
▶ 示例:nsenter 进入容器命名空间(难度⭐⭐⭐)
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
💡 提示: nsenter 比 docker exec 更底层——它直接进入容器的 Linux namespace,不需要容器内有 shell。适合调试 scratch/distroless 镜像。
9. 常见故障与解决对照表
| 故障现象 | 排查命令 | 常见根因 | 解决方法 |
|---|---|---|---|
| 容器频繁重启 | docker ps -a + docker logs |
OOM / 应用崩溃 | 增大内存 / 修复 bug / restart 策略 |
| 磁盘空间满 | docker system df -v |
日志/镜像/卷堆积 | docker system prune + 日志轮转 |
| 网络连接超时 | docker exec ping + nc |
网络配置错误 | 检查网络/DNS/端口 |
| 构建缓慢 | docker build --progress=plain |
缓存失效 | 调整 COPY 顺序 |
| 容器启动失败 | docker logs + docker inspect |
配置错误/依赖缺失 | 修复配置/检查依赖 |
| IO 等待高 | iostat -x |
日志驱动/大量写入 | 切换日志驱动/优化写入 |
10. 完整示例:容器 OOM 排查与修复
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
❓ 常见问题
Q 容器性能问题怎么分层排查?
A 四步法:① docker stats 看 CPU/内存/IO 概览;② 根据最高指标选工具(CPU→top,内存→smem,IO→iostat,网络→iperf);③ 定位到具体容器/进程;④ 分析应用日志找根因。
Q overlay2 和 aufs 哪个好?
A overlay2 更好,是 Docker 默认和唯一推荐的存储驱动。aufs 已弃用,Docker 24+ 不再支持。overlay2 性能更好、实现更简单、社区支持更活跃。
Q 容器磁盘空间满了怎么清理?
A
docker system df -v 看什么占最多 → 对应清理:① 镜像:docker image prune -a;② 构建缓存:docker builder prune;③ 容器:docker container prune;④ 卷:docker volume prune(谨慎,会删除数据);⑤ 全部:docker system prune -a。Q 容器 IO 慢怎么排查?
A ①
docker stats 看 BlockIO 列;② 主机 iostat -x 1 看 %util 和 await;③ docker system df -v 看存储驱动占用;④ 常见原因:日志驱动写满磁盘、overlay2 层过多、bind mount 到慢磁盘。Q 怎么给容器做网络延迟测试?
A 用 iperf3:服务端容器
iperf3 -s,客户端容器 iperf3 -c server。测试吞吐量和延迟。容器间测试需在同一网络或用 --network host。📖 小节
- 性能排查决策树:CPU→内存→IO→网络,逐层定位
docker stats实时监控,docker system df磁盘分析- OOM 排查:docker events + inspect 确认,增大内存或修复应用
- 磁盘清理:
docker system prune一键回收,日志轮转防堆积 - overlay2 是唯一推荐的存储驱动
- nsenter 进入容器命名空间进行高级调试
📝 作业
- 基础题(难度⭐):用 stress 容器模拟 CPU 压力,用
docker stats监控 CPU 使用率变化。 - 进阶题(难度⭐⭐):用
docker system df -v分析磁盘占用,执行docker system prune -a清理,对比清理前后的空间差异。 - 挑战题(难度⭐⭐⭐):用 iperf3 测试两个容器间的网络带宽,对比 bridge 网络和 host 网络的性能差异。