目錄

Docker Compose 教學:用一個檔案管理多個容器

一個真實的應用通常不只一個容器:網站、資料庫、快取……每個都要記得一長串 docker run 參數,還要先建網路、Volume,並注意啟動順序。

Docker Compose 讓你把這些設定寫進一個 YAML 檔,然後一個指令全部啟動:

docker compose up -d

安裝與版本

  • Docker Desktop(Windows、macOS)已內建 Compose。
  • Linux:照 安裝 Docker 的步驟安裝 docker-compose-plugin 即可。
$ docker compose version
Docker Compose version v5.6.0

舊版的獨立程式叫 docker-compose(中間有連字號,v1),已經停止維護;現在請使用 docker compose(空格)。Compose 的版本號從 v2 直接跳到 v5,用法沒有改變。網路上的舊教學把兩者混用,指令和參數大致相同。

範例專案:網站 + 資料庫 + 管理介面

建立資料夾 compose-demo,結構如下:

compose-demo/
├── compose.yaml
└── site/
    └── index.html

site/index.html 放一個簡單的網頁(內容隨意)。compose.yaml:

services:
  web:
    image: nginx:1.30-alpine
    ports:
      - "8080:80"
    volumes:
      - ./site:/usr/share/nginx/html:ro

  db:
    image: postgres:18
    environment:
      POSTGRES_PASSWORD: example
    volumes:
      - pgdata:/var/lib/postgresql

  adminer:
    image: adminer
    ports:
      - "8081:8080"
    depends_on:
      - db

volumes:
  pgdata:

三個服務:

服務作用
webnginx,把 ./site 資料夾當作網站,主機 8080
dbPostgreSQL 18,資料存在名為 pgdata 的 Volume(注意 18 版掛載的是 /var/lib/postgresql,見 Volume)
adminer網頁版資料庫管理工具,主機 8081

同樣的設定如果用 docker run 寫,需要先 docker network create、docker volume create,再執行三個很長的 docker run。

啟動:docker compose up

在 compose-demo 資料夾裡執行:

$ docker compose up -d
[+] up 34/34
 ✔ Image nginx:1.30-alpine          Pulled                                                      7.8s
 ✔ Image adminer                    Pulled                                                      8.7s
 ✔ Network compose-demo_default     Created                                                     0.1s
 ✔ Volume compose-demo_pgdata       Created                                                     0.0s
 ✔ Container compose-demo-web-1     Started                                                     1.7s
 ✔ Container compose-demo-db-1      Started                                                     0.8s
 ✔ Container compose-demo-adminer-1 Started                                                     1.0s

一個指令完成了:下載映像檔(Pulled,第一次才會有)、建立網路與 Volume、啟動三個容器。

$ docker compose ps
NAME                     IMAGE               COMMAND                  SERVICE   CREATED          STATUS          PORTS
compose-demo-adminer-1   adminer             "entrypoint.sh docke…"   adminer   10 seconds ago   Up 9 seconds    0.0.0.0:8081->8080/tcp, [::]:8081->8080/tcp
compose-demo-db-1        postgres:18         "docker-entrypoint.s…"   db        10 seconds ago   Up 10 seconds   5432/tcp
compose-demo-web-1       nginx:1.30-alpine   "/docker-entrypoint.…"   web       10 seconds ago   Up 9 seconds    0.0.0.0:8080->80/tcp, [::]:8080->80/tcp

$ docker network ls --filter name=compose-demo
NETWORK ID     NAME                   DRIVER    SCOPE
a722da926fbd   compose-demo_default   bridge    local

$ docker volume ls --filter name=compose-demo
DRIVER    VOLUME NAME
local     compose-demo_pgdata
  • 容器名稱是 專案名稱-服務名稱-編號。專案名稱預設是資料夾名稱(compose-demo),所以不同資料夾的專案不會互相干擾。
  • Compose 自動建立了 compose-demo_default 網路,三個服務都在裡面,可以用服務名稱互相連線。
  • pgdata Volume 實際的名稱是 compose-demo_pgdata。
  • db 沒有設定 ports,所以 PORTS 欄位只有 5432/tcp,外部連不到它。

