Docker Compose
Docker Compose 讓你用一份設定檔(compose.yaml)描述多個容器,然後用一個指令全部啟動。一個網站通常不只一個程式,例如網站本身加上資料庫、快取;如果每個都用 docker run 手動啟動,要打很長的指令,還要自己建立網路。Compose 把這些都寫進設定檔,啟動、停止、分享給同事都變得很簡單。本頁用一個「網頁瀏覽次數計數器」帶你實際做一次。
為什麼要用 Compose?
假設要跑一個網站加一個 Redis 資料庫,不用 Compose 的話要這樣做:
docker network create mynet
docker volume create redis-data
docker run -d --name redis --network mynet -v redis-data:/data redis:8
docker run -d --name web --network mynet -p 8000:8000 -e REDIS_HOST=redis myweb
用 Compose,這些設定全部寫在 compose.yaml 裡,只要一行:
好處是:
- 不用記一長串參數:設定都在檔案裡,打開就看得懂。
- 自動建立網路:同一份 Compose 檔裡的容器,自動可以用服務名稱互相連線。
- 可以放進 Git:同事拿到專案,執行同一個指令就有一樣的環境。
動手做:網頁計數器
這個範例有兩個服務:一個 Flask 網站,每次有人瀏覽就把 Redis 裡的數字加一。
1. 準備檔案
建立一個資料夾,放入以下檔案:
app.py:
import os
import redis
from flask import Flask
app = Flask(__name__)
db = redis.Redis(host=os.getenv("REDIS_HOST", "localhost"), port=6379)
@app.get("/")
def index():
count = db.incr("hits")
return f"Hello Docker!這個頁面被看了 {count} 次。\n"
程式用環境變數 REDIS_HOST 決定要連到哪裡,等一下在 Compose 檔裡設定它。
requirements.txt:
Dockerfile(和 Dockerfile 入門 的寫法相同):
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
RUN useradd --create-home appuser
USER appuser
EXPOSE 8000
CMD ["flask", "--app", "app", "run", "--host", "0.0.0.0", "--port", "8000"]
2. 寫 compose.yaml
services:
web: # 第一個服務,名字叫 web
build: . # 用這個資料夾的 Dockerfile 建置
ports:
- "8000:8000" # 電腦的 8000 埠 → 容器的 8000 埠
environment:
REDIS_HOST: redis # 用服務名稱當作主機名稱
depends_on:
redis:
condition: service_healthy # 等 redis 準備好才啟動
redis: # 第二個服務,名字叫 redis
image: redis:8 # 直接用現成的 Image
volumes:
- redis-data:/data # 資料存在 Volume,刪除容器也不會消失
healthcheck: # 檢查 redis 是否已經可以使用
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5
volumes:
redis-data: # 宣告上面用到的 Volume
services 底下每一個名字就是一個服務(一個容器)。重點在 REDIS_HOST: redis:在 Compose 裡,服務名稱就是主機名稱,網站用 redis 就能連到 Redis 容器。
3. 啟動
打開 http://localhost:8000,每重新整理一次,數字就會加一。
4. 停止與清除
docker compose down # 停止並刪除容器和網路,Volume 會保留
docker compose up -d # 再啟動,數字會接著上次繼續
docker compose down -v # 連 Volume 一起刪除,數字歸零
常用指令
所有指令都要在 compose.yaml 所在的資料夾執行。
| 指令 | 用途 |
|---|---|
docker compose up -d |
背景啟動所有服務 |
docker compose up -d --build |
先重新建置 Image 再啟動(改了程式碼時用) |
docker compose ps |
查看服務狀態 |
docker compose logs -f web |
追蹤 web 服務的日誌 |
docker compose exec web sh |
進入 web 容器 |
docker compose restart web |
重新啟動 web 服務 |
docker compose stop |
停止服務,但保留容器 |
docker compose down |
停止並刪除容器、網路 |
docker compose down -v |
同上,並刪除 Volume(資料會消失) |
depends_on:控制啟動順序
depends_on 讓服務依照順序啟動,但有兩種寫法,效果不一樣:
資料庫啟動後通常還要幾秒才能接受連線。用第一種寫法,網站可能在資料庫還沒準備好時就去連線而出錯。所以依賴資料庫時,建議搭配 healthcheck 使用第二種寫法。
用 .env 檔管理設定
不想把密碼、連接埠直接寫死在 compose.yaml 裡,可以放在同一個資料夾的 .env 檔:
然後在 compose.yaml 用 ${變數名稱} 取用:
用 docker compose config 可以看到變數替換後的結果。
有幾件事要特別注意:
.env只用來替換compose.yaml裡的${...},不會自動傳進容器。要讓容器裡的程式讀到變數,要寫在environment:,或用env_file: .env整個傳進去。- 終端機裡已經設定的環境變數,優先於
.env的值。 - 用
--env-file指定其他檔案時(例如docker compose --env-file .env.prod up -d),預設的.env就不會被讀取。 .env常放密碼,記得加進.gitignore,不要上傳到 Git。
進階用法
- 開發與正式環境用不同設定:寫一份共用的
compose.yaml,再用另一份檔案覆寫差異,例如docker compose -f compose.yaml -f compose.prod.yaml up -d,後面的檔案會蓋過前面的設定。詳見 DevOps 與 CI/CD。 - 限制資源:在服務底下寫
deploy.resources.limits,例如限制記憶體memory: 512M。 - 查看完整設定鍵:請看 docker-compose.yml 寫法。
參考資料
推薦影音
What is Docker Compose?
簡述:Docker 官方短片,說明 Compose 的用途,並示範一個指令啟動整組服務。(Docker 官方)
Ultimate Docker Compose Tutorial
簡述:一小時從零學會 Compose,包含設定檔結構、服務之間的網路、環境變數與 Volume,可以和本頁範例搭配練習。(TechWorld with Nana)
更多影片請見 影音教學。