← 全部笔记

Docker · 3 容器运行与管理

容器停止后,仍然存在

进程退出让容器变成 exited;删除容器才会清掉它的可写层。

约 15 分钟 · 截至 2026-11-03,Docker Engine 29.x · 实验未实测 · Linux 容器

状态决定命令

容器生命周期状态机 create 创建,start 启动,pause 与 unpause 往返运行和暂停。stop 或默认 kill 使运行中的容器退出,start 能重新启动已退出的容器,rm 删除容器。removed 表示对象已不存在。 create created 已创建,未启动 start running 主进程在运行 pause unpause paused 进程仍在,已冻结 stop / kill或主进程自行退出 start exited 已退出,记录还在 rm removed 对象不存在 rm(未启动也可删除) 实线圆角框:仍可查询的容器 虚线框:删除后的终点
  1. docker create 从镜像创建对象和可写层,尚未运行程序。预测:此时用 start,还是再用 run?
  2. docker start 启动这个容器的主进程,进入 running。
  3. docker pause 冻结容器内的进程,进入 paused。预测:恢复时,程序从头开始还是继续?
  4. docker unpause 让原进程继续执行,回到 running。
  5. docker stop 或默认 docker kill 让主进程终止,进入 exited。程序自行完成也会走到这里。预测:想再运行同一个容器,应该选哪条边?
  6. docker start 重新执行原来的启动命令;容器 ID 和可写层保留,进程从头启动。
  7. 再次 docker stop,回到 exited;已退出不等于已删除。
  8. 完整路线:docker rm 删除已退出或从未启动的容器。虚线框只表示“已不存在”,之后无法再 start。
图 1 同一容器可以暂停、恢复和重新启动;删除后只能重新创建。

手机可在图内横向滚动;打开时显示完整图。把步骤滑块移到最左端,再预测下一条命令。

状态机就是“状态 + 触发变化的事件”。容器的主进程是启动命令运行的进程,在容器内通常编号为 PID 1;它退出,容器就停止。[1] 图中的箭头是常用路线:先 unpause,再 stop,便于逐步观察。

created 是从未启动;exited 是已经停止;paused 的进程与内存仍在。Linux 的 pause 使用内核的进程冻结机制。[2] [3]

你在第一次 docker run里见过“新建并启动”。run 每次新建容器;start 复用已有容器。重新 start 会从启动命令开头运行,unpause 则让冻结的原进程继续。[4] [5]

hello-world 打印完消息后,docker ps 看不到它。能据此断定容器已被删除吗?你会用什么命令确认?

不能。docker ps 默认只列运行中的容器。用 docker ps -a 包括已停止的记录;未加 --rm 时通常能看到 exited 容器。使用 --rm 才会在退出后自动删除。[2] [1]

你想让 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 容器名

  1. 向主进程发 SIGTERM。
  2. 最多等 5 秒:程序可处理信号、完成清理并退出。提前退出就结束等待。
  3. 仍未退出 → SIGKILL 强制终止。

docker kill 容器名

  1. 向主进程发 SIGKILL。
  2. 不留给程序处理信号、完成清理的机会。
图 2 默认 stop 留出处理终止请求的窗口;默认 kill 跳过这个窗口。编号只表示事件顺序。

“请求终止”能否平稳完成,取决于程序是否处理信号。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. 先跑一个自动删除的短任务

docker run --rm --network none hello-world

预期输出含 Hello from Docker!(见 hello-world 官方源码与安装验证文档;本页未实测)。程序退出后,这次新建的容器被自动删除;下载的镜像保留。--rm 不适合下面需要反复观察 exited 的实验。

2. 创建后停下来观察

下面的 --name 给容器起名;若 life-demo-17 已被占用,请统一换个名字,勿删除已有容器。Alpine 是带 shell 的 Linux 镜像;sh -c 执行引号内的脚本。

docker create --name life-demo-17 --network none alpine:3.22 sh -c 'echo saved > /note; trap "exit 0" TERM; while :; do sleep 1; done'
docker inspect -f '{{.State.Status}}' life-demo-17
docker start life-demo-17
docker inspect -f '{{.State.Status}}' life-demo-17

脚本先写容器内文件 /note;trap 让 shell 收到 TERM 后正常退出;循环中的 sleep 让进程持续存在。create 尚未执行脚本,start 才执行。inspect -f 按模板只打印状态字段,避免把时间和随机 ID 当成固定输出。[9]

3. 暂停、恢复、停止,再启动

