📚 延伸閱讀
📖 前置知識:如果對 Linux 終端機不熟悉,建議先閱讀 Linux 終端機入門:開發者必備指令
這篇文章要解決什麼問題?
後端工程師:「奇怪,我更新了 A 專案的套件,結果 B 專案跑不起來了…」
資深工程師:「因為它們共用系統環境,套件版本互相衝突了。」
後端工程師:「那我要怎麼隔離?每個專案開一台虛擬機?」
資深工程師:「不用那麼麻煩,用 Docker。每個專案跑在獨立的容器裡,互不干擾。」
後端工程師:「容器?那跟虛擬機有什麼不同?」
資深工程師:「容器更輕量,啟動只要幾秒,而且吃的資源少很多。」
這篇文章會讓你理解:
- Docker 解決什麼問題
- Container 和 Image 是什麼
- Docker Compose 怎麼用
- 讀懂 docker-compose.yml 檔案
技術概念
Docker 解決什麼問題?
傳統開發環境的痛點:
| 問題 | 情境 |
|---|---|
| 版本不一致 | 「我的 Python 是 3.9,你的是 3.12」 |
| 環境污染 | 「裝了 A 專案的套件,B 專案壞了」 |
| 安裝複雜 | 「PostgreSQL 在 Windows 裝不起來」 |
| 難以重現 | 「在我電腦可以跑啊」 |
Docker 的解法:把應用程式和它需要的環境打包在一起。
傳統方式:
應用程式 → 依賴作業系統環境 → 每台電腦都要裝一遍
Docker 方式:
應用程式 + 環境 → 打包成 Image → 任何電腦都能跑
Container vs 虛擬機
| 比較 | 虛擬機 (VM) | Container |
|---|---|---|
| 啟動時間 | 分鐘級 | 秒級 |
| 資源佔用 | GB 級(含完整 OS) | MB 級(共用 OS 核心) |
| 隔離程度 | 完全隔離 | 程序級隔離 |
| 適用場景 | 需要不同 OS | 同 OS 下的應用隔離 |
簡單比喻:
- 虛擬機:每個應用住一棟獨立的房子(含地基、水電)
- Container:每個應用住公寓的一間房(共用大樓基礎設施)
Image vs Container
這是最重要的概念:
| 概念 | 說明 | 比喻 |
|---|---|---|
| Image(映像檔) | 唯讀的模板,包含應用程式和環境 | 蛋糕食譜 |
| Container(容器) | Image 的執行實例,可以啟動、停止 | 按食譜做出的蛋糕 |
一個 Image 可以建立多個 Container:
postgres:16-alpine (Image)
├── ching-tech-os-db (Container 1)
├── another-project-db (Container 2)
└── test-db (Container 3)
Docker Compose 是什麼?
Docker 本身一次只管理一個 Container。但實際專案通常需要多個服務:
一個 Web 專案可能需要:
├── PostgreSQL(資料庫)
├── Redis(快取)
├── Nginx(反向代理)
└── code-server(開發環境)
Docker Compose 讓你用一個檔案(docker-compose.yml)定義所有服務,一個指令全部啟動。
Docker Compose v1 vs v2
| 版本 | 指令 | 狀態 |
|---|---|---|
| v1 | docker-compose up |
已棄用 |
| v2 | docker compose up |
現行標準 |
v2 已內建於 Docker,不需另外安裝。注意指令是 docker compose(空格),不是 docker-compose(連字號)。
# 檢查版本
docker --version # Docker version 28.5.0
docker compose version # Docker Compose version v2.39.4
安裝 Docker
Ubuntu / Debian
使用官方安裝腳本(最簡單):
# 下載並執行官方安裝腳本
curl -fsSL https://get.docker.com | sh
# 將目前使用者加入 docker 群組(免 sudo)
sudo usermod -aG docker $USER
# 重新登入或執行以下指令讓群組生效
newgrp docker
# 驗證安裝
docker --version
docker compose version
其他系統
| 系統 | 安裝方式 |
|---|---|
| macOS | 下載 Docker Desktop |
| Windows | 下載 Docker Desktop(需啟用 WSL2) |
| CentOS/RHEL | 同樣可用 curl -fsSL https://get.docker.com | sh |
注意:安裝後若遇到權限問題(
permission denied),確認已執行usermod -aG docker $USER並重新登入。
跟著做:理解 docker-compose.yml
以下是我們專案實際使用的 docker-compose.yml,逐段解說:
完整檔案
services:
postgres:
image: postgres:16-alpine
container_name: ching-tech-os-db
environment:
POSTGRES_USER: ${DB_USER:-ching_tech}
POSTGRES_PASSWORD: ${DB_PASSWORD:-ching_tech_dev}
POSTGRES_DB: ${DB_NAME:-ching_tech_os}
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "${DB_PORT:-5432}:5432"
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-ching_tech} -d ${DB_NAME:-ching_tech_os}"]
interval: 10s
timeout: 5s
retries: 5
code-server:
image: codercom/code-server:latest
container_name: ching-tech-os-code
command: ["--auth", "none", "--bind-addr", "0.0.0.0:8080"]
volumes:
- ${HOME}/SDD:/home/coder/SDD
- code_server_data:/home/coder/.local
ports:
- "${CODE_PORT:-8443}:8080"
restart: unless-stopped
working_dir: /home/coder/SDD/ching-tech-os
volumes:
postgres_data:
code_server_data:
逐段解說
1. services(服務定義)
services:
postgres: # 服務名稱(自訂)
...
code-server: # 另一個服務
...
services 下面定義所有要啟動的服務,名稱可以自訂。
2. image(映像檔)
image: postgres:16-alpine
指定要使用的 Image:
postgres:Image 名稱(來自 Docker Hub)16:版本號alpine:輕量版(基於 Alpine Linux,體積小)
常見的 Image 來源:
- Docker Hub:官方映像檔庫
- 搜尋方式:
docker search postgres
3. container_name(容器名稱)
container_name: ching-tech-os-db
指定容器名稱,方便辨識。如果不指定,Docker 會自動產生名稱。
4. environment(環境變數)
environment:
POSTGRES_USER: ${DB_USER:-ching_tech}
POSTGRES_PASSWORD: ${DB_PASSWORD:-ching_tech_dev}
POSTGRES_DB: ${DB_NAME:-ching_tech_os}
設定容器內的環境變數。${VAR:-default} 語法:
- 如果
DB_USER環境變數有設定,使用它的值 - 如果沒有設定,使用預設值
ching_tech
環境變數可以寫在 .env 檔案:
# .env
DB_USER=ching_tech
DB_PASSWORD=my_secret_password
DB_NAME=ching_tech_os
5. volumes(資料持久化)
volumes:
- postgres_data:/var/lib/postgresql/data # Named Volume
- ${HOME}/SDD:/home/coder/SDD # Bind Mount
Container 刪除後,裡面的資料會消失。Volume 讓資料保留下來。
| 類型 | 語法 | 說明 |
|---|---|---|
| Named Volume | 名稱:容器路徑 |
Docker 管理,存在 Docker 資料目錄 |
| Bind Mount | 主機路徑:容器路徑 |
直接掛載主機目錄 |
# 檔案最下方要宣告 Named Volume
volumes:
postgres_data: # 宣告名為 postgres_data 的 Volume
code_server_data:
6. ports(埠號映射)
ports:
- "${DB_PORT:-5432}:5432"
# ↑ 主機埠號 ↑ 容器埠號
格式:主機埠號:容器埠號
- 容器內 PostgreSQL 監聽 5432
- 映射到主機的 5432(或
.env指定的埠號) - 外部透過
localhost:5432連線
7. restart(重啟策略)
restart: unless-stopped
| 策略 | 說明 |
|---|---|
no |
不自動重啟(預設) |
always |
總是重啟 |
unless-stopped |
除非手動停止,否則重啟 |
on-failure |
只在錯誤退出時重啟 |
8. healthcheck(健康檢查)
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ching_tech -d ching_tech_os"]
interval: 10s # 每 10 秒檢查一次
timeout: 5s # 檢查超時時間
retries: 5 # 連續失敗 5 次才算不健康
讓 Docker 知道服務是否正常運作。其他服務可以等待它 healthy 後再啟動。
9. command(覆蓋預設指令)
command: ["--auth", "none", "--bind-addr", "0.0.0.0:8080"]
覆蓋 Image 的預設啟動指令。這裡讓 code-server 不需要密碼認證。
10. working_dir(工作目錄)
working_dir: /home/coder/SDD/ching-tech-os
設定容器啟動後的預設工作目錄。
常用指令速查
基本操作
# 啟動所有服務(背景執行)
docker compose up -d
# 停止所有服務
docker compose down
# 停止並刪除 Volume(資料會遺失!)
docker compose down -v
# 查看運行中的容器
docker compose ps
# 查看日誌(持續追蹤)
docker compose logs -f
# 查看特定服務的日誌
docker compose logs -f postgres
進入容器
# 進入容器執行指令
docker compose exec postgres psql -U ching_tech -d ching_tech_os
# 進入容器的 shell
docker compose exec postgres bash
單獨操作服務
# 只啟動特定服務
docker compose up -d postgres
# 只停止特定服務
docker compose stop code-server
# 重啟特定服務
docker compose restart postgres
清理
# 刪除停止的容器
docker container prune
# 刪除未使用的 Image
docker image prune
# 刪除未使用的 Volume(危險!)
docker volume prune
# 全部清理(危險!)
docker system prune -a
進階技巧
1. 查看容器狀態
# 詳細狀態(含健康檢查)
docker compose ps -a
# 輸出範例:
NAME STATUS PORTS
ching-tech-os-db running (healthy) 0.0.0.0:5432->5432/tcp
ching-tech-os-code running 0.0.0.0:8443->8080/tcp
2. 查看 Volume 位置
# 列出所有 Volume
docker volume ls
# 查看 Volume 詳細資訊
docker volume inspect docker_postgres_data
3. 備份與還原
# 備份資料庫
docker compose exec postgres pg_dump -U ching_tech ching_tech_os > backup.sql
# 還原資料庫
docker compose exec -T postgres psql -U ching_tech ching_tech_os < backup.sql
4. 常見問題排除
埠號被佔用:
# 找出佔用埠號的程式
lsof -i :5432
# 解法:修改 .env 換一個埠號
DB_PORT=5433
容器無法啟動:
# 查看錯誤訊息
docker compose logs postgres
# 常見原因:
# - Image 下載失敗(網路問題)
# - Volume 權限問題
# - 埠號衝突
清除重來:
# 停止並刪除所有容器和 Volume
docker compose down -v
# 重新啟動
docker compose up -d
小結
這篇文章介紹了:
| 概念 | 重點 |
|---|---|
| Docker 用途 | 解決環境不一致、安裝複雜的問題 |
| Image vs Container | Image 是模板,Container 是實例 |
| Docker Compose v2 | 用 docker compose(空格)指令 |
| docker-compose.yml | services、volumes、ports、environment |
| 常用指令 | up、down、ps、logs、exec |
理解這些概念後,就可以閱讀 Docker Compose 一鍵啟動開發環境,實際操作我們的開發環境了!
參考資源
- Docker 官方文件
- Docker Compose 官方文件
- Docker Hub(映像檔庫)
- Play with Docker(線上練習環境)