状态决定命令
docker create从镜像创建对象和可写层,尚未运行程序。预测:此时用 start,还是再用 run?docker start启动这个容器的主进程,进入 running。docker pause冻结容器内的进程,进入 paused。预测:恢复时,程序从头开始还是继续?docker unpause让原进程继续执行,回到 running。docker stop或默认docker kill让主进程终止,进入 exited。程序自行完成也会走到这里。预测:想再运行同一个容器,应该选哪条边?docker start重新执行原来的启动命令;容器 ID 和可写层保留,进程从头启动。- 再次
docker stop,回到 exited;已退出不等于已删除。 - 完整路线:
docker rm删除已退出或从未启动的容器。虚线框只表示“已不存在”,之后无法再 start。
手机可在图内横向滚动;打开时显示完整图。把步骤滑块移到最左端,再预测下一条命令。
- 能根据当前状态,选择 create / start / pause / unpause / stop / kill / rm。
- 能解释 stop 的等待过程与 kill 的默认信号。
- 能区分 exited 保留的磁盘数据与 rm 删除的容器数据。
状态机就是“状态 + 触发变化的事件”。容器的主进程是启动命令运行的进程,在容器内通常编号为 PID 1;它退出,容器就停止。[1] 图中的箭头是常用路线:先 unpause,再 stop,便于逐步观察。
created 是从未启动;exited 是已经停止;paused 的进程与内存仍在。Linux 的 pause 使用内核的进程冻结机制。[2] [3]
你在第一次 docker run里见过“新建并启动”。run 每次新建容器;start 复用已有容器。重新 start 会从启动命令开头运行,unpause 则让冻结的原进程继续。[4] [5]
hello-world 打印完消息后,docker ps 看不到它。能据此断定容器已被删除吗?你会用什么命令确认?
你想让 paused 容器中的计算接着往下做,保留当前进程的内存。该用哪条命令?
start 用于启动已停止的容器。paused 保留着被冻结的进程,要先解除冻结。
run 创建的是另一个容器,无法接着原进程的内存执行。
unpause 解除冻结,恢复原进程。停止后再 start 会创建新进程,从启动命令开头执行;它能保留磁盘可写层,但不会恢复原来的进程内存。
真实状态比这张简图更多吗?
有。Docker 还列出 restarting(按策略重启中)、removing(正在删除)和 dead(异常、无法正常运行的残留对象)。removed 不是 docker inspect 能返回的状态,因为对象已经删除。图中先省去重启策略与异常路径;所有“停止后留在 exited”的描述都假设未启用自动重启、也未设置自动删除。[2]
同样退出,不同过程
stop 给清理时间
信号是内核向进程发送的通知。默认 stop 先发 SIGTERM,请求主进程终止;超时仍不退出,再发 SIGKILL 强制终止。默认 kill 直接发 SIGKILL。[6] [7]
docker stop -t 5 容器名
- 向主进程发 SIGTERM。
- 最多等 5 秒:程序可处理信号、完成清理并退出。提前退出就结束等待。
- 仍未退出 → SIGKILL 强制终止。
docker kill 容器名
- 向主进程发 SIGKILL。
- 不留给程序处理信号、完成清理的机会。
“请求终止”能否平稳完成,取决于程序是否处理信号。SIGKILL 不能被捕获、阻塞或忽略;不要指望它触发程序的收尾逻辑。正常关服务先考虑 stop。[8]
执行 docker stop -t 5 后,程序在第 1 秒完成清理并退出。Docker 还会等到第 5 秒再发 SIGKILL 吗?
不会。5 秒是等待上限。进程提前退出就不需要强制终止。反过来,程序不响应终止请求,才会在超时后收到 SIGKILL。这里的秒数是题设,不是一次性能测量。
默认值、信号配置与 PID 1
Linux 容器未配置时,stop 的等待上限为 10 秒;可用 docker stop --timeout 为这次操作指定。创建时的 --stop-timeout 可以设置默认值。stop 首个信号可由镜像的 STOPSIGNAL、创建时的 --stop-signal 或本次 docker stop --signal 改变。[6]
docker kill --signal=HUP 容器名 发送 HUP 信号;程序如何处理它决定是否退出,所以“kill 一定变成 exited”只适用于图中的默认 SIGKILL。Docker 将信号发给主进程;若外层 shell 没有转发,内部应用可能收不到。前面 Dockerfile 模块里的 exec 形式有助于让应用成为主进程。[7]
你来走完状态机
逐步观察同一容器
编写环境未安装 Docker。以下是供你执行的实验与文档支持的预期观察,没有附伪造的终端输出。请在已启动 Docker Engine 29.x、可运行 Linux 容器的机器上验证。
在有 Docker 访问权限的宿主机终端执行。首次拉取镜像需要联网;镜像和容器会占宿主机磁盘。实验用 --network none 禁用容器外部网络,不发布端口、不挂载宿主机目录、不使用特权模式。pause 需要运行环境支持进程冻结。[1]
1. 先跑一个自动删除的短任务
预期输出含 Hello from Docker!(见 hello-world 官方源码与安装验证文档;本页未实测)。程序退出后,这次新建的容器被自动删除;下载的镜像保留。--rm 不适合下面需要反复观察 exited 的实验。
2. 创建后停下来观察
下面的 --name 给容器起名;若 life-demo-17 已被占用,请统一换个名字,勿删除已有容器。Alpine 是带 shell 的 Linux 镜像;sh -c 执行引号内的脚本。
脚本先写容器内文件 /note;trap 让 shell 收到 TERM 后正常退出;循环中的 sleep 让进程持续存在。create 尚未执行脚本,start 才执行。inspect -f 按模板只打印状态字段,避免把时间和随机 ID 当成固定输出。[9]
3. 暂停、恢复、停止,再启动
| 刚执行完 | 状态字段的预期值 | 要观察的差别 |
|---|---|---|
| create | created | 创建对象,但没有运行脚本 |
| start | running | 脚本运行,容器内生成 /note |
| pause | paused | 进程冻结,仍保留内存 |
| unpause | running | 原进程继续循环 |
| stop -t 5 | exited | diff 应列出新增的 /note;可写层仍在 |
| 再次 start | running | 同一容器,从脚本开头运行 |
| 默认 kill | exited | 强制终止,ps -a 仍能列出它 |
上表是预期观察,未实测,不是终端记录。docker diff 查看相对镜像的文件变化,A 表示新增。这里不预填 ID、时间、退出码或大小。若某步失败,请先查权限、镜像拉取和 pause 支持情况。[10]
在删除前,补全命令:把已经 exited 的同一个容器重新启动。
docker life-demo-17
start 针对已有容器。run 的参数是镜像,执行后会产生一个新容器。这里只在页面里填空,无需真的再启动。
4. 只删除这次实验的容器
预期:列表中不再有这个容器;inspect 报对象不存在(具体报错文字以本机为准)。rm 会删除容器内的 /note 与可写层,镜像仍留在本地。若你中途又启动了它,先 stop 再 rm。避免把这一步改成批量清理命令。[11]
退出与删除的边界
exited 仍占磁盘
exited 时主进程已经终止,应用不再运行;容器的文件与配置仍然留着。可写层是每个容器自己的文件改动,叠在只读镜像之上;停掉容器不会删除它。[1] [12]
进程已退出
- 应用不再执行
- 原进程内存不再保留供恢复
- start 将运行新进程
容器仍保留
- 可写层:如 /note
- 配置、ID、名称、退出记录
- 本地日志(取决于日志驱动)
单独管理的对象
- 共享的只读镜像
- 卷:Docker 管理的独立数据存储
- 绑定挂载:直接接入的宿主机路径
名称也还被占用。保留 exited 容器能继续查看配置、检查文件变化;有可读日志时,还能回看输出。代价是磁盘与名称不会因 stop 自动释放。[13] [14]
你停止了一个容器,磁盘空间却没明显增加。用自己的话解释为什么,并说出删除前要确认哪类数据。
停止只结束进程。容器可写层、配置和本地日志可能继续占磁盘,镜像也还存在。删除前要确认可写层里是否有需要保留的文件,并分清数据位于容器内、卷里,还是宿主机绑定路径。
- 说清 stop 不删除可写层
- 指出本地日志与共享镜像也可能占空间
- 删除前确认数据位置与保留需求
rm、rm -v、--rm 各自删到哪里?
docker rm 清理容器自身和可写层,默认保留卷。docker rm -v 还会删除关联的匿名卷;有名字的卷保留。docker run --rm 在退出后自动删除容器及关联匿名卷,也保留命名卷。绑定挂载中的宿主机文件不会随 rm 删除。[11] [1] [12]
docker rm -f 可用 SIGKILL 强制终止并删除运行中的容器,跳过正常清理机会。本页实验采用先 stop/kill、再 rm 的可观察路线。不要对有用的容器随手加 -f。[11]
为什么不能把容器大小直接相加?
多个容器可以共享镜像只读层。可写层大小也不包括全部本地日志、卷和配置等开销。Docker Engine 29 的新安装默认采用 containerd image store,磁盘布局与旧存储驱动示例不同;这里不假定某个宿主机目录,也不填写未经测量的大小。[13]
间隔检索
按目标选命令
- 新建用 create / run,已有容器启动用 start;同一个 ID 不等于同一个进程。
- pause 冻结,unpause 接着执行;stop 后再 start 从启动命令开头执行。
- 默认 stop 先请求终止,超时才强制;默认 kill 直接 SIGKILL。
- exited 保留可写层与记录;rm 后容器不存在,镜像与外部数据单独管理。
容器未配置自动重启或 --rm。你执行 stop,程序不响应终止请求。等待超时后,哪种结果符合机制?
冻结来自 pause;stop 请求终止,超时后会强制终止。
stop 不负责删除容器,也不会删除镜像;题设没有自动删除。
超时触发 SIGKILL,主进程终止后容器成为 exited。容器对象与可写层继续存在;需要显式 rm 才删除容器自身。即使 rm,镜像也不会被一并删除。
若“进程”和“容器对象”还容易混淆,可回看镜像、容器与仓库。接下来学习 run 参数时,把每个参数放回这张状态机:它影响创建配置、运行过程,还是退出后的清理?
来源
核查于 2026-11-03。范围为 Docker Engine 29.x、Linux 容器;在线文档会更新。全部 Docker 命令未实测,维护者可补实测记录。以下链接分别支持命令、信号与存储边界。
- docker container run:新建、重新启动、--rm、名称、网络与退出后的文件系统。
- docker container ls:-a、状态枚举与过滤。
- docker pause / unpause:冻结与恢复进程。
- docker create:创建可写层、初始 created 状态。
- docker start:启动已有停止容器。
- docker stop:终止信号、等待上限与超时处理。
- docker kill:默认 SIGKILL、自定义信号与 shell 转发边界。
- Linux signal(7):SIGTERM、SIGKILL 的定义与不可捕获性质。
- docker inspect:--format 模板与对象信息。
- docker diff:文件变化与 A/C/D 标记。
- docker rm:删除、强制删除与匿名卷。
- Storage:可写层、卷、绑定挂载。
- Storage drivers:共享只读层、额外磁盘开销与 Engine 29 存储提示。
- docker logs:可用日志与日志驱动的关系。