開發者必學 Docker:映像檔、容器與 Compose
你聽過 Docker 和容器,但當你嘗試使用時,卻被映像檔(image)、容器(container)、磁碟區(volume)和 Compose 等術語搞得暈頭轉向。或者你已經在使用 Docker,但映像檔過於龐大、建置速度緩慢,管理多個服務更是麻煩。本指南將化繁為簡,涵蓋開發者必備的 Docker 核心知識,專注於你真正需要知道的重點,以高效地建置、執行和管理容器化應用程式。
為什麼需要 Docker?它解決了什麼問題
在 Docker 出現之前,部署應用程式意味著必須完全匹配環境:特定的作業系統版本、函式庫和設定。「在我的機器上可以運作」之所以成為陳腔濫調,正是因為它經常發生。Docker 透過將應用程式及其相依性打包成一個可攜的單元——容器——來解決這個問題。容器輕量、隔離,並且在任何安裝了 Docker 的地方都能一致地執行。
映像檔 vs. 容器:核心區別
映像檔是一個唯讀範本,包含你的應用程式碼、執行環境、函式庫和設定。容器則是映像檔的執行實例。可以將映像檔想成類別(class),容器想成物件(object)。你可以從同一個映像檔執行多個容器,每個容器彼此隔離。
映像檔如何建置
映像檔是從 Dockerfile 建置而成,這是一個包含指令的文字檔。以下是一個 Node.js 應用程式的最小範例:
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
每個指令都會建立一個層(layer)。層會被快取,因此如果你只修改原始碼,Docker 會重複使用相依性的快取層,讓重新建置變得快速。
建置與執行
建置映像檔並執行容器:
docker build -t my-app .
docker run -p 3000:3000 my-app
-p 旗標會將主機的 3000 埠對應到容器的 3000 埠。
打造高效 Docker 映像檔的最佳實踐
過大的映像檔會拖慢建置、推送和部署的速度。遵循以下做法來保持映像檔精簡:
- 盡可能使用官方的 slim 或 alpine 基礎映像檔。例如,
node:18-alpine比node:18小得多。 - 利用多階段建置(multi-stage builds) 將建置時期的相依性與執行時期分離,讓最終映像檔保持最小。
- 合併 RUN 指令 以減少層數,並在同一層中清理套件管理員的快取。
- 使用 .dockerignore 檔案 從建置上下文中排除不必要的檔案(例如 node_modules、.git)。
以下是一個 Go 應用程式的多階段 Dockerfile:
# Build stage
FROM golang:1.21-alpine AS builder
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /app/main .
# Final stage
FROM alpine:latest
COPY --from=builder /app/main /main
CMD ["/main"]
最終映像檔只包含編譯後的執行檔和 Alpine,不包含 Go 工具鏈。
使用磁碟區管理資料
容器是短暫的;當它們被移除時,資料也會遺失。磁碟區(Volumes) 能將資料保存在容器生命週期之外。可用於資料庫、上傳檔案或任何需要在重啟後存續的狀態。
docker run -v my-data:/var/lib/postgresql/data postgres
這會建立一個由 Docker 管理的具名磁碟區 my-data。在開發時,你也可以將原始碼綁定掛載(bind-mount)到容器中,以實現即時重新載入:
docker run -v $(pwd):/app -p 3000:3000 my-app
Docker Compose:編排多個容器
真實的應用程式通常需要多個服務:網頁伺服器、資料庫、快取。使用 docker run 逐一啟動既繁瑣又容易出錯。Docker Compose 讓你透過單一 YAML 檔案定義並執行多容器應用程式。
實用的 docker-compose.yml
以下是一個包含 PostgreSQL 和 Redis 的 Node.js 應用程式 Compose 檔案:
version: '3.8'
services:
web:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgres://user:pass@db:5432/mydb
- REDIS_URL=redis://cache:6379
depends_on:
- db
- cache
db:
image: postgres:15-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: mydb
volumes:
- postgres_data:/var/lib/postgresql/data
cache:
image: redis:7-alpine
volumes:
postgres_data:
執行 docker compose up 即可啟動所有服務。Compose 會建立一個預設網路,讓容器可以透過服務名稱(例如 db、cache)互相聯繫。
常用的 Compose 指令
docker compose up -d– 以分離模式(背景)啟動。docker compose logs -f web– 持續追蹤某個服務的日誌。docker compose exec web sh– 在執行中的容器內開啟 shell。docker compose down– 停止並移除容器、網路和磁碟區(除非磁碟區是外部的)。
何時使用 Docker Compose 與 Kubernetes
Docker Compose 非常適合本機開發、測試和小型部署。Kubernetes 則擅長在生產環境中大規模地跨叢集編排容器。對許多開發者而言,Compose 足以應付日常工作,當你需要自動擴展、自我修復和進階網路功能時,再進階到 Kubernetes 即可。
| 功能 | Docker Compose | Kubernetes |
|---|---|---|
| 使用情境 | 本機開發、小型部署 | 生產叢集 |
| 複雜度 | 低 | 高 |
| 擴展 | 手動 | 自動 |
| 學習曲線 | 平緩 | 陡峭 |
常見問題
映像檔和容器有什麼區別?
映像檔是包含應用程式和相依性的唯讀範本。容器是映像檔的執行實例。你可以從一個映像檔執行多個容器。
如何縮小 Docker 映像檔的大小?
使用較小的基礎映像檔(如 Alpine)、多階段建置、合併 RUN 指令,並使用 .dockerignore 檔案排除不必要的檔案。
我可以在生產環境中使用 Docker Compose 嗎?
可以,對於小規模部署而言。對於更大、動態的環境,Kubernetes 或 Docker Swarm 更為合適。
準備好最佳化你的 Docker 工作流程了嗎?試試我們的 Nginx Log Analyzer,用於除錯和監控你的容器化網頁伺服器。