目录

Docker 容器生命周期教程:创建、启动、停止和删除

容器从创建到删除会经历几种状态。了解这些状态,就能明白为什么容器有时会“运行一下就停止”、为什么已停止的容器仍占用名称,以及为什么 docker stop 有时要等 10 秒。

容器的状态

Docker 容器生命周期状态图
容器的状态以及切换状态的命令
状态含义docker ps -a 的 STATUS
created已创建但从未启动Created
running主进程正在运行Up 3 minutes
paused所有进程都被冻结Up 3 minutes (Paused)
exited主进程已结束,容器仍然存在Exited (0) 10 seconds ago
restarting正按重启策略重新启动Restarting (1) 2 seconds ago

Exited 后面括号中的数字是主进程的退出代码,0 表示正常结束,下面会详细说明。

容器何时会停止

容器的生命周期 = 主进程(PID 1)的生命周期。 主进程结束,容器就会停止。

这解释了一个很常见的疑问:

$ docker run ubuntu:26.04

$ docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

$ docker ps -a
CONTAINER ID   IMAGE          COMMAND       CREATED                  STATUS                              PORTS     NAMES
66e6f85c66e0   ubuntu:26.04   "/bin/bash"   Less than a second ago   Exited (0) Less than a second ago             dreamy_solomon

docker run ubuntu:26.04 没有任何输出就结束了,docker ps 也看不到它。使用 docker ps -a 才能看到:它的主进程是 /bin/bash,但没有加 -it,bash 没有可读取的输入,启动后立即结束,容器也就停止了(Exited (0))。

加上 -it 为它提供一个交互式终端,bash 才会持续等待你的输入:

docker run -it ubuntu:26.04

nginx、PostgreSQL 这类服务镜像的主进程会一直在前台运行,因此容器会持续运行。

创建与启动

docker run 实际上相当于 docker create(创建)加上 docker start(启动)。也可以分开执行:

$ docker create --name web nginx:1.30
ad99713ea5acddf70d854365e882fd0a3b6d4508d50da25993b94c9878f1c3bc

$ docker ps -a --filter name=web
CONTAINER ID   IMAGE        COMMAND                  CREATED                  STATUS    PORTS     NAMES
ad99713ea5ac   nginx:1.30   "/docker-entrypoint.…"   Less than a second ago   Created             web

$ docker start web
web

$ docker ps --filter name=web
CONTAINER ID   IMAGE        COMMAND                  CREATED                  STATUS                  PORTS     NAMES
ad99713ea5ac   nginx:1.30   "/docker-entrypoint.…"   Less than a second ago   Up Less than a second   80/tcp    web

创建后状态为 Created,启动后变为 Up。--filter name=web 只会列出名称包含 web 的容器。

名称不能重复

docker run 每次都会创建一个新容器。如果容器名称已被占用,即使那个容器已经停止,也会报错:

$ docker run -d --name web nginx:1.30
docker: Error response from daemon: Conflict. The container name "/web" is already in use by container "ad99713ea5acddf70d854365e882fd0a3b6d4508d50da25993b94c9878f1c3bc". You have to remove (or rename) that container to be able to reuse that name.

Run 'docker run --help' for more information

要重新启动之前的容器,使用 docker start web;要用新配置重新创建,先执行 docker rm -f web,再运行 docker run。

停止:stop 与 kill 的区别

命令行为
docker stop先发送 SIGTERM,让程序自行收尾;等待 10 秒后如果仍未结束,再发送 SIGKILL 强制终止
docker kill直接发送 SIGKILL,立即终止

stop 会给程序机会“妥善收尾”,例如让数据库将数据写回硬盘、让 Web 服务器处理完正在进行的请求。通常都使用 stop,只有程序卡住时才使用 kill。

$ docker start web
web

$ docker kill web
web

$ docker ps -a --filter name=web
CONTAINER ID   IMAGE        COMMAND                  CREATED          STATUS                                PORTS     NAMES
ad99713ea5ac   nginx:1.30   "/docker-entrypoint.…"   14 seconds ago   Exited (137) Less than a second ago             web

被 kill 的容器退出代码是 137(128 + 9,9 是 SIGKILL 的编号)。

为什么 docker stop 有时要等 10 秒?

下面实际比较三个容器停止所需的时间:

$ time docker stop web
web
real	0m 0.10s
user	0m 0.01s
sys	0m 0.00s

$ docker run -d --name slow alpine:3.23 sh -c "sleep 300"
Unable to find image 'alpine:3.23' locally
3.23: Pulling from library/alpine
d0c1d894c237: Pull complete
Digest: sha256:85fe1e81d6758c208f3e1eed4338a1997e19d4be002d4dd32d3100c9a8c010a0
Status: Downloaded newer image for alpine:3.23
170d08a64bb8ec1519d183f8c20508d669358eea4d5a978fa4f4675ffcec41ab