打開 http://localhost:8080:

Compose 啟動的 nginx 顯示 site/index.html
web 服務顯示 site/index.html 的內容

用 Adminer 管理資料庫

打開 http://localhost:8081 是 Adminer 的登入畫面。注意 System 預設是 MySQL:

Adminer 登入畫面預設 System 為 MySQL
Adminer 的預設:System 是 MySQL / MariaDB,Server 已自動填入 db

依照下面的設定登入:

欄位填入
SystemPostgreSQL(一定要改,否則會用 MySQL 的方式連線而失敗)
Serverdb(服務名稱,透過 Compose 網路解析)
Usernamepostgres
Passwordexample(compose.yaml 中的 POSTGRES_PASSWORD)
Adminer 登入畫面,System 選 PostgreSQL
System 改成 PostgreSQL 後按 Login

登入成功後,畫面會顯示 PostgreSQL 的版本與資料庫列表:

Adminer 登入後顯示 PostgreSQL 版本與資料庫列表
Adminer 透過 Compose 網路連到 db 服務的 PostgreSQL

點選左側的 SQL command,輸入 SQL:

CREATE TABLE guestbook (id serial PRIMARY KEY, name text, message text);
INSERT INTO guestbook (name, message) VALUES ('Docker', 'Hello from Compose!');
SELECT * FROM guestbook;
Adminer SQL command 輸入畫面
在 SQL command 輸入 SQL,按 Execute

按 Execute,三個指令依序執行,最後的 SELECT 列出剛才新增的資料:

Adminer 執行 SQL 的結果
建立資料表、新增一筆資料、查詢結果

查看日誌

