目錄

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 讓程式有機會「好好收尾」,例如資料庫把資料寫回硬碟、網頁伺服器處理完進行中的請求。平常一律用 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日