$ time docker stop slow
slow
real	0m 10.17s
user	0m 0.00s
sys	0m 0.01s

$ docker run -d --name slow2 --init alpine:3.23 sh -c "sleep 300"
d1854be4790b5fc9375004e05708d27a27d56c2c540a8159424351985db20ef9

$ time docker stop slow2
slow2
real	0m 0.13s
user	0m 0.00s
sys	0m 0.01s
容器停止时间原因
nginx0.10 秒nginx 收到 SIGTERM 后会立即正常关闭
sh -c "sleep 300"10.17 秒主进程是 sh,作为 PID 1 运行时会忽略 SIGTERM,Docker 等足 10 秒后才用 SIGKILL 强制终止
同上,加上 --init0.13 秒--init 会用一个小型 init 进程作为 PID 1,并由它将信号转发给子进程

Linux 对 PID 1 有一条特殊规则:如果 PID 1 没有自行处理 SIGTERM,就会忽略这个信号。因此,如果你自己编写的镜像每次执行 docker stop 都要等 10 秒,通常是因为主进程以 PID 1 运行,而程序没有处理 SIGTERM。例如,直接以 node server.js 作为主进程的 Node.js 程序,经实测也要等 10 秒,详见Dockerfile 指令大全中的实际对比。解决办法是在程序中处理 SIGTERM,或加上 --init。

退出代码

$ docker run --name exit3 alpine:3.23 sh -c "exit 3"

$ docker ps -a --filter name=exit3
CONTAINER ID   IMAGE         COMMAND            CREATED        STATUS                              PORTS     NAMES
84996cca5ec5   alpine:3.23   "sh -c 'exit 3'"   1 second ago   Exited (3) Less than a second ago             exit3

$ docker inspect --format '{{.State.ExitCode}}' exit3
3

主进程以什么代码结束,Exited (...) 就会显示什么。常见代码如下:

代码常见原因
0正常结束
1 等其他数字程序自身报告的错误,查看 docker logs
137被 SIGKILL 终止:执行了 docker kill、docker stop 等待时间过长,或因内存不足被系统终止(OOM)
143收到 SIGTERM 后正常结束(128 + 15)

暂停与恢复

$ docker start web
web

$ docker pause web
web

$ docker ps --filter name=web
CONTAINER ID   IMAGE        COMMAND                  CREATED          STATUS                           PORTS     NAMES
ad99713ea5ac   nginx:1.30   "/docker-entrypoint.…"   15 seconds ago   Up Less than a second (Paused)   80/tcp    web

$ docker unpause web
web

pause 会冻结容器内的所有进程(不会结束它们),状态会显示 (Paused)。这个功能很少用,适合临时释放 CPU,同时保留内存中的状态。

删除容器

$ docker rm web
Error response from daemon: cannot remove container "web": container is running: stop the container before removing or force remove

$ docker rm -f web
web

运行中的容器不能直接删除,需要先执行 stop,或使用 -f 强制删除(相当于先 kill 再 rm)。

一次性清理所有已停止的容器

练习一段时间后,docker ps -a 中就会积累很多已停止的容器:

$ docker ps -a
CONTAINER ID   IMAGE          COMMAND                  CREATED          STATUS                        PORTS     NAMES
75ee00dc4081   nginx:1.30     "/docker-entrypoint.…"   1 second ago     Up Less than a second         80/tcp    web
5dfb843c0b40   alpine:3.23    "sh -c 'echo startin…"   26 seconds ago   Exited (1) 24 seconds ago               flaky
84996cca5ec5   alpine:3.23    "sh -c 'exit 3'"         27 seconds ago   Exited (3) 26 seconds ago               exit3
d1854be4790b   alpine:3.23    "sh -c 'sleep 300'"      29 seconds ago   Exited (143) 28 seconds ago             slow2
170d08a64bb8   alpine:3.23    "sh -c 'sleep 300'"      39 seconds ago   Exited (137) 29 seconds ago             slow
66e6f85c66e0   ubuntu:26.04   "/bin/bash"              43 seconds ago   Exited (0) 42 seconds ago               dreamy_solomon

$ docker container prune -f
Deleted Containers:
5dfb843c0b400146827fe138890ee4d62a24104cad5531aff4100fc471b0727f
84996cca5ec5bfe7ca51c6365b60ef89e49055cf06a3f0dd3a49f9e50e08d6f4
d1854be4790b5fc9375004e05708d27a27d56c2c540a8159424351985db20ef9
170d08a64bb8ec1519d183f8c20508d669358eea4d5a978fa4f4675ffcec41ab
66e6f85c66e0f2b586c5919a900a0e16d6f0fc49535d35fa7d30f77747f1ce0e

Total reclaimed space: 24.58kB

