5911 字
30 分钟
Docker 常用命令速查与排障实战
2026-11-15

装好 Docker、把服务跑起来之后,日常打交道最多的其实不是写配置,而是查状态、看日志、找问题。容器起不来先敲什么?磁盘满了是谁吃的?端口冲突怎么定位?这一篇就是干这个的:前半部分是按场景整理的命令速查表,后半部分是五条最常见的排障实战链路。建议收藏,出问题时按图索骥即可。

前置阅读:还没装 Docker 的先看 《如何在Linux部署Docker&Compose》;本文所有命令默认你已经能正常执行 docker 命令(在 Docker 组里或用 sudo)。

先记住一条贯穿全文的万能起手式,任何容器出问题都先走这三连:

Terminal window
docker ps -a # 1. 它到底是什么状态?(Exited?Restarting?Up?)
docker logs <容器名> # 2. 它自己说了什么?(应用日志九成能定位)
docker inspect <容器名> # 3. 它的配置和死因是什么?(退出码、挂载、端口)

三连走完还没头绪,再翻到本文后面的排障实战部分对号入座。

容器类命令速查#

容器是每天操作最多的对象。先看状态类:

命令作用备注
docker ps列出正在运行的容器最常用,没有之一
docker ps -a列出全部容器(含已退出)容器「消失了」先用它找,多半是退出了
docker ps -a -q只输出容器 ID配合批量操作,如 docker rm $(docker ps -a -q)
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"自定义输出列嫌默认列太宽时用
docker start <容器名>启动已存在的容器和 run 不同,start 不新建容器
docker stop <容器名>优雅停止(先 SIGTERM,超时后 SIGKILL)默认等 10 秒,可用 -t 30 改等待时长
docker restart <容器名>重启容器改了挂载文件、想让应用重读配置时用
docker kill <容器名>直接 SIGKILL 强杀stop 不动时再用,会丢未落盘数据
docker rm <容器名>删除已停止的容器运行中的要先 stop,或 rm -f 强删(慎用)
docker rename <旧名> <新名>给容器改名不用重建容器就能改

docker run 的参数组合太多,单独拉一张表,这是实际最常用的几个:

参数组合作用备注
docker run -d --name app nginx后台运行并命名-d 是 detach,不加会占住终端
docker run -d --restart unless-stopped ...宿主机重启后自动拉起服务器部署必加;always 与它的区别是手动 stop 后开机是否还拉起
docker run -p 8080:80 ...端口映射 宿主机:容器只想本机访问写 -p 127.0.0.1:8080:80,更安全
docker run -v /宿主机目录:/容器目录 ...绑定挂载目录配置、数据持久化都靠它
docker run -e TZ=Asia/Shanghai ...传环境变量时区、密码类配置常用
docker run --rm -it ubuntu bash退出即删,进交互终端临时测试镜像时用,不留垃圾
docker run -it --entrypoint sh <镜像>覆盖入口点进 shell 排查镜像起不来、想进去看看文件时用

进容器和传文件:

命令作用备注
docker exec -it <容器名> bash进正在运行的容器开终端没有 bash 的精简镜像换 sh
docker exec <容器名> <命令>不进终端、直接在容器里执行一条命令脚本里常用,如 docker exec db pg_isready
docker cp <容器名>:/路径 /宿主机路径从容器里拷文件出来拷日志、拷配置出来看很方便
docker cp /宿主机路径 <容器名>:/路径把文件拷进容器临时塞个配置文件进去测试
docker logs -f --tail 100 <容器名>实时追踪最近 100 行日志日志的完整用法见日志管理专篇,这里只列最常用的一条
docker update --restart unless-stopped <容器名>不重建容器、直接改它的重启策略老容器当年忘了加 --restart,用它补,不用删了重建
docker update --memory 512m --cpus 1 <容器名>动态调整资源上限临时救急可以,长期还是写回 compose 文件
TIP

