Docker Compose 實際伺服器常用指令速查
整理 Docker Compose V2 伺服器日常約 12 個指令,涵蓋啟停、套用變更、logs、shell、network、volume 與安全清理,並提醒常見陷阱。
實際會用到的 Compose 指令
Docker Compose 提供超過 40 個子指令。伺服器上的日常工作通常只會用到約 12 個。本頁依工作目的整理這些指令,為每個指令說明一個明確用途,並在指令有容易忽略的陷阱時,提供深入說明的連結。
本頁全部使用 Compose V2:docker compose 中間有空格,而不是舊版的 docker-compose script。V2 是隨 Docker Engine 安裝的 Go plugin。V1 已不包含在目前的套件中,因此截至 2026 年 7 月,在全新的 Ubuntu 主機上執行 docker-compose: command not found 預期會找不到指令,不代表系統故障。使用 docker compose version 檢查。如果沒有任何輸出,請安裝 docker-compose-plugin package。
以下每個指令都必須在存放 compose.yaml 的目錄中執行,因為 Compose 會從該目錄取得 project name,並以該目錄為相對位置尋找檔案。在上一層目錄執行相同指令時,Compose 會停止並顯示 no configuration file provided: not found。如果你還不熟悉檔案格式,請先閱讀VPS 上的第一個 Compose 檔案,再回到這裡了解各項指令。
生命週期:你會輸入的 4 個指令,以及會移除容器的指令
docker compose up -d
docker compose up -d --wait
docker compose stop
docker compose start
docker compose restart web
docker compose downup -d 會建立 network、建立 containers、啟動它們,然後返回。它會在 containers 建立完成 後立即返回,因此 deploy script 若接著執行 curl probe,第一次嘗試通常會失敗。up -d --wait 會持續等待,直到每個宣告 healthcheck 的 service 都回報 healthy;如果其中一個始終未達到此狀態,指令會以非 0 狀態碼結束。這個 flag 的可靠性取決於背後的檢查,因此在自動化流程中使用前,請先撰寫 Compose 可以信任的 healthcheck。
stop 會停止 containers,但保留它們,因此 start 會以相同的 writable layer 重新啟動相同的 containers。down 會停止 containers,接著移除 containers 和 project network。寫入 container 內部、且不在 volume 中的任何資料都會一併移除。這是 Compose 中代價最高的誤解,down 與 stop 的完整差異說明了它會在哪些情況造成影響。
restart 不是 reload。它會使用現有設定停止並重新啟動相同的 container,因此變更後的 environment variable、新的 image tag 或修改後的 port mapping 完全不會生效。若要套用檔案變更,請再次執行 up -d。Compose 會將每個 service 與其執行中的 container 比對,只重新建立設定已變更的 service。
套用變更:重新建立、拉取或重建
docker compose up -d --force-recreate
docker compose pull && docker compose up -d
docker compose build --no-cache web
docker compose up -d --build webup -d 在沒有變更時不會執行任何動作,因此可安全地重複執行。--force-recreate 會略過這項比對,即使設定完全相同,也會替換所有容器。因此,這是清除容器內異常狀態最快的方法。
更新映像需要執行 2 個命令,因為這 2 個命令的作用不同。pull 會下載檔案中列出的每個標籤的最新映像。接著,up -d 會發現服務的映像 ID 已不再符合目前執行中的容器,並重新建立該容器。略過 pull 時,up -d 會讓上個月的 latest 繼續執行,且不會顯示錯誤。
相反的風險會出現在多服務堆疊中:一次為所有服務提取 latest,可能讓 10 秒前仍正常運作的應用程式立即故障。因此,自架 AFFiNE 工作區 會改為固定其 4 個映像標籤。固定標籤也能讓升級變成有意識的編輯流程:先修改標籤,再執行相同的 pull 與 recreate。對於啟動時會遷移資料庫的堆疊,則應在執行任一命令前先準備好資料庫傾印;自架 Chatwoot 客服台 每次升級版本時都會依循這項流程。
build 適用於宣告 build: 區段而非 image: 的服務。up -d --build 會在單一步驟中完成建置並啟動,這是修改程式碼時的標準流程。只有在明確判定快取層已過期時,才使用 --no-cache,因為它會從頭重建每一層。
查看目前執行中的項目
docker compose ps
docker compose ps -a
docker compose logs -f --tail=100
docker compose logs --since 15m --timestamps db
docker compose top
docker compose lsps 只會列出目前執行中的容器。服務在啟動期間當機時,必須加入 -a 才能看到;因此,容器未出現在 ps,但 ps -a 顯示其狀態為 Exited (1),正是啟動失敗的常見情況。先查看結束代碼,再查看日誌。
logs -f 會同時追蹤所有服務,並在每行前加上服務名稱。當服務彼此通訊且事件順序很重要時,這是所需的檢視方式。指定服務名稱即可縮小範圍。對於已執行一個月的容器,--tail=100 很重要,因為預設會輸出完整歷史記錄,導致終端機充滿訊息。--since 15m 可回答你通常想知道的問題,也就是剛才執行重新啟動期間發生了什麼事。
top 會列出每個容器內的程序,藉此區分「容器正在執行」與「容器內的程序正在執行」。ls 會跳出目前目錄,列出主機上的所有 Compose 專案及其狀態,讓你找出三個月前啟動的 stack。
在服務容器內取得 shell
docker compose exec web sh
docker compose exec -u root web sh
docker compose run --rm web env
docker compose run --rm --no-deps web shexec 會在已經執行中的容器內執行命令。run 會根據相同的服務定義啟動新的容器。當服務無法維持執行足夠長的時間,讓你使用 exec 進入時,就需要使用這個命令。務必將 run 與 --rm 搭配使用。否則每次執行都會留下已停止的容器,這些容器會持續累積,直到 docker compose ps -a 無法讀取。
先嘗試 sh,再使用 bash。以 Alpine 為基礎的映像檔不包含 bash,因此失敗訊息會顯示 exec: "bash": executable file not found in $PATH。將 --no-deps 加入 run,可略過服務的相依項目,避免快速的設定檢查啟動整個資料庫。
run --rm web env 是查看服務實際取得之環境的最快方式。此時所有 .env 檔案、environment: 區塊和 shell 變數都已合併。值不正確時,原因通常是合併順序所致;Compose 如何解析 env 檔案與 secret 說明了哪個來源優先。
網路、連接埠與名稱解析
docker compose port web 80
docker compose exec web getent hosts db
docker compose config --networksCompose 會將每個服務放在同一個專案網路上,每個服務名稱都是該網路中的 DNS 名稱。在 web 內執行 getent hosts db 時,若名稱解析成功,會列印容器 IP;若解析失敗,則不會列印任何內容。因此,兩秒內即可確認「這些容器能否彼此連線」。如果名稱能解析,但連線遭拒,表示 db 內的程序繫結至 127.0.0.1,而不是 0.0.0.0,因此不會接受來自其他容器的封包。相同的網路邊界也說明了,從專案外部啟動的容器,不論是由 docker run 啟動,或以獨立堆疊執行,都完全無法解析 jellyfin 這類名稱。當 Jellyfin 媒體庫的 Halcyon 前端無法連線至其指定的伺服器時,這是首先應檢查的項目。其餘運作方式請參閱Compose 網路與服務 DNS 的運作方式。
port web 80 會輸出容器已發布的連接埠所對應的主機位址與連接埠。當對映來自變數時,這可避免猜測。發布連接埠也會寫入由 Docker 自行管理的防火牆規則,而且該規則優先於你建立的規則。因此,你以為是私有的服務可能會直接暴露在網際網路上。已發布的 Docker 連接埠為何會繞過 ufw涵蓋這種情況。更安全的做法是不要發布這些連接埠,改在專案網路上放置一個負責驗證的代理,讓它位於服務之前。將 Authentik 作為單一登入層執行即採用這種架構。
Volumes 與資料
docker compose config --volumes
docker compose cp db:/etc/postgresql/pg_hba.conf ./pg_hba.conf
docker compose down -vconfig --volumes 會逐行列出專案宣告的具名 volume。這份清單就是需要備份的內容。當 volume 儲存無法取代的資料時,精確的備份命令與清單同樣重要。因此,PhotoPrism 與 Immich 的比較會列出各個相片伺服器所需的傾印與複製命令。cp 可在不開啟 shell 的情況下,將檔案複製到容器或從容器複製出來;容器所在的一側使用 service:path 格式。
down -v 會連同容器一起移除這些具名 volume。這是拆除測試堆疊的正確命令,但不適用於儲存重要資料的環境,因為執行時不會要求確認,也無法復原。Bind mount 不受此命令影響,因為資料位於主機檔案系統中。這種影響範圍的差異,也是應審慎選擇 bind mount 與具名 volume 的原因之一。
清理磁碟空間而不遺失資料
docker compose down --remove-orphans
docker system df
docker image prune -a
docker builder prune--remove-orphans 會刪除屬於該專案、但已不再出現在檔案中的容器。服務重新命名後,正是這種情況。若不執行此命令,這些容器會持續執行,且在 docker compose ps 中不可見。
docker system df 會在刪除任何內容前,顯示磁碟空間的使用情況,並分別列出映像、容器、本機 volume 與建置快取,以及各項可回收的空間。image prune -a 會移除沒有任何 tag 指向的映像。如果伺服器曾拉取大型映像的多個版本,通常可回收最多空間。builder prune 會清除建置快取。任何自行建置映像的伺服器,都可能在背景中持續累積這些快取。
上述命令都不會處理 named volume。只有 docker volume prune 和 docker compose down -v 會處理。
在設定造成問題前先檢查檔案
docker compose config --quiet
docker compose config --services
docker compose --dry-run up -dconfig --quiet會驗證檔案,成功時不輸出任何內容,因此適合放在部署前步驟或 git hook 中。單獨執行 config 會輸出完整合併並插值後的檔案。這可用來確認變數是否已解析,以及 override 檔案是否依預期套用。未設定的變數會顯示為空值,旁邊會出現警告 The "X" variable is not set. Defaulting to a blank string.
--dry-run 是全域旗標,不是子命令旗標,因此要放在 up 前面。它會列出 Compose 將執行的每個動作,但不會修改任何內容。在重要的 stack 上執行 down 前,花費這 30 秒相當值得。
跨檔案、設定檔與專案工作
docker compose -f compose.yaml -f compose.prod.yaml up -d
docker compose --profile debug up -d
docker compose -p staging up -d多個 -f 旗標會依序合併,後面的檔案會逐項覆寫前面的設定。這是保留一個基礎檔案,再搭配小型 production 覆寫檔的標準方式。不過,清單與 map 的合併規則不同,因此若遇到非預期結果,請先閱讀Compose 如何合併多個檔案。
--profile 會啟動標記該 profile 的服務,以及未標記 profile 的服務,讓除錯工具不會出現在一般的 up 中。-p 會設定 project 名稱,因此同一個 stack 的兩份副本可以並行執行,並使用各自的 network 與 volume 名稱。重新開機後恢復 stack 不需要手動輸入指令,而是由自動執行的 unit 負責,詳見開機時啟動 Compose stack。
FAQ
docker-compose 加上連字號後,是由什麼取代?
Compose V2 取代了它,使用方式是 docker compose,中間以空格分隔。這是隨 Docker Engine 一併提供的外掛程式,而目前的套件已不再安裝 V1 Python 工具。如果使用空格的形式沒有輸出,請為所用的發行版安裝 docker-compose-plugin 套件。請將舊有指令碼改為使用空格形式,不要另外建立別名,因為 V2 支援許多 V1 沒有的旗標。
為什麼 docker compose restart 沒有套用我的設定變更?
restart 會使用建立現有容器時的設定停止並重新啟動容器,不會重新讀取 compose.yaml。環境變數、埠、磁碟區或映像標籤的任何變更,都需要執行 docker compose up -d;該指令會比較每項服務與其執行中的容器,並重新建立有差異的容器。若要在檔案內容未變更時也強制替換,請加入 --force-recreate。
如何將服務更新為較新的映像?
執行 docker compose pull,再執行 docker compose up -d。pull 會取得檔案中每個標籤目前對應的映像,而 up -d 會重新建立映像 ID 與容器不再相符的服務。單獨執行 up -d 時會重用磁碟上已有的映像,因此堆疊若固定使用 latest,可能會持續執行數個月前建立的版本,且不會顯示任何錯誤。
哪些清理指令可安全地在執行中的伺服器上使用?
docker system df、docker image prune -a 和 docker builder prune 只會移除映像與快取,因此執行中的服務會繼續運作,具名磁碟區也不會受影響。具危險性的兩個指令是 docker compose down -v 和 docker volume prune,它們會在沒有提示的情況下刪除具名磁碟區。請先執行 docker compose config --volumes,確認可能受到影響的內容。
可以只執行一個指令而不啟動整個堆疊嗎?
可以。docker compose run --rm --no-deps web sh 會根據 web 服務定義啟動單一容器、略過其相依服務,並在離開時移除該容器。若容器已在執行,請改用 exec,因為 exec 會加入執行中的程序,並顯示服務實際所處的狀態。