名称: container-debug
描述: 调试正在运行的 Docker 容器和 Compose 服务。适用于检查容器日志、进入运行中的容器、诊断网络问题、检查资源使用情况、调试多阶段构建、排查健康检查问题或修复 Compose 服务依赖关系。
元数据: {"clawdbot":{"emoji":"🐳","requires":{"bins":["docker"]},"os":["linux","darwin","win32"]}}
调试正在运行的 Docker 容器和 Compose 服务。涵盖日志查看、命令执行、网络检查、资源监控、多阶段构建、健康检查以及常见故障模式。
# 查看最后 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
# 分离 stdout 和 stderr 输出
docker logs my-container > stdout.log 2> stderr.log
# 检查容器使用的日志驱动
docker inspect --format='{{.HostConfig.LogConfig.Type}}' my-container
# 如果使用 json-file 驱动,查找实际的日志文件
docker inspect --format='{{.LogPath}}' my-container
# 检查日志文件大小
ls -lh $(docker inspect --format='{{.LogPath}}' my-container)
# 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
# 容器已退出?检查退出码
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
# 使用 docker cp 提取文件
docker cp my-container:/app/config.json ./
# 使用 nsenter 进入容器的命名空间(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
# 显示容器 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
# 从容器 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
# 容器间出现“连接被拒绝”
# 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” 可以相互解析
# 在容器内使用 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
# 所有容器
docker stats
# 特定容器
docker stats api db redis
# 单次快照(非流式)
docker stats --no-stream
# 格式化输出
docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}"
# 检查内存限制
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_in_bytes
# 容器内进程内存使用
docker exec my-container ps aux --sort=-%mem | head -10
docker exec my-container top -bn1
# 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/
# 构建到特定阶段
docker build --target builder -t my-app: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 .
# 显示镜像层(每层大小)
docker history my-image
docker history --no-trunc my-image
# 检查镜像配置(入口点、命令、环境变量、端口)
docker inspect my-image | jq '.[0].Config | {Cmd, Entrypoint, Env, ExposedPorts, WorkingDir}'
# 比较两个镜像
docker history image-a --format "{{.Size}}\t{{.CreatedBy}}" > layers-a.txt
docker history image-b --format "{{.Size}}\t{{.CreatedBy}}" > layers-b.txt
diff layers-a.txt layers-b.txt
# 查找构建间的变化
docker diff my-container
# A = 添加,C = 更改,D = 删除
# 在 Dockerfile 中
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1
# 检查健康状态
docker inspect --format='{{.State.Health.Status}}' my-container
# "healthy"、"unhealthy" 或 "starting"
# 查看健康检查日志(最近 5 次结果)
docker inspect --format='{{json .State.Health}}' my-container | jq
# 手动运行健康检查
docker exec my-container curl -f http://localhost:8080/health
# 运行时覆盖健康检查
docker run --health-cmd "curl -f http://localhost:8080/health || exit 1" \
--health-interval 10s my-image
# 禁用健康检查
docker run --no-healthcheck my-image
# 检查服务状态
docker compose ps
# 查看服务失败原因
docker compose logs failed-service
# 启动时显示详细输出
docker compose up --build 2>&1 | tee compose.log
# 启动单个服务(包含依赖)
docker compose up db
# 启动时不包含依赖服务
docker compose up --no-deps api
# 从头重新创建容器
docker compose up --force-recreate --build
# 检查生效的配置(变量替换后)
docker compose config
# docker-compose.yml
services:
api:
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
db:
image: postgres:16
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 5s
timeout: 5s
retries: 5
redis:
image: redis:7
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 5s
retries: 5
# 在运行命令前等待服务变为健康状态
docker compose up -d db
docker compose exec db pg_isready # 轮询直到就绪
docker compose up -d api
# 移除已停止的容器
docker container prune
# 移除未使用的镜像
docker image prune
# 移除所有未使用的资源(容器、镜像、网络、卷)
docker system prune -a
# 同时移除卷(警告:会删除数据)
docker system prune -a --volumes
# 移除悬空的构建缓存
docker builder prune
docker logs -f 是首要检查项。大多数容器故障在日志中可见。0.0.0.0,而非 127.0.0.1。容器内的 localhost 是隔离的。bridge 网络不行。多容器设置应始终创建自定义网络。docker exec 仅适用于运行中的容器。对于已崩溃的容器,使用 docker cp 提取日志或用 docker run --entrypoint sh 覆盖入口点。nicolaka/netshoot 是容器网络调试的瑞士军刀,预装了所有网络工具。--progress=plain 显示完整的命令输出,这对调试构建失败至关重要。start-period 的健康检查可防止应用启动缓慢时出现错误的“不健康”状态。