容器名和容器 ID 可以混用,ID 只写前几位能唯一匹配即可。但脚本里强烈建议用容器名,可读性好得多。前提是部署时都用 --name 或 compose 的 container_name 起好名字,别用系统随机生成的那串单词。

镜像类命令速查#

命令作用备注
docker images列出本机镜像看 TAG 和 SIZE,排查磁盘占用先看它
docker pull nginx:1.27拉取指定版本镜像务必带版本号,别无脑 latest
docker tag <旧标签> <新标签>给镜像多打一个标签推送到自己仓库前必须先 tag 成仓库地址格式
docker rmi <镜像>删除镜像有容器在用(哪怕已停止)会拒绝,先删容器
docker history <镜像>看镜像每一层是怎么来的、多大排查「镜像为什么这么大」
docker inspect <镜像>看镜像的完整元数据重点看 Entrypoint、Cmd、ExposedPorts、Env
docker build -t myapp:1.0 .用当前目录 Dockerfile 构建镜像打包自己的应用时用
docker save -o app.tar myapp:1.0把镜像导出成 tar 文件离线搬运、无外网环境传镜像
docker load -i app.tar从 tar 文件导入镜像与 save 配对使用
docker image prune删除悬空镜像(<none> 那些)安全,只清构建/更新留下的无标签残层

离线搬运的完整流程(A 机导出、U盘/内网传过去、B 机导入):

Terminal window
# A 机:导出
docker save -o myapp-1.0.tar myapp:1.0
# B 机:导入,镜像名和标签原样恢复
docker load -i myapp-1.0.tar
docker images | grep myapp
WARNING

docker save/load 搬的是镜像,不包含容器里的数据卷。要搬整个服务(含数据),正确做法是:save 镜像 + 单独打包数据卷目录 + 带上 compose 文件,到目标机先恢复数据再 docker compose up -d。只 save 镜像过去,数据库数据是不会跟着走的。

docker inspect 精讲#

docker inspect 输出一大坨 JSON,是排查时信息量最大的命令。直接看全量输出太累,记住下面几个最常看的字段和 --format 取值写法就够了。

整体结构里最常翻的四块:

字段路径看什么典型用途
.State.Status / .State.ExitCode / .State.OOMKilled运行状态、退出码、是否被内存杀手干掉容器退出第一时间看这里
.NetworkSettings.Ports端口映射实际生效情况写了 -p 却访问不了,先确认映射在不在
.NetworkSettings.IPAddress容器在默认 bridge 上的 IP自定义网络下要看 .NetworkSettings.Networks 里对应网络
.Mounts数据卷/绑定挂载的源和目标「我改了宿主机文件容器里没变」多半是挂载路径写错
.Config.Env容器实际拿到的环境变量密码、时区没生效,先看这里是不是传进去了
.HostConfig.RestartPolicy重启策略容器开机没自启,看它是不是 no

用 --format 只取想要的值,输出干净利落:

Terminal window
# 取容器 IP(默认 bridge)
docker inspect -f '{{.NetworkSettings.IPAddress}}' <容器名>
# 取退出码和状态,一行说清死因
docker inspect -f '{{.State.Status}} exit={{.State.ExitCode}} oom={{.State.OOMKilled}}' <容器名>
# 取自定义网络下的 IP(网络名换成自己的)
docker inspect -f '{{index .NetworkSettings.Networks "mynet" "IPAddress"}}' <容器名>
# 列出全部挂载:源 -> 目标
docker inspect -f '{{range .Mounts}}{{.Source}} -> {{.Destination}}{{"\n"}}{{end}}' <容器名>
# 看重启策略
docker inspect -f '{{.HostConfig.RestartPolicy.Name}}' <容器名>
TIP

查 JSON 字段还有个笨办法但很稳:docker inspect <容器名> | grep -A2 -B2 关键词。比如想不起来 IP 字段在哪,就 grep IPAddress。先解决问题,再慢慢记字段路径。

资源与状态命令#

