Docker Compose 執行流程
當執行 docker-compose up
命令時,Docker Compose 會依序執行以下操作:
檢查是否需要建置映像檔:Docker Compose 會查看 docker-compose.yml 中每個服務的 build 設定。
建置映像檔:如果服務配置了 build 選項(指向一個包含 Dockerfile 的目錄),Docker 會使用該目錄中的 Dockerfile 來建置映像檔。建置過程會執行 Dockerfile 中的所有指令。
建立和啟動容器:一旦映像檔建置完成,Docker Compose 會使用這些映像檔建立容器,並根據 docker-compose.yml 中的設定啟動它們。
所以,你不需要自己手動執行 Dockerfile 中的指令。當你執行 docker-compose up 時,整個過程會自動進行:
docker-compose up
這個命令會:
建置所有需要的映像檔(根據 Dockerfile)
建立並啟動所有服務的容器
顯示所有容器的日誌輸出
如果你只想建置映像檔但不啟動容器,可以使用:
docker-compose build
如果你修改了 Dockerfile 並需要重新建置映像檔,可以使用:
docker-compose up --build
問題排解記錄
問題一:Angular 建構預算超出限制
在執行 docker-compose up
時,前端的建構過程發生了錯誤。主要問題是 Angular 應用打包時超出了預設的大小限制。這是一個常見的問題,與安全性無關,只是 Angular 的建構預算限制。
錯誤訊息顯示:
✘ [ERROR] bundle initial exceeded maximum budget. Budget 1.00 MB was not met by 21.09 kB with a total of 1.02 MB.
這表示應用打包後大小是 1.02MB,而設定的預算上限是 1.00MB。
解決方案
修改前端的 Angular 配置:
在前端專案中找到
angular.json
檔案找到
budgets
部分,應該看起來像這樣:"budgets": [ { "type": "initial", "maximumWarning": "500kb", "maximumError": "1mb" }, { "type": "anyComponentStyle", "maximumWarning": "2kb", "maximumError": "4kb" }]
將
maximumError
的值從1mb
增加到2mb
,以允許更大的套件大小
修改後再次執行 docker-compose up
就能解決這個問題。
問題二:容器命名衝突
遇到了容器命名衝突的問題。錯誤訊息表示名為 "/voting_db" 的容器已經存在,所以 Docker 無法建立一個同名的新容器。
這通常發生在你之前已經執行過 Docker Compose,但容器沒有被正確移除的情況下。
解決方案
有兩種方式可以解決這個問題:
移除現有的容器:
docker rm voting_db
這會移除已存在的容器,讓你可以重新建立一個同名的容器。
使用 down 命令(建議使用這種方式):
docker-compose down
這個命令會停止並移除所有由 docker-compose.yml 定義的容器、網路和磁碟區,讓你可以重新開始。
然後,再次執行:
docker-compose up
人為中斷或不正常關閉 Docker 容器時,常會發生這種情況。使用 docker-compose down
是一個好習慣,它能確保所有資源被正確清理。
問題三:後端缺少 nodemon 套件
前端和資料庫容器成功啟動,但後端容器一直報錯:
sh: 1: nodemon: not found
這表示後端容器中沒有安裝 nodemon 套件,而 docker-compose.yml 中的命令卻嘗試使用它。
解決方案一:在啟動時安裝 nodemon
參考:Stack Overflow - Docker /bin/bash: nodemon: command not found
修改 docker-compose.yml 中後端服務的 command 設定,確保在執行程式之前先安裝所需的套件:
command: sh -c "npm install -g nodemon && npm install && npm run dev"
這個命令會:
全域安裝 nodemon 套件
安裝專案的相依套件
執行 package.json 中定義的 dev 腳本
解決方案二:移除卷掛載
另一個解決方案是移除 volumes 設定:
# 移除這一行
# volumes:
# - ./voting-system-be:/app
當使用 volumes 將本地目錄掛載到容器的 /app 目錄時,它會覆蓋容器內的檔案,包括在 Dockerfile 建構過程中安裝的相依套件。移除 volumes 設定後,容器會使用在建構階段安裝好的相依套件,而不是使用掛載進來的可能不完整的本地目錄。
為什麼會發生這個問題?
原本 be 裡就有主管建置好的 Dockerfile
跟 docker-compose.yml
,be 可以單獨啟動 server 跟 db,那為什麼在父容器啟動時就會報錯沒有找到 nodemon 呢?
這是因為:
卷掛載覆蓋了容器內容:當使用
volumes: - ./voting-system-be:/app
時,它會覆蓋容器內的 /app 目錄,包括在 Dockerfile 建構階段安裝的 nodemon。環境差異:在 Docker 環境中,容器啟動後的執行環境與建構環境不完全相同。
路徑問題:全域安裝的套件可能在不同的路徑,而 PATH 環境變數設定可能不同。
解決方案比較
方案一:在啟動時安裝套件
volumes:
- ./voting-system-be:/app
command: sh -c "npm install -g nodemon && npm install && npm run dev"
優點:
保留卷掛載,可以實時更新程式碼
確保所有必要的套件都已安裝
缺點:
每次啟動容器都需要重新安裝套件,啟動較慢
不是最佳實踐,尤其對於生產環境
方案二:移除卷掛載
# 不使用 volumes
command: npm run dev # 甚至可以移除此行,使用 Dockerfile 中的 CMD
優點:
更可靠的啟動流程
使用 Dockerfile 中已經安裝好的套件
啟動速度更快
缺點:
修改程式碼後需要重新建置容器,無法即時反映變更
失去開發環境中的「熱更新」優勢
在你的情境中,使用移除卷掛載的方式更合適。實際上,如果 Dockerfile 中已經定義了 CMD 指令,docker-compose.yml 中的 command 行也可以移除,讓容器使用 Dockerfile 中定義的預設命令。
經驗總結
建立 Docker 容器時常會遇到各種問題,保持耐心並分析錯誤訊息是解決問題的關鍵。
使用
docker-compose down
而不是直接關閉終端機,可以避免容器命名衝突的問題。容器內的環境和本地開發環境可能不同,需要確保所有相依套件都在容器中正確安裝。
理解卷掛載(volumes)的工作原理很重要:它會覆蓋容器內的檔案,這可能會導致在 Dockerfile 中安裝的套件「消失」。
在開發環境中需要權衡「即時程式碼更新」與「可靠啟動」之間的取捨。
Angular 的建構預算設定可能需要根據專案的實際大小來調整。
編寫 docker-compose.yml 時,要考慮各服務啟動的順序和相依關係,特別是後端服務可能依賴資料庫服務。
Last updated