容器调试
调试运行中的Docker容器和Compose服务。涵盖日志、exec、网络、资源检查、多阶段构建、健康检查和常见故障模式。
何时使用
- - 容器立即退出或启动时崩溃
- 容器内的应用程序行为与宿主机不同
- 容器之间无法通信
- 容器占用过多内存或CPU
- 多阶段Docker构建产生意外结果
- 健康检查失败
- Compose服务启动顺序错误或无法连接
容器日志
查看和过滤日志
bash
最后100行
docker logs --tail 100 my-container
实时跟踪(流式)
docker logs -f my-container
带时间戳实时跟踪
docker logs -f -t my-container
从某个时间点开始的日志
docker logs --since 30m my-container
docker logs --since 2026-02-03T10:00:00 my-container
两个时间点之间的日志
docker logs --since 1h --until 30m my-container
Compose:所有服务的日志
docker compose logs -f
Compose:特定服务的日志
docker compose logs -f api db
将日志重定向到文件进行分析
docker logs my-container > container.log 2>&1
分离标准输出和标准错误
docker logs my-container > stdout.log 2> stderr.log
检查日志驱动
bash
检查容器使用的日志驱动
docker inspect --format={{.HostConfig.LogConfig.Type}} my-container
如果是json-file驱动,查找实际日志文件
docker inspect --format={{.LogPath}} my-container
检查日志文件大小
ls -lh $(docker inspect --format={{.LogPath}} my-container)
进入容器执行命令
交互式Shell
bash
Bash(最常见)
docker exec -it my-container bash
如果没有bash(Alpine、distroless镜像)
docker exec -it my-container sh
以root身份(即使容器以非root用户运行)
docker exec -u root -it my-container bash
带特定环境变量
docker exec -e DEBUG=1 -it my-container bash
执行单个命令(无交互式Shell)
docker exec my-container cat /etc/os-release
docker exec my-container ls -la /app/
docker exec my-container env
调试崩溃的容器
bash
容器已退出?检查退出码
docker inspect --format={{.State.ExitCode}} my-container
docker inspect --format={{.State.Error}} my-container
常见退出码:
0 = 正常退出
1 = 应用程序错误
137 = 被杀死(OOM或docker kill)— 128 + 信号9
139 = 段错误 — 128 + 信号11
143 = 终止(SIGTERM)— 128 + 信号15
启动已停止的容器进行调试
docker start -ai my-container
或者覆盖入口点以获取Shell
docker run -it --entrypoint sh my-image
从已停止的容器中复制文件
docker cp my-container:/app/error.log ./error.log
docker cp my-container:/etc/nginx/nginx.conf ./nginx.conf
无Shell调试(distroless / scratch镜像)
bash
使用docker cp提取文件
docker cp my-container:/app/config.json ./
使用nsenter在容器命名空间中获取Shell(Linux)
PID=$(docker inspect --format={{.State.Pid}} my-container)
nsenter -t $PID -m -u -i -n -p -- /bin/sh
将调试容器附加到同一命名空间
docker run -it --pid=container:my-container --net=container:my-container busybox sh
Docker Desktop:使用调试扩展
docker debug my-container
网络
检查容器网络
bash
显示容器IP地址
docker inspect -f {{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}} my-container
显示所有网络详情
docker inspect -f {{json .NetworkSettings.Networks}} my-container | jq
列出所有网络
docker network ls
检查网络(查看所有连接的容器)
docker network inspect bridge
docker network inspect my-compose-network
显示端口映射
docker port my-container
测试容器间连接
bash
从容器A内部,访问容器B
docker exec container-a ping container-b
docker exec container-a curl http://container-b:8080/health
容器内DNS解析
docker exec my-container nslookup db
docker exec my-container cat /etc/resolv.conf
docker exec my-container cat /etc/hosts
测试端口是否可达
docker exec my-container nc -zv db 5432
docker exec my-container wget -qO- http://api:3000/health
如果容器内没有curl/ping,安装或使用调试容器:
docker run --rm --network container:my-container curlimages/curl curl -s http://localhost:8080
常见网络问题
bash
容器间连接被拒绝
1. 检查应用程序绑定到0.0.0.0,而不是127.0.0.1
docker exec my-container netstat -tlnp
如果监听在127.0.0.1 — 修复应用程序配置
2. 检查容器是否在同一网络
docker inspect -f {{json .NetworkSettings.Networks}} container-a | jq keys
docker inspect -f {{json .NetworkSettings.Networks}} container-b | jq keys
3. 检查发布端口与暴露端口
EXPOSE仅用于文档说明,不会实际发布端口
使用 -p 宿主机端口:容器端口 来发布
名称未找到 — DNS无法解析容器名称
容器名称仅在用户定义的网络上解析,不在默认的bridge网络上
docker network create my-net
docker run --network my-net --name api my-api-image
docker run --network my-net --name db postgres
现在api和db可以互相解析
捕获网络流量
bash
在容器内使用tcpdump
docker exec my-container tcpdump -i eth0 -n port 8080
如果没有tcpdump,使用sidecar容器
docker run --rm --net=container:my-container nicolaka/netshoot tcpdump -i eth0 -n
netshoot包含:tcpdump、curl、nslookup、netstat、iperf等
docker run --rm --net=container:my-container nicolaka/netshoot bash
资源使用
实时统计
bash
所有容器
docker stats
特定容器
docker stats api db redis
一次性(不流式)
docker stats --no-stream
格式化输出
docker stats --format table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}
内存调查
bash
检查内存限制
docker inspect --format={{.HostConfig.Memory}} my-container
0表示无限制
检查容器是否被OOM杀死
docker inspect --format={{.State.OOMKilled}} my-container
内存使用明细(Linux cgroups)
docker exec my-container cat /sys/fs/cgroup/memory.current 2>/dev/null || \
docker exec my-container cat /sys/fs/cgroup/memory/memory.usage
inbytes
容器内进程内存
docker exec my-container ps aux --sort=-%mem | head -10
docker exec my-container top -bn1
磁盘使用
bash
总体Docker磁盘使用
docker system df
docker system df -v
容器文件系统大小
docker inspect --format={{.SizeRw}} my-container
查找容器内的大文件
docker exec my-container du -sh /* 2>/dev/null | sort -rh | head -10
docker exec my-container find /tmp -size +10M -type f
检查日志文件膨胀
docker exec my-container ls -lh /var/log/
Dockerfile调试
多阶段构建调试
bash
构建到特定阶段
docker build --target builder -t my-app:builder .
检查builder阶段的内容
docker run --rm -it my-app:builder sh
docker run --rm my-app:builder ls -la /app/
docker run --rm my-app:builder cat /app/package.json
检查哪些文件进入了最终镜像
docker run --rm my-image ls -laR /app/
不使用缓存构建(全新构建)
docker build --no-cache -t my-app .
带进度输出构建
docker build --progress=plain -t my-app .
镜像检查
bash