container prune 只会删除已停止的容器,正在运行的 web 不受影响。也可以对照上面的退出代码:slow 被强制终止,退出代码为 137;加了 --init 的 slow2 正常收到 SIGTERM,退出代码为 143。

如果希望一次性容器结束后自动删除,可以在运行时加上 --rm:

docker run --rm alpine:3.23 echo "用完就丢"

重启策略:--restart

服务器重启或程序崩溃时,是否要自动重新启动容器?使用 --restart 进行设置:

取值行为
no默认值,不自动重启
on-failure[:次数]只有退出代码不为 0 时才重启,可以限制次数
always始终重启;手动 stop 后,如果 Docker 本身重新启动,容器仍会再次启动
unless-stopped类似 always,但手动 stop 过的容器不会再自动启动

实际看看 on-failure

下面这个容器每次启动都会打印 starting,然后以代码 1 结束,用来模拟不断崩溃的程序:

$ docker run -d --name flaky --restart on-failure:3 alpine:3.23 sh -c "echo starting; exit 1"
5dfb843c0b400146827fe138890ee4d62a24104cad5531aff4100fc471b0727f

$ docker ps -a --filter name=flaky
CONTAINER ID   IMAGE         COMMAND                  CREATED          STATUS                      PORTS     NAMES
5dfb843c0b40   alpine:3.23   "sh -c 'echo startin…"   25 seconds ago   Exited (1) 23 seconds ago             flaky

$ docker inspect --format '{{.RestartCount}} {{.State.Status}} {{.State.ExitCode}}' flaky
3 exited 1

$ docker logs flaky
starting
starting
starting
starting

日志中有 4 次 starting:第一次启动,加上 3 次重启(RestartCount 为 3),达到上限后容器就停在 Exited (1)。Docker 会逐渐延长每次重启之间的等待时间,避免频繁重启拖垮主机。

修改已有容器的重启策略

长期运行的服务一般建议使用 unless-stopped。也可以修改已在运行的容器:

$ docker run -d --name web --restart unless-stopped nginx:1.30
75ee00dc4081f4c2849562fbd89edfdd9386839a161ea9d66956eaa41257d4cf

$ docker inspect --format '{{.HostConfig.RestartPolicy.Name}}' web
unless-stopped

$ docker update --restart always web
web

$ docker inspect --format '{{.HostConfig.RestartPolicy.Name}}' web
always

在 Linux 上,要让容器随系统启动,Docker 本身也必须设置为开机自动启动:sudo systemctl enable docker。在 Docker Desktop 中,则要在设置里启用“Start Docker Desktop when you sign in”。

命令汇总

命令作用
docker run创建并启动新容器
docker create只创建容器
docker start / stop / restart启动 / 停止 / 重启已有容器
docker kill强制终止(SIGKILL)
docker pause / unpause暂停 / 恢复
docker rm [-f]删除容器
docker container prune删除所有已停止的容器
docker ps [-a]列出容器(-a 包括已停止的容器)
docker update --restart修改重启策略

下一节将完整介绍 docker run 的常用参数。

重点回顾

  • 容器的状态:created、running、paused、exited、restarting。
  • 主进程结束时容器会停止;docker stop 会先发送 SIGTERM,10 秒后再发送 SIGKILL。
  • 如果主进程是 PID 1 且没有处理 SIGTERM,stop 会等待整整 10 秒;可以用 --init 解决。
  • 长期运行的服务应加上 --restart unless-stopped。

动手练习

练习 1:使用 docker run -d --name t1 alpine:3.23 sh -c "exit 3" 启动容器,它的状态和退出代码是什么?

答案

docker ps -a 会显示 Exited (3)。也可以使用 docker inspect -f "{{.State.ExitCode}}" t1 获取退出代码 3。

练习 2:启动 docker run -d --name t2 alpine:3.23 sleep 300,分别使用 time docker stop t2(记得先重新创建容器)和加上 --init 的版本,比较停止所需的时间。

提示

不加 --init 时,sleep 是 PID 1,会忽略 SIGTERM,约 10 秒后才被强制终止;加上 --init 后,init 进程会把信号转发给 sleep,容器几乎立即停止。

常见问题

Exited (137) 是什么意思?

137 = 128 + 9,表示容器被 SIGKILL 强制终止,可能是执行了 docker kill、docker stop 等待时间过长,或因内存不足被系统终止。

服务器重启后,容器会自动启动吗?

需要设置重启策略(例如 --restart unless-stopped),而且 Docker 本身也要设置为开机自动启动(Linux 上执行 sudo systemctl enable docker)。

暂停(pause)和停止(stop)有什么区别?

pause 会冻结容器内的所有进程,保留内存中的内容,恢复后从原状态继续运行;stop 会结束进程,内存中的状态也会消失。

更新于 2026年10月14日