5.2 守護態執行

在生產環境中,我們通常需要容器持續執行,不受終端關閉的影響。本節將深入講解如何讓容器在後台執行,以及理解容器生命週期的核心概念。

5.2.1 核心概念:前台 vs 後台

當你在終端執行一個程式時,有兩種模式:

  • 前台執行:程式佔用當前終端,輸出直接顯示,關閉終端程式就停止
  • 後台執行:程式在後台執行,不佔用終端,終端關閉也不影響程式

Docker 容器預設是 前台執行 的。使用 -d (detach) 引數可以讓容器在後台執行。

5.2.2 基本使用

前台執行:預設

$ docker run ubuntu:24.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
hello world
hello world
hello world
hello world

容器會把輸出的結果 (STDOUT) 列印到宿主機上面。此時:

  • 終端被佔用,無法執行其他指令
  • Ctrl+C 會終止容器
  • 關閉終端視窗,容器也會停止

後台執行:使用 -d 引數

$ docker run -d ubuntu:24.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
77b2dc01fe0f3f1265df143181e7b9af5e05279a884f4776ee75350ea9d8017a

使用 -d 引數後:

  • 容器在後台執行
  • 回傳容器的完整 ID
  • 終端立即釋放,可以繼續執行其他指令
  • 輸出不會直接顯示 (需要用 docker logs 檢視)

5.2.3 深入理解:容器為什麼會 『立即退出』?

這是初學者最常遇到的困惑。 理解這個問題,你就理解了 Docker 的核心設計理念。

很多人嘗試這樣啟動容器:

$ docker run -d ubuntu:24.04

然後用 docker ps 檢視,發現容器根本不在執行!這是為什麼?

核心原理:容器的生命週期與主程序繫結

flowchart TD subgraph Lifecycle ["Docker 容器的生命週期 = 容器內 PID 1 程序的生命週期"] direction LR Start["主程序啟動"] --> Run["容器執行"] Exit["主程序退出"] --> Stop["容器停止"] end

當你執行 docker run -d ubuntu:24.04 時:

  1. 容器啟動
  2. 沒有指定指令,預設執行 /bin/bash
  3. 但沒有互動式終端 (沒有 -it 引數),bash 發現沒有輸入源
  4. bash 立即退出
  5. 主程序退出,容器停止

關鍵理解

  • -d 引數 不是 讓容器 『一直執行』
  • -d 引數是讓容器 『在後台執行』,能執行多久取決於主程序

常見的 『立即退出』 場景

場景 原因 解決方案
docker run -d ubuntu 預設 bash 無輸入立即退出 指定長期執行的指令
docker run -d nginx 後改了設定 設定錯誤導致 nginx 啟動失敗 檢視 docker logs
自定義映象容器啟動即退 Dockerfile 的 CMD 執行完畢 確保 CMD 是前台程序

5.2.4 檢視後台容器

檢視執行中的容器

$ docker container ls
CONTAINER ID  IMAGE         COMMAND               CREATED        STATUS       PORTS NAMES
77b2dc01fe0f  ubuntu:24.04  /bin/sh -c 'while tr  2 minutes ago  Up 1 minute        agitated_wright

檢視容器輸出日誌

$ docker container logs 77b2dc01fe0f
hello world
hello world
hello world
...

實時檢視日誌 (類似 tail -f):

$ docker container logs -f 77b2dc01fe0f

檢視已停止的容器

$ docker container ls -a

加上 -a 引數可以看到所有容器,包括已停止的。這對於除錯 『容器啟動即退出』 的問題非常有用。

5.2.5 最佳實踐

1. 長期執行的服務使用 -d

## Web 伺服器

$ docker run -d -p 80:80 nginx:latest

## 資料庫

$ docker run -d -p 3306:3306 mysql:8.4

## 快取服務

$ docker run -d -p 6379:6379 redis:latest

版本說明:範例使用常見的標籤如 latest 或穩定大版本號如 mysql:8.4。具體版本可根據需求調整,生產環境建議明確指定版本號(如 mysql:8.4.4)而非使用 latest

2. 除錯時先用前台模式

當容器啟動有問題時,去掉 -d 引數 可以直接看到輸出和錯誤:

## 有問題的容器,先前台執行看看發生了什麼

$ docker run myimage:v1.0.0

3. 使用 --rm 自動清理

對於一次性任務,使用 --rm 引數讓容器退出後自動刪除:

$ docker run --rm ubuntu:24.04 echo "Hello, World!"
Hello, World!

## 容器執行完後自動刪除

...

4. 配合日誌檢視

## 後台啟動

$ docker run -d --name myapp myimage:v1.0.0

## 檢視最近 100 行日誌

$ docker logs --tail 100 myapp

## 實時跟蹤日誌

$ docker logs -f myapp

## 檢視帶時間戳的日誌

$ docker logs -t myapp

5.2.6 常見問題排查

Q:容器啟動後立即退出

  1. 檢視退出狀態碼

    $ docker ps -a --filter "name=mycontainer"
    # 檢視 STATUS 列,如 『Exited (1)』 表示異常退出
    
    
  2. 檢視容器日誌

    $ docker logs mycontainer
    
  3. 以互動模式除錯

    # /bin/sh 覆蓋映象原本的啟動指令,避免容器再次崩潰退出
    # 進入 shell 後可手動執行原啟動指令,定位具體報錯原因
    $ docker run -it myimage:v1.0.0 /bin/sh
    

Q:容器在後台執行但無法訪問服務

  1. 檢查連接埠對映

    $ docker port mycontainer
    
  2. 檢查容器內服務狀態

    $ docker exec mycontainer ps aux
    

Q:如何讓已經在後台執行的容器回到前台?

使用 docker attach

$ docker attach mycontainer

注意attach 會連線到容器的主程序。如果主程序不是互動式的,你可能只能看到輸出。使用 Ctrl+P Ctrl+Q 可以安全退出而不停止容器。

5.2.7 延伸閱讀

第 37 页,共 196 页
使用 mdPress 构建