$ docker compose logs --tail 2
web-1  | 2026/10/13 00:14:23 [notice] 1#1: start worker processes
web-1  | 2026/10/13 00:14:23 [notice] 1#1: start worker process 30
db-1   | 2026-10-13 00:14:24.205 UTC [71] LOG:  database system was shut down at 2026-10-13 00:14:24 UTC
db-1   | 2026-10-13 00:14:24.210 UTC [1] LOG:  database system is ready to accept connections
adminer-1  | [Tue Oct 13 00:14:22 2026] PHP 8.4.26 Development Server (http://[::]:8080) started

docker compose logs 會合併顯示所有服務的日誌,每行前面標示是哪個服務。--tail 2 只顯示每個服務的最後 2 行,-f 持續追蹤,docker compose logs db 只看 db。

停止與啟動

$ docker compose stop
[+] stop 3/3
 ✔ Container compose-demo-adminer-1 Stopped                                                     0.4s
 ✔ Container compose-demo-web-1     Stopped                                                     0.4s
 ✔ Container compose-demo-db-1      Stopped                                                     0.3s

$ docker compose ps -a
NAME                     IMAGE               COMMAND                  SERVICE   CREATED          STATUS                              PORTS
compose-demo-adminer-1   adminer             "entrypoint.sh docke…"   adminer   53 seconds ago   Exited (0) Less than a second ago
compose-demo-db-1        postgres:18         "docker-entrypoint.s…"   db        53 seconds ago   Exited (0) Less than a second ago
compose-demo-web-1       nginx:1.30-alpine   "/docker-entrypoint.…"   web       53 seconds ago   Exited (0) Less than a second ago

$ docker compose start
[+] start 3/3
 ✔ Container compose-demo-db-1      Started                                                     0.3s
 ✔ Container compose-demo-web-1     Started                                                     1.0s
 ✔ Container compose-demo-adminer-1 Started                                                     0.4s

stop 只是停止容器(Exited (0)),容器、網路、Volume 都還在;start 再把它們啟動。

down:刪除容器,但保留資料

$ docker compose down
[+] down 4/4
 ✔ Container compose-demo-adminer-1 Removed                                                     0.7s
 ✔ Container compose-demo-web-1     Removed                                                     0.7s
 ✔ Container compose-demo-db-1      Removed                                                     0.3s
 ✔ Network compose-demo_default     Removed                                                     0.1s

down 刪除了容器和網路,但沒有刪除 Volume。重新 up,資料還在:

$ docker compose up -d
[+] up 4/4
 ✔ Network compose-demo_default     Created                                                     0.1s
 ✔ Container compose-demo-web-1     Started                                                     0.7s
 ✔ Container compose-demo-db-1      Started                                                     1.1s
 ✔ Container compose-demo-adminer-1 Started                                                     1.6s

$ docker compose exec db psql -U postgres -c "SELECT * FROM guestbook;"
 id |  name  |       message
----+--------+---------------------
  1 | Docker | Hello from Compose!
(1 row)

down -v:連資料一起刪除

$ docker compose down -v
[+] down 5/5
 ✔ Container compose-demo-adminer-1 Removed                                                     0.7s
 ✔ Container compose-demo-web-1     Removed                                                     0.7s
 ✔ Container compose-demo-db-1      Removed                                                     0.2s
 ✔ Volume compose-demo_pgdata       Removed                                                     0.1s
 ✔ Network compose-demo_default     Removed                                                     0.1s

加上 -v 會一併刪除 compose-demo_pgdata Volume,資料庫的資料就沒了。正式環境請謹慎使用 down -v。

基本操作整理

docker compose up -d        # 建立並在背景啟動所有服務
docker compose ps           # 查看服務狀態
docker compose logs -f      # 追蹤所有服務的日誌
docker compose logs -f db   # 只看 db
docker compose stop         # 停止(容器保留)
docker compose start        # 再次啟動
docker compose down         # 停止並刪除容器與網路(Volume 保留)
docker compose down -v      # 連 Volume 一起刪除(資料會消失!)

修改 compose.yaml 之後,再執行一次 docker compose up -d,Compose 只會重建有變動的服務(實例見 docker compose 指令)。

專案名稱與檔案名稱

  • 專案名稱預設是資料夾名稱,也可以在 compose.yaml 最上面指定 name: myproject,或用 docker compose -p myproject。
  • Compose 預設依序尋找 compose.yaml、compose.yml、docker-compose.yaml、docker-compose.yml。新專案建議使用 compose.yaml。
  • 檔案開頭的 version: "3.8" 是舊格式的寫法,現在已經不需要,寫了只會出現警告。

下一步

重點回顧

  • compose.yaml 描述多個服務、網路與 Volume,一個指令就能全部啟動。
  • Compose 自動建立專案網路,服務之間用服務名稱連線。
  • docker compose down 保留 Volume;down -v 會刪除資料。
  • Docker Desktop 會把 Compose 專案群組顯示。

動手練習

練習 1:在本章的專案中,用一個指令只看 db 服務最後 5 行日誌。

答案
docker compose logs --tail 5 db

練習 2:執行 docker compose down 後再 up -d,Adminer 中建立的資料表還在嗎?換成 down -v 呢?

答案

down 後資料還在,因為 pgdata Volume 被保留;down -v 會刪除 Volume,資料庫重新初始化,資料表就不見了。

常見問題

docker-compose 和 docker compose 有什麼不同?

docker-compose(有連字號)是已停止維護的 v1 獨立程式;現在使用 Docker CLI 的外掛 docker compose(空格),本教學使用 v5。

compose.yaml 和 docker-compose.yml 都可以嗎?

都可以,Compose 會依序尋找。新專案建議使用 compose.yaml。

專案名稱是怎麼決定的?

預設是 compose.yaml 所在資料夾的名稱,容器、網路、Volume 的名稱都會加上它作為前綴。可以用 name: 或 -p 指定。

更新於 2026年10月14日