docker pause life-demo-17
docker inspect -f '{{.State.Status}}' life-demo-17
docker unpause life-demo-17
docker inspect -f '{{.State.Status}}' life-demo-17
docker stop -t 5 life-demo-17
docker inspect -f '{{.State.Status}}' life-demo-17
docker diff life-demo-17
docker start life-demo-17
docker inspect -f '{{.State.Status}}' life-demo-17
docker kill life-demo-17
docker inspect -f '{{.State.Status}}' life-demo-17
docker ps -a --filter name=life-demo-17
刚执行完状态字段的预期值要观察的差别
createcreated创建对象,但没有运行脚本
startrunning脚本运行,容器内生成 /note
pausepaused进程冻结,仍保留内存
unpauserunning原进程继续循环
stop -t 5exiteddiff 应列出新增的 /note;可写层仍在
再次 startrunning同一容器,从脚本开头运行
默认 killexited强制终止,ps -a 仍能列出它

上表是预期观察,未实测,不是终端记录。docker diff 查看相对镜像的文件变化,A 表示新增。这里不预填 ID、时间、退出码或大小。若某步失败,请先查权限、镜像拉取和 pause 支持情况。[10]

在删除前,补全命令:把已经 exited 的同一个容器重新启动。

docker life-demo-17

start 针对已有容器。run 的参数是镜像,执行后会产生一个新容器。这里只在页面里填空,无需真的再启动。

4. 只删除这次实验的容器

# 确认上一段 kill 成功,容器已是 exited
docker rm life-demo-17
docker ps -a --filter name=life-demo-17
docker inspect life-demo-17

预期:列表中不再有这个容器;inspect 报对象不存在(具体报错文字以本机为准)。rm 会删除容器内的 /note 与可写层,镜像仍留在本地。若你中途又启动了它,先 stop 再 rm。避免把这一步改成批量清理命令。[11]

退出与删除的边界

exited 仍占磁盘

exited 时主进程已经终止,应用不再运行;容器的文件与配置仍然留着。可写层是每个容器自己的文件改动,叠在只读镜像之上;停掉容器不会删除它。[1] [12]

进程已退出

  • 应用不再执行
  • 原进程内存不再保留供恢复
  • start 将运行新进程

容器仍保留

  • 可写层:如 /note
  • 配置、ID、名称、退出记录
  • 本地日志(取决于日志驱动)

单独管理的对象

  • 共享的只读镜像
  • 卷:Docker 管理的独立数据存储
  • 绑定挂载:直接接入的宿主机路径
图 3 stop 结束进程;rm 清理容器自身;镜像和外部数据有各自的生命周期。

名称也还被占用。保留 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]

间隔检索

按目标选命令

容器未配置自动重启或 --rm。你执行 stop,程序不响应终止请求。等待超时后,哪种结果符合机制?

冻结来自 pause;stop 请求终止,超时后会强制终止。

stop 不负责删除容器,也不会删除镜像;题设没有自动删除。

超时触发 SIGKILL,主进程终止后容器成为 exited。容器对象与可写层继续存在;需要显式 rm 才删除容器自身。即使 rm,镜像也不会被一并删除。

若“进程”和“容器对象”还容易混淆,可回看镜像、容器与仓库。接下来学习 run 参数时,把每个参数放回这张状态机:它影响创建配置、运行过程,还是退出后的清理?

来源

核查于 2026-11-03。范围为 Docker Engine 29.x、Linux 容器;在线文档会更新。全部 Docker 命令未实测,维护者可补实测记录。以下链接分别支持命令、信号与存储边界。

  1. docker container run:新建、重新启动、--rm、名称、网络与退出后的文件系统。
  2. docker container ls:-a、状态枚举与过滤。
  3. docker pause / unpause:冻结与恢复进程。
  4. docker create:创建可写层、初始 created 状态。
  5. docker start:启动已有停止容器。
  6. docker stop:终止信号、等待上限与超时处理。
  7. docker kill:默认 SIGKILL、自定义信号与 shell 转发边界。
  8. Linux signal(7):SIGTERM、SIGKILL 的定义与不可捕获性质。
  9. docker inspect:--format 模板与对象信息。
  10. docker diff:文件变化与 A/C/D 标记。
  11. docker rm:删除、强制删除与匿名卷。
  12. Storage:可写层、卷、绑定挂载。
  13. Storage drivers:共享只读层、额外磁盘开销与 Engine 29 存储提示。
  14. docker logs:可用日志与日志驱动的关系。