Docker 容器化

是什麼?

Docker 是一個容器化平台,把應用程式和所有依賴打包成標準化的 Container。Container 比虛擬機更輕量(共享 OS Kernel),啟動速度以秒計,是現代 CI/CD 和雲端部署的基礎設施。

ℹ️Container vs VM

VM:包含完整 OS,啟動需要分鐘,佔用 GB 級記憶體。Container:共享 Host OS Kernel,啟動只需秒,佔用 MB 級記憶體。Container 不是輕量級 VM,而是一種程序隔離技術。

核心觀念

常見誤區

⚠️常見誤區

  • Image 太大:用 node:20 作為 base(1GB+),應該用 node:20-alpine(~130MB)。最終 Image 不需要包含編譯工具
  • 不用 Multi-stage Build:把 build 工具和 source code 留在最終 Image 中,不但肥大還有安全風險
  • 用 root 跑容器:Container 內預設用 root 執行,一旦被攻破等於拿到 root 權限。必須建立非 root 用戶

流程/步驟

1

撰寫 Dockerfile

定義 base image、安裝依賴、複製程式碼、設定啟動命令

2

Build Image

docker build -t myapp:v1 . 建置映像檔

3

測試 Container

docker run -p 8080:80 myapp:v1 在本機測試

4

推送 Registry

docker push 到 Docker Hub 或私有 Registry

5

Compose 編排

用 docker-compose.yml 定義多容器開發環境

6

CI/CD 整合

在 Pipeline 中 build、push、deploy Image

流程解讀:Dockerfile 定義 Image 的建置步驟。Build 後在本機測試,確認正常後推送到 Registry。開發環境用 Docker Compose 一鍵啟動多個服務。CI/CD Pipeline 中自動 build 和 push Image。

程式碼範例

C# 版本

dockerfile
# .NET Multi-stage Dockerfile
# Stage 1: Build
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY *.csproj .
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app/publish
 
# Stage 2: Runtime(最終 Image 只有 runtime,不含 SDK)
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
WORKDIR /app
 
# 建立非 root 用戶
RUN adduser --disabled-password --gecos "" appuser
USER appuser
 
COPY --from=build /app/publish .
EXPOSE 8080
ENTRYPOINT ["dotnet", "MyApp.dll"]

TypeScript 版本

dockerfile
# Node.js Multi-stage Dockerfile
# Stage 1: Build
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json .
RUN npm ci
COPY . .
RUN npm run build
 
# Stage 2: Runtime
FROM node:20-alpine AS runtime
WORKDIR /app
 
# 非 root 用戶
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
 
COPY --from=build /app/dist ./dist
COPY --from=build /app/node_modules ./node_modules
COPY package*.json .
 
EXPOSE 3000
CMD ["node", "dist/index.js"]

Python 版本

dockerfile
# Python Multi-stage Dockerfile
FROM python:3.12-slim AS build
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir --target=/deps -r requirements.txt
 
FROM python:3.12-slim AS runtime
WORKDIR /app
 
RUN useradd --create-home appuser
USER appuser
 
COPY --from=build /deps /home/appuser/.local/lib/python3.12/site-packages
COPY . .
 
EXPOSE 8000
CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
yaml
# docker-compose.yml — 開發環境
services:
  app:
    build: .
    ports:
      - "8080:8080"
    environment:
      - DATABASE_URL=postgresql://postgres:secret@db:5432/myapp
    depends_on:
      - db
      - redis
 
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: myapp
    volumes:
      - pgdata:/var/lib/postgresql/data
 
  redis:
    image: redis:7-alpine
 
volumes:
  pgdata:

架構圖/概念圖

Dockerfile
docker build→
Docker Image (Layers)
docker push→
Container Registry
docker run→
Container (Dev)
→
Container (Staging)
→
Container (Prod)

Dockerfile 建置出 Image,推送到 Registry 後,任何環境都能從 Registry 拉取同一個 Image 建立 Container。Dev、Staging、Prod 跑的是同一個 Image,確保環境一致性。

實戰補充

Q: Image 太大怎麼瘦身?

A: (1) 用 Alpine 基底(node:20-alpine)。(2) 用 Multi-stage Build,最終 Image 不含 SDK 和 Build 工具。(3) .dockerignore 排除不需要的檔案。(4) 合併 RUN 指令減少 Layer 數量。

Q: Docker Compose 和 Kubernetes 的關係?

A: Docker Compose 適合本機開發和簡單部署(單機多容器)。Kubernetes 適合生產環境的大規模容器編排(多機、自動擴縮、滾動更新)。開發時用 Compose,上線用 K8s。

Q: Volume 和 Bind Mount 有什麼區別?

A: Volume(-v mydata:/data):Docker 管理的持久化儲存,適合資料庫等需要持久化的場景。Bind Mount(-v ./src:/app/src):直接掛載 Host 目錄,適合開發時即時同步程式碼。

理解測驗

🤔 Container 和 VM 的核心差異是什麼?

🤔 Multi-stage Build 的主要好處是什麼?

🤔 為什麼 Container 內不應該用 root 執行?

重點整理

💡一句話記住

Docker = 把應用和環境打包成標準貨櫃,走到哪都能跑。 口訣:「Dockerfile 定義、Image 打包、Container 執行」

概念說明
Image唯讀藍圖,由 Dockerfile 建置
ContainerImage 的執行實例
Multi-stage分離 Build 和 Runtime,縮小 Image
ComposeYAML 定義多容器開發環境
Registry存放和分發 Image 的倉庫

你可能也想看

← Pipeline 中的測試策略部署策略 →

按 ← → 鍵切換課程