服务跑久了要回答三个问题:谁在吃 CPU/内存?磁盘被谁占了?刚才发生了什么事?对应四组命令:

命令作用备注
docker stats实时滚动显示所有容器的 CPU、内存、网络、磁盘 IO像 top 一样常驻,按 Ctrl+C 退出
docker stats --no-stream只输出一次当前资源占用脚本采集、快速看一眼时用
docker stats <容器名>只看指定容器怀疑某个容器吃资源时锁定它
docker top <容器名>看容器里到底有哪些进程等于在宿主机视角看容器的进程树
docker events实时事件流:容器启停、死亡、镜像拉取等排查「容器半夜自己重启了」时回放时间线(可加 --since 1h)
docker system df汇总镜像、容器、数据卷、构建缓存各占多少磁盘磁盘排查的起点
docker system df -v详细列出每个镜像/卷各占多少找出具体是哪个卷/镜像在膨胀
Terminal window
# 一次性看所有容器资源,按内存从大到小排个序(配合 sort)
docker stats --no-stream --format "table {{.Name}}\t{{.MemPerc}}\t{{.MemUsage}}"
# 看最近 2 小时内所有容器的死亡和重启事件
docker events --since 2h --filter event=die --filter event=restart
# 磁盘总账
docker system df
# 典型输出:
# TYPE TOTAL ACTIVE SIZE RECLAIMABLE
# Images 23 8 6.2GB 3.1GB (50%)
# Containers 10 9 120MB 0B
# Local Volumes 6 4 18GB 2GB (11%)
# Build Cache 15 0 800MB 800MB

docker system df 只告诉你「哪一类」占得多,真要定位到具体目录,接着用宿主机的 du:

Terminal window
# Docker 的全部家当都在这里,按子目录看大小
sudo du -h --max-depth=1 /var/lib/docker | sort -hr | head
# 容器日志单独有多大(日志爆磁盘的头号嫌疑人)
sudo du -sh /var/lib/docker/containers/*/*-json.log | sort -hr | head

网络与数据卷常用命令#

这两类平时动得少,出问题时容易手生,各备一小表。

网络:

命令作用备注
docker network ls列出所有网络默认有 bridge、host、none 三个
docker network inspect <网络名>看子网、网关、挂了哪些容器及其 IP容器互访不通时先看是不是在同一个网络里
docker network create mynet建自定义网络自定义网络自带 DNS,容器可按名字互访
docker network connect mynet <容器名>把运行中的容器接入某网络不用重建容器
docker network disconnect mynet <容器名>把容器从某网络断开
docker network rm mynet删除网络还有容器挂着时会拒绝

数据卷:

命令作用备注
docker volume ls列出所有数据卷那一串随机哈希名的是匿名卷
docker volume inspect <卷名>看卷的宿主机实际路径(Mountpoint)备份数据就是去打包这个目录
docker volume create mydata建命名卷重要数据一律用命名卷,别用匿名卷
docker volume rm <卷名>删除卷数据真删,不可恢复,见下方警告
docker volume prune删除所有未被容器使用的卷同样危险,老版本 Docker 无确认提示
WARNING

数据卷相关的删除命令是整个 Docker 里最不可逆的操作:docker volume rm 和 docker volume prune 删的是真实数据目录,没有回收站。删之前务必先 docker volume inspect 确认 Mountpoint、把数据打包备份一份,再动手。生产环境的数据库卷,看到名字先停手三秒。

Compose 常用命令速查#

实际部署大多用 Compose,它的命令和原生 docker 命令是两套,排障时经常混着用,这里单独备一表(在 Compose 文件所在目录执行):

命令作用备注
docker compose up -d按文件创建并启动全部服务改了配置再执行一次,它只重建有变化的服务
docker compose ps看本项目的容器状态比 docker ps 多一列 SERVICE,定位更快
docker compose logs -f <服务名>追踪某个服务的日志不写服务名是全部服务混在一起看
docker compose down停掉并删除本项目容器和网络不加 -v 不会删数据卷;加了 -v 连卷一起删,慎用
docker compose restart <服务名>只重启某个服务改了挂载的配置文件时常用
docker compose exec <服务名> sh进某个服务的容器和 docker exec 等效,但用服务名不用记容器名
docker compose pull批量拉取文件里所有镜像的新版配合 up -d 就是手动更新全套服务
docker compose config把最终生效的配置打印出来检查变量替换、多文件合并的结果都以它为准,排障神器
TIP

Compose 排障有个高频误会:改了 Compose 文件后直接 docker compose restart 没效果——restart 只是重启旧容器,不会按新配置重建。改配置(端口、环境变量、挂载)后必须 docker compose up -d,它会发现差异并重建对应服务。

清理命令与红线#

磁盘紧张时要清理,但 Docker 的清理命令威力分级很陡,必须先看再清、从轻到重:

命令清什么危险程度
docker image prune只清悬空镜像(无标签、无容器引用)低,放心用
docker image prune -a清所有未被容器使用的镜像中:下次启动要重新拉取,离线环境慎用
docker container prune清所有已停止的容器中:停止的容器如果还想 start 回来,先别清
docker builder prune清构建缓存低,经常 build 的机器能清出不少
docker volume prune清未被使用的卷高:删真实数据,见上一节警告
docker system prune组合清:停止的容器 + 悬空镜像 + 无用网络中高,用前看清提示里列的清单
docker system prune -a --volumes上面全部 + 所有未用镜像 + 所有未用卷极高,新手禁用

正确的清理姿势是三步走:

Terminal window
docker system df # 第一步:先看账,哪类占得多、能回收多少
docker image prune # 第二步:只清最安全的悬空镜像
docker system df # 第三步:复查效果,不够再考虑下一档
WARNING

红线:绝不要把 docker system prune -a 当日常命令随手敲。 它会删掉所有当前没有容器在用的镜像——包括你特意保留的旧版本镜像、离线 save 进来的镜像、暂时停掉准备回滚的版本。网上很多「Docker 清理教程」上来就教这条,在单机玩票环境无所谓,在装了正经服务的服务器上敲一次,轻则全站重新拉镜像断网半小时,重则配合 --volumes 把数据库数据一起送走。清理永远从 docker system df 开始,按需逐项清。

排障实战一:容器启动即退出#

症状:docker compose up -d 显示 Started,但 docker ps 里找不到,过一会儿 docker ps -a 里状态是 Exited (x)。

第一步看什么:日志和退出码,两个命令定生死:

Terminal window
docker logs <容器名> # 应用自己报的错,九成在这里
docker inspect -f '{{.State.ExitCode}}' <容器名>

退出码含义速查:

退出码含义常见根因
0正常结束不是故障:程序本身就是一次性的,或者主进程干完活自己退了
1通用错误应用层报错:配置写错、连不上数据库、文件不存在,看 logs
2参数/用法错误启动命令参数写错、shell 脚本语法问题
126命令不可执行入口脚本没有执行权限(chmod +x 没做)、或不是可执行文件
127命令不存在Cmd/Entrypoint 里写的程序镜像里根本没有,如精简镜像里调用 bash
137被 SIGKILL 强杀头号嫌疑是 OOM(内存爆了被内核杀),用 inspect 看 OOMKilled 是否为 true
143收到 SIGTERM 后退出有人/有程序执行了 stop,或宿主机在关机流程里,这不算异常

定位链路:

Terminal window
# 1. 先看日志最后 50 行
docker logs --tail 50 <容器名>
# 2. 确认是不是 OOM
docker inspect -f '{{.State.OOMKilled}}' <容器名> # true 就是内存不够被杀
# 3. 怀疑镜像本身有问题:覆盖入口点进去看
docker run --rm -it --entrypoint sh <镜像名>
ls /app # 看文件在不在
./start.sh # 手动执行启动脚本,看它当场报什么错

常见根因汇总:

常见根因说明
配置文件路径写错挂载没生效
数据库还没起来应用先连了Compose 里加 healthcheck + depends_on 的 condition
脚本是 Windows 换行符\r 会让 shebang 失效,报错很隐蔽,用 dos2unix 处理
数据目录权限不对容器内非 root 用户写不进挂载目录

排障实战二:容器反复 Restarting#

症状:docker ps 里状态一直是 Restarting (1) x seconds ago,或者 Up 几秒又变 Restarting,循环往复。

第一步看什么:先分清是「崩溃重启」还是「策略性重启」:

Terminal window
docker logs --tail 100 <容器名> # 看每次启动是不是同一个报错
docker inspect -f '{{.RestartCount}} 重启策略={{.HostConfig.RestartPolicy.Name}}' <容器名>

定位链路:

  1. 日志每次都是同一个错 → 本质还是「启动即退出」问题,只是 restart 策略在不停重试。按实战一的方法修根因,修好自然停。
  2. 日志没报错但就是重启 → 检查主进程是不是「假装在运行」:比如启动脚本最后用了后台运行 & 又立刻结束,Docker 认为主进程已退出,于是按策略重启。对策是让主进程前台阻塞(如 Nginx 的 daemon off;、用 tail -f /dev/null 临时顶住做验证)。
  3. Compose 里两个服务互相 depends_on → A 等 B、B 又等 A,形成循环依赖,Compose 会直接报错或行为异常。把依赖关系画出来,环上必有一条是多余的,删掉它;实在需要双向,就拆掉其中一条改用应用层重试。

常见根因:应用启动就崩(占九成)、主进程后台化、循环依赖、健康检查误杀(healthcheck 命令在精简镜像里不存在,容器被判 unhealthy 后被编排反复重建——先临时去掉 healthcheck 验证)。

临时止血:先把重启策略改掉,别让它无限刷日志:

Terminal window
docker update --restart no <容器名>
docker stop <容器名>

排障实战三:端口已被占用#

症状:启动时报 Bind for 0.0.0.0:8080 failed: port is already allocated,或者 address already in use。

第一步看什么:谁占了这个端口,一条命令见分晓:

Terminal window
sudo ss -tlnp | grep 8080
# 输出里的 users:(("nginx",pid=1234,...)) 就是占用者

定位链路:

Terminal window
# 情况 A:是另一个容器占的
docker ps --format "{{.Names}} {{.Ports}}" | grep 8080
# 处理:改其中一个的宿主机端口,如 8080 -> 8081,容器内端口不用动
# 情况 B:是宿主机上的普通进程占的(如系统自带 nginx、apache)
sudo systemctl stop nginx # 确认不再需要它,再考虑 disable
# 或者干脆给容器换个宿主机端口,互不打扰
# 情况 C:ss 查不到占用,但 Docker 还报占用
# 多半是残留的代理进程,重启 Docker 服务可解(会影响全部容器,挑低峰期)
sudo systemctl restart docker

常见根因:同一套 Compose 起了两遍(旧容器没删)、宿主机原生装的同类服务没关、别的项目图省事都用了 8080/3306 这类热门端口。养成习惯:每个服务规划固定的宿主机端口段,写进 compose 文件留档。

排障实战四:磁盘爆满#

症状:服务器磁盘 100%,容器开始报错、数据库写不进去、docker 命令本身都可能变慢或失败。

第一步看什么:先分清是 Docker 吃的还是系统其他地方吃的:

Terminal window
df -h # 哪个分区满了
docker system df # Docker 内部的账
sudo du -h --max-depth=1 /var/lib/docker | sort -hr | head # Docker 里谁最大

定位链路(Docker 场景下两大元凶):

元凶一:容器日志无限膨胀。 默认 json-file 驱动不做轮转,一个话痨容器能写出几十 GB 的日志。

Terminal window
# 找出最大的几个日志文件
sudo find /var/lib/docker/containers -name "*-json.log" -exec du -h {} + | sort -hr | head
# 应急:清空某个容器的日志文件(不要直接删文件,用 truncate)
sudo truncate -s 0 /var/lib/docker/containers/<容器ID>/<容器ID>-json.log
# 根治:给 daemon.json 配置日志轮转 max-size/max-file 后重启 Docker(只对新建容器生效,
# 存量容器要重建才吃到新配置,细节见日志管理专篇)

元凶二:镜像和构建缓存堆积。 反复更新、反复 build 的机器尤其明显。

Terminal window
docker images | wc -l # 镜像数量是否离谱
docker system df -v | head -50 # 逐个看大小
docker image prune # 先清悬空镜像
docker builder prune # 再清构建缓存

常见根因:日志没轮转(占大头)、自动更新工具没开清理旧镜像、频繁构建镜像没清缓存、数据卷里应用自己囤了大量文件(这种情况 Docker 命令清不掉,要进卷目录处理应用数据)。注意:如果 df 显示满了但 du 加起来对不上,多半是已删除但被进程占着的文件,用 sudo lsof +L1 找出来,重启对应容器即可释放。

排障实战五:容器间网络不通#

症状:应用连不上同机的数据库容器,日志里全是 Connection refused、Name or service not known 或超时。

第一步看什么:确认两个容器在不在同一个网络里,这是前提:

Terminal window
docker network inspect <网络名> | grep -A1 '"Name"' # 看成员名单
# 或者分别看两个容器挂了哪些网络
docker inspect -f '{{range $k,$v:=.NetworkSettings.Networks}}{{$k}} {{end}}' <容器名>

定位链路(按顺序逐项排除):

Terminal window
# 1. 名字解析:在应用容器里 ping 一下数据库的服务名/容器名
docker exec -it <应用容器> ping -c2 db
# 解析不了 -> 不在同一个自定义网络,或用了默认 bridge(默认 bridge 不支持按名解析)
# 2. 端口对不对:容器间互访用的是,不是映射到宿主机的端口
# 数据库容器内监听 5432,应用就连 db:5432,哪怕宿主机映射的是 15432:5432
docker exec -it <应用容器> sh -c 'wget -qO- http://api:3000/health || curl -v http://api:3000/health'
# 精简镜像没工具时,用宿主机侧验证:
docker exec <数据库容器> ss -tlnp # 确认服务真的在容器内监听了
# 3. 服务本身活没活
docker logs --tail 50 <数据库容器> # 数据库自己没起来,网络再通也没用
docker ps -a | grep db # 确认状态是 Up 不是 Exited

常见根因:两个容器不在同一网络(占多数)、连错端口(拿宿主机映射端口在容器间互访)、用默认 bridge 还指望按容器名解析、目标服务根本没启动成功、目标服务只监听了 127.0.0.1(在容器内只绑回环,同网络的其他容器也连不进,要改绑 0.0.0.0)。

WARNING

容器间通信永远记住三句话:同网络、喊名字、用容器端口。映射端口(-p)是给宿主机和外网用的,跟容器互访没关系。把这三句贴在显示器边上,这类问题能少八成。

小结#

  • 任何故障先走万能三连:docker ps -a 看状态 → docker logs 看自述 → docker inspect 看死因和配置。
  • 退出码是最快的分诊台:137 先查内存,127/126 查命令和权限,1 回日志里找应用报错。
  • 清理的铁律是先 docker system df 看账、从最安全的档位逐级清;docker system prune -a 和删卷命令永远不要当顺手命令敲。
  • 磁盘爆满先查日志文件和镜像两大头;端口冲突用 ss -tlnp 一锤定音;网络不通按「同网络 → 服务名 → 容器端口」顺序排查。
  • 命令记不住没关系,记住每类问题第一个该敲的命令,剩下的查表就行——这篇就是干这个用的。
Docker 常用命令速查与排障实战
https://blog.anexns.com/posts/docker-commands-troubleshooting/
作者
Anexns
发布于
2026-11-15
许可协议
CC BY-NC-SA 4.0