Watch at Ease看見世界,讀懂生活。

科技 · 實用指南

Docker Compose 顯示孤立容器?刪除前先稽核專案歸屬

孤立警告不能證明容器可以丟棄。先確認實際 Compose 專案,檢查歸屬標籤與資料掛載,區分服務改名、專案名稱衝突、不同檔案組合與一次性執行,再選擇最小安全動作。

兩個 Docker Compose 專案群組在清理前接受容器歸屬核對的原創概念圖
原創概念圖:在保留、隔離或刪除警告容器前,先證明實際 Compose 專案與服務擁有者。 Watch at Ease

Docker Compose 所說的孤立容器,是指容器屬于目前有效專案識別,但它的服務没有出現在本次命令使用的有效 Compose 模型中。這可能是服務改名後的正常結果,也可能說明兩個無關檔案共用了專案名稱、目前使用了较舊或不同的檔案組合,或留下了已停止的一次性執行容器。

因此,警告是證據,不是刪除許可。安全問题不只是 `--remove-orphans` 是否存在,而是每個具名容器由哪個專案和服務创建、目前設定是否仍打算管理它,以及它的挂載中是否包含必須保留的資料。

本指南從只讀命令開始。它不建議全局 prune,不刪除具名磁碟區或外部磁碟區,也不會在歸屬未查明前關闭警告。最終產物是一份簡短的歸屬記錄和一個範圍明確的動作。

1. 儲存准確警告,暫缓清理决定

儲存完整警告、触發它的命令、工作目錄,以及所有 `-f`、`--project-directory`、`-p` 或 `--project-name` 參數。在歸屬問题未解决前,不要執行 `docker container prune`、`docker compose down -v`,也不要帶着 `--remove-orphans` 重復原命令。

記錄 `docker compose version`、目前 Docker context 和相關 Compose 檔案名稱。如果命令由自動化發起,還要保留會影响專案命名的環境,特別是 `COMPOSE_PROJECT_NAME` 和該次調用選擇的 `.env` 檔案。

用 `docker ps -a --no-trunc` 列出警告中提到的全部容器,並記錄完整 ID、状態和名稱。名稱是線索,標籤與有效 Compose 模型才是歸屬證據。

2. 解析實際 Compose 專案名稱,不要依赖记忆中的檔案名稱

Docker 文檔給出的專案名稱優先級依次為:命令行 `-p`、`COMPOSE_PROJECT_NAME`、所指定檔案中最後一個顶層 `name`、專案目錄的基本名稱,最後才是目前目錄。先重建准確調用,再判斷兩個檔案是否真是不同專案。

使用與原調用相同的檔案、profiles、環境和專案參數執行 `docker compose config`,並使用已安装版本支援的名稱输出選項渲染模型。儲存最終專案名稱和服務清單,但不要暴露秘密值。

兩個仓库如果都從名為 `docker` 的目錄啟動,或自動化為它們提供同一個顯式專案名稱,就可能碰撞。在該分支中,警告里的容器可能仍屬于另一套有效應用。應給專案設定穩定且不同的名稱,不要只為消除警告而刪除另一個專案的容器。

3. 讀取每個警告容器的 Compose 歸屬標籤

檢查每個准確容器 ID,並記錄 `com.docker.compose.project`、`com.docker.compose.service`、`com.docker.compose.project.config_files`、`com.docker.compose.project.working_dir`,以及目前 Compose 版本提供的一次性執行標记。使用 `docker inspect` 的 JSON 输出,不要從截斷的名稱猜歸屬。

把專案標籤與目前調用解析出的實際專案名稱比较。專案標籤不同就是停止条件:刪除任何内容前,先查清為什麼本次執行把它歸入警告。專案標籤相同而服務不在渲染模型中,只能說明它是候選孤立項,還不能證明刪除安全。

再把記錄的設定檔和工作目錄標籤與目前檔案組合比较。這可能暴露檔案改名、`-f` 順序變化、部署自動化從另一個目錄執行,或舊調用曾經有意管理更多服務。

4. 區分四個常見分支

服務改名或刪除後,容器的專案標籤仍匹配,但舊服務標籤不再出現在目前模型中。將其判定為失效前,先用版本控制或部署記錄確認這項變更。

專案名稱衝突表現為專案識別相同,實際應用或檔案根目錄却不同。為每個應用設定穩定、唯一的專案名稱後重新檢查。刪除容器不是首要修復,因為錯誤專案仍會再次碰撞。

一次 `docker compose run` 可能在命令結束或工作流中斷後留下已停止容器。上游 issue 展示過特定版本中反復執行命令會积累容器和警告的案例。把它保留為一個分支:先檢查標籤、状態、退出碼和版本,不要把所有警告都套用到該案例。

舊檔案組合分支出現在同一專案有意使用不同 `-f` 組合或 profiles 時。今天的模型中缺少某服務,並不表示另一種受支援調用不再需要它。清理前先記錄它由哪個模型拥有。

5. 在接触容器前稽核挂載和磁碟區

對每個候選項,從 `docker inspect` 記錄 bind mount、具名磁碟區和匿名磁碟區。已停止容器仍可能是定位資料的最直接地圖,而這些資料的用途未必記錄在其他地方。與服務擁有者確認備份和恢復预期。

Compose down 參考把容器和網路刪除與磁碟區刪除分開說明。應用聲明的具名磁碟區不等于可丢弃的容器層,外部磁碟區則由 Compose 專案之外管理。絕不能僅因為警告寫着孤立,就随手加上 `-v`。

如果容器仍暴露端口或執行工作负載,在停止前識別其使用者和依赖。孤立分類只表示它不在目前模型中,並不能證明工作负載或資料已無用。

6. 選擇範圍最窄的動作並記錄結果

只有在容器已被證實失效、確屬目前專案、不再承載所需工作负載且資料已保全後,才使用與相同檔案組合和專案名稱對應的專案範圍 Compose 命令。文檔說明 `docker compose up --remove-orphans` 會刪除目前檔案中未定義服務的容器,因此必須先證明它的專案範圍正確。

如果原因是專案名稱衝突,應更改專案識別並在不刪除的情况下重新執行。如果容器屬于预期的替代 profile 或檔案組合,應保留並記錄正確調用。如果原因是一次性執行容器,應優先使用正常生命周期控制和针對具體版本的修復,而不是全局 prune。

執行後,用相同 context 再跑一次原命令並儲存新的警告状態。重新檢查存活容器,確認無關專案、端口、網路和資料挂載没有變化。

證據 | 可能分支 | 最小安全動作 專案標籤不同于预期專案 | 歸屬不符 | 停止;先解决調用和命名問题 專案相同,且有意改名後舊服務已不在模型中 | 已確認的失效服務 | 保全資料後,使用專案範圍的孤立清理 無關檔案根目錄解析出相同專案名稱 | 專案名稱衝突 | 設定穩定且不同的專案名稱;保留有效容器 已停止的一次性容器有匹配執行證據 | 一次性執行生命周期 | 檢查退出状態和版本,只刪除已確認的執行容器 服務屬于另一種受支援的檔案或 profile 組合 | 预期资源 | 保留,並記錄拥有它的調用

7. 驗證清理並准備可交給支援人员的歸屬記錄

驗收条件必須具體:警告中的每個具名容器都有已記錄的專案和服務擁有者;保留容器對應受支援調用;被刪容器已證實失效;所需挂載仍存在;原 Compose 命令不再干扰另一個專案。

提交支援请求時,附上已脫敏的 Compose 與 Engine 版本、Docker context、實際專案名稱、檔案順序、容器 ID、專案/服務/設定檔標籤、状態與退出碼,以及挂載類型。報告中不得包含凭據、秘密環境值或私有仓库令牌。

只有在已排除專案名稱優先級、檔案組合差異、標籤、一次性状態和普通生命周期行為後,才升級為可能的 Compose 回歸。警告提到 `--remove-orphans`,並不能單獨證明該標志适用于准確子命令或能修復目前分支。

常見問題

Docker Compose 所說的孤立容器是什麼意思? 它表示容器與實際 Compose 專案識別相關聯,但其服務不在目前模型中。原因可能是真實的服務刪除、專案名稱衝突、不同檔案/profile 組合,或一次性執行容器。

`--remove-orphans` 總是安全吗? 不是。只有在目前專案範圍正確、每個候選項確實失效,而且所需挂載或資料已保全後才安全。該標志遵循目前 Compose 模型;專案名稱或檔案組合錯誤會讓範圍變得危險。

為什麼兩個無關 Compose 檔案會看到彼此的容器? 它們可能透過目錄預設值、環境變量、顶層 name 或顯式 `-p` 解析成同一個專案名稱。應為無關應用設定穩定且不同的專案名稱。

應該用 `docker container prune` 清除警告吗? 不應把它作為第一步。全局 prune 範圍更大,也不能解释歸屬。先檢查標籤、專案命名、状態和挂載,再只刪除已證實失效的容器。

孤立容器的具名磁碟區、外部磁碟區與繫結掛載在刪除前接受檢查的原創概念圖
原創概念圖:執行任何專案範圍的孤立清理前,先檢查掛載並保全資料。 Watch at Ease