跳轉到主要內容
Docker Compose 單一 docker run 帶一堆旗標難維護,多個容器更是。Docker Compose 用一份 compose.yaml 把整套應用(多服務、網路、volume)宣告起來,一個指令拉起整組。
現行版本是 docker compose(v2,空格,無連字號),已內建於 Docker CLI。舊的 docker-compose(v1,Python 版)已 EOL、不再維護,不要再用compose.yaml不需要也不要寫 version: 頂層欄位,它在 Compose Specification 已 obsolete,寫了只會收到過時警告。
compose.yaml 裡的鍵,看每個區塊在做什麼:

頂層結構

name: myapp          # 專案名(可選)

services:            # 必要,各個容器
  web:
    image: nginx
networks:            # 可選,自訂網路
volumes:             # 可選,具名 volume
configs:             # 可選,非敏感設定檔
secrets:             # 可選,敏感資料

service 常用鍵

用途
image拉現成映像(固定 tag,別 latest)
build從 Dockerfile build(context / dockerfile / args / target
ports發布埠,主機:容器
environment / env_file環境變數(內聯 / 從檔案)
volumesbind mount 與具名 volume
depends_on啟動順序(配 condition: service_healthy
healthcheck健康檢查指令
restart重啟策略(no / always / on-failure / unless-stopped
networks加入哪些網路
command / entrypoint覆蓋映像的預設指令 / 進入點
profiles把服務歸入 profile,預設不啟動
deploy資源限制與 GPU

建立網路

docker compose up 會自動建一個專案專屬的 bridge 網路(命名 <專案名>_default),所有服務自動加入。服務名就是它在這個網路上的 DNS hostname,所以 web 服務直接用 db:5432 連資料庫,不必管 IP。要分層隔離就自己宣告網路:
services:
  proxy:
    networks: [frontend]
  app:
    networks: [frontend, backend]
  db:
    networks: [backend]          # 只在 backend,proxy 連不到

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
proxydb 不同網路無法直接通訊,只有 app 能同時接觸兩者。

容器群組(專案)名稱

Compose 用「專案名」把這組資源綁在一起,並當命名前綴:
資源命名格式範例(專案 myapp、服務 web
容器<專案>-<服務>-<index>myapp-web-1
網路<專案>_<網路>myapp_default
Volume<專案>_<volume>myapp_db-data
優先序(高到低):docker compose -p <name> > COMPOSE_PROJECT_NAME 環境變數 > 頂層 name: > compose.yaml 所在目錄名。

環境設定參數

寫法適用
environment:少量、可見的變數,直接寫在 YAML,支援 ${VAR} 插值
env_file:變數多、或機密想抽出 YAML 並 gitignore
專案根的 .envcompose.yaml 本身插值用(不是自動注入容器)
插值語法:${VAR} 取值、${VAR:-default} 未設定或為空用預設、${VAR:?msg} 未設定就報錯中止。容器內環境變數的優先序(高到低):docker compose run -e > environment: > env_file: > 宿主 shell 繼承 > Dockerfile ENV

使用 GPU

官方寫法是在服務的 deploy.resources.reservations.devices 宣告(主機需先裝 NVIDIA Container Toolkit):
services:
  trainer:
    image: nvidia/cuda:12.9.0-base-ubuntu22.04
    command: nvidia-smi
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: all              # 或 count: 1 / device_ids: ['0','3']
              capabilities: [gpu]     # 必填,缺了部署會報錯

效能與啟動順序

  • depends_onhealthcheck:用 condition: service_healthy 等依賴服務真的 ready 才啟動,避免應用搶在資料庫還沒起來時連線失敗。
  • 資源限制deploy.resources.limitscpus / memory 在 standalone(非 Swarm)模式也生效。
  • pull_policy 與 build cache:控制要不要每次都 pull、build 重用快取。
  • 啟動相關:up -d(背景)、--build(先重 build)、--scale web=3(擴成 3 份)、--wait(等到全部 healthy)。
services:
  app:
    depends_on:
      db:
        condition: service_healthy
  db:
    image: postgres:18
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${DB_USER}"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s

volume 與 bind mount 映射

Compose 的 volumes: 同時管 bind mount 與具名 volume,靠來源寫法區分(差別見 資料落點):
services:
  app:
    volumes:
      - ./src:/app/src              # bind mount:主機相對路徑
      - ./config.yaml:/app/config.yaml:ro   # 唯讀
      - app-data:/var/lib/data      # 具名 volume(需頂層宣告)

volumes:
  app-data:
要保留的資料用具名 volume,開發即時同步用 bind mount。不在 volumes: 指定的路徑,寫進去就只在容器可寫層,容器一刪就沒。

一份完整的 compose.yaml

# compose.yaml — 不需要也不要寫 version 欄位(已 obsolete)
name: myapp

services:
  web:
    build:
      context: .
      target: production
    ports:
      - "8080:80"
    environment:
      DATABASE_URL: "postgresql://db:5432/${DB_NAME:-mydb}"
    env_file:
      - path: .env
        required: false
    volumes:
      - ./static:/app/static:ro
      - upload-data:/app/uploads
    depends_on:
      db:
        condition: service_healthy
    restart: unless-stopped
    networks: [frontend, backend]

  db:
    image: postgres:18
    environment:
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: ${DB_NAME:-mydb}
    volumes:
      - db-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${DB_USER}"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s
    restart: unless-stopped
    networks: [backend]

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge

volumes:
  db-data:
  upload-data:

docker compose 常用指令

docker compose up -d            # 背景拉起整組
docker compose up -d --build    # 先重 build 再起
docker compose ps               # 看這個專案的容器
docker compose logs -f web      # 即時看 web 服務日誌
docker compose exec web sh      # 進 web 服務的 shell
docker compose config           # 展開並驗證 compose 檔(成功回 exit 0)
docker compose build --no-cache # 不用快取重 build
docker compose down             # 停止並移除容器與網路
一份 compose.yaml 起整組長這樣:
docker compose down -v 會刪掉具名 volumecompose.yamlvolumes: 區段宣告的那些),資料庫資料常在裡面,下去就沒了。只想停服務、保留資料用不帶 -vdocker compose down

接下來

官方參考:docs.docker.com/reference/compose-fileCompose GPU 支援