5.2 撰寫 docker-compose.yml#
用一份檔案宣告整個架構#
把 5.1 節那四行 docker run 改寫成 docker-compose.yml(放在專案根目錄):
services:
api:
build: .
ports:
- "8000:8000"
environment:
- DATABASE_URL=postgres://postgres:mysecret@db:5432/mydb
- REDIS_URL=redis://cache:6379
depends_on:
- db
- cache
volumes:
- .:/app
- /app/node_modules
db:
image: postgres:16
environment:
- POSTGRES_PASSWORD=mysecret
volumes:
- pgdata:/var/lib/postgresql/data
cache:
image: redis:7
volumes:
pgdata:
對照 docker run 的每個部分,各個配置的意義:
| 配置 | 對應 docker run | 意義 |
|---|---|---|
image: | 鏡像名稱 | 用現成 Image |
build: | docker build . | 用這個目錄的 Dockerfile 建構(二選一) |
ports: | -p | 埠對映,只有要對外暴露的服務才需要 |
volumes: | -v | 掛載(Bind Mount 或 volume) |
environment: | -e | 環境變數 |
depends_on: | (人工顧順序) | 宣告啟動順序的相依 |
networks: | --network | 通常不用寫——Compose 自動建網路 |
幾個關鍵細節#
服務名稱就是主機名稱#
api 的 DATABASE_URL 中,host 寫 db——Compose 自動建立網路(複習 4.2 節),每個服務可以用服務名稱互相訪問。這是 Compose 最好用的地方:你完全不用管網路設定。
build 與 image 二選一(也可以同時有)#
image: postgres:16:直接用現成 Imagebuild: .:用本專案的 Dockerfile 建構- 兩個都寫:建構之後順便打上
image:指定的標籤(方便推上倉庫)
depends_on 只管啟動順序#
depends_on 保證 db 先啟動,但不保證 Postgres 已經準備好接受連線(啟動到就緒有幾秒差距)。應用程式要有連線重試的邏輯,這是初學者最常踩的坑。
開發用 Bind Mount、資料用 volume#
db的pgdata是具名 volume:資料庫資料要活得比容器久(複習 4.1 節)api的.:/app是 Bind Mount:開發時改主機程式碼、容器內即時生效/app/node_modules是一個「排除」技巧:避免主機的 node_modules 蓋掉容器內安裝的依賴
環境變數與機密#
正式的專案不該把密碼寫死在 YAML 裡。用 .env 檔搭配變數引用:
db:
image: postgres:16
environment:
- POSTGRES_PASSWORD=${DB_PASSWORD}
.env 檔(記得放進 .gitignore,不進版本控制):
DB_PASSWORD=mysecret
本章小結#
services定義每個容器,image/build二選一(可同時有)- 服務名稱就是主機名稱,網路 Compose 自動建,通常不用寫
networks depends_on只保證啟動順序,不保證服務已就緒——要有連線重試- 資料用具名 volume,開發程式碼用 Bind Mount
- 機密用
.env+${VAR}引用,.env不進 Git
想一想#
- 為什麼 Compose 通常不用寫
networks配置?它背後自動做了什麼? depends_on加了之後,為什麼應用程式還可能連不上資料庫?怎麼解?- 為什麼
.env不該進 Git?那要怎麼讓同事知道需要哪些環境變數?(提示:放一份.env.example)