
簡介
容器是雲端原生的基礎。微服務架構中的每個服務都被打包到容器映像中,以確保開發、登台和生產之間的一致性。本文深入探討容器、Docker 和基本的最佳實務。
1. 容器與虛擬機
1.1 虛擬機
┌──────────────────────────────────────┐
│ Host Hardware │
├──────────────────────────────────────┤
│ Host OS (Linux) │
├──────────────────────────────────────┤
│ Hypervisor (KVM/ESXi) │
├────────────┬────────────┬────────────┤
│ Guest OS │ Guest OS │ Guest OS │
│ (Ubuntu) │ (CentOS) │ (Debian) │
├────────────┼────────────┼────────────┤
│ Libs/Bins │ Libs/Bins │ Libs/Bins │
├────────────┼────────────┼────────────┤
│ App A │ App B │ App C │
└────────────┴────────────┴────────────┘
- 每個虛擬機器運行單獨的作業系統(單獨的核心)
- 資源消耗:500MB - 2GB RAM 僅用於作業系統
- 啟動:30 秒 - 幾分鐘
- 隔離:強(硬體等級)
1.2 容器
┌──────────────────────────────────────┐
│ Host Hardware │
├──────────────────────────────────────┤
│ Host OS (Linux Kernel) │
├──────────────────────────────────────┤
│ Container Runtime (containerd)│
├────────────┬────────────┬────────────┤
│ Libs/Bins │ Libs/Bins │ Libs/Bins │
├────────────┼────────────┼────────────┤
│ App A │ App B │ App C │
└────────────┴────────────┴────────────┘
- 所有容器共享主機作業系統的核心
- Light:容器鏡像 5MB - 200MB
- 啟動: < 1 秒
- Isolation: Process-level (namespaces + cgroups)
1.3 比較
| 標準 | 虛擬機器 | 貨櫃 |
|---|---|---|
| Startup time | 30s - 5min | < 1s |
| Image size | GB | MB |
| RAM overhead | 500MB+ per VM | ~0 overhead |
| Isolation | Strong (hypervisor) | Process-level (namespace) |
| Density | 10-20 VMs per host | 100-1000 containers per host |
| Portability | Moderate | Excellent |
2. Docker Architecture
2.1 Core Components
┌─────────────────────────────────────────────────┐
│ Docker Client (CLI) │
│ docker build, docker run, docker push │
└───────────────────────┬─────────────────────────┘
│ REST API
┌───────────────────────▼─────────────────────────┐
│ Docker Daemon (dockerd) │
│ │
│ ┌──────────┐ ┌──────────────┐ ┌────────────┐ │
│ │ Images │ │ Containers │ │ Volumes │ │
│ └──────────┘ └──────────────┘ └────────────┘ │
│ ┌──────────┐ ┌──────────────┐ │
│ │ Networks │ │ containerd │ │
│ └──────────┘ └──────┬───────┘ │
└──────────────────────┬──────────────────────────┘
│
┌──────────────────────▼──────────────────────────┐
│ Container Runtime (runc) │
│ Linux Kernel: namespaces + cgroups │
└─────────────────────────────────────────────────┘
2.2 Linux Kernel Features
容器基於 Linux 核心的 2 個核心功能建構:
命名空間 — 隔離:
pid— 進程隔離(容器只能看到自己的進程)net— 網路隔離(每個容器都有自己的網路堆疊)mnt— 掛載自己的檔案系統uts— 私有主機名ipc— 單獨的進程間通信user— 使用者/群組 ID 單獨映射
Cgroups — 資源限制:
- CPU (millicores)
- Memory (bytes)
- Disk I/O
- Network bandwidth
3. Dockerfile Best Practices
3.1 Multi-stage Build
多階段建置透過分離建置環境和運行時來幫助建立緊湊的映像:
# === Stage 1: Build ===
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
COPY . .
RUN npm run build
# === Stage 2: Runtime ===
FROM node:20-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
USER appuser
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
CMD ["node", "dist/main.js"]
結果:映像建置 ~800MB → 映像運行時 ~150MB
3.2 Layer Caching
Docker 快取每一層。安排Dockerfile來優化緩存:
# ✅ Tốt: Dependencies ít thay đổi → cache được layer này
COPY package*.json ./
RUN npm ci
# Source code thay đổi thường xuyên → chỉ invalidate từ đây
COPY . .
RUN npm run build
# ❌ Xấu: Mỗi lần thay đổi code → rebuild tất cả
COPY . .
RUN npm ci && npm run build
3.3 Security Best Practices
# 1. Dùng specific version, KHÔNG dùng :latest
FROM node:20.11-alpine3.19
# 2. Chạy với non-root user
RUN addgroup -S app && adduser -S app -G app
USER app
# 3. Không copy file nhạy cảm
# .dockerignore:
# .env
# .git
# node_modules
# *.secret
# 4. Scan image trước khi push
# trivy image myapp:1.0.0
3.4 Java / Go / Python Examples
Java (Spring Boot):
FROM eclipse-temurin:21-jdk-alpine AS build
WORKDIR /app
COPY gradle/ gradle/
COPY gradlew build.gradle.kts settings.gradle.kts ./
RUN ./gradlew dependencies --no-daemon
COPY src/ src/
RUN ./gradlew bootJar --no-daemon
FROM eclipse-temurin:21-jre-alpine
RUN addgroup -S app && adduser -S app -G app
COPY --from=build /app/build/libs/*.jar /app/app.jar
USER app
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
Go:
FROM golang:1.22-alpine AS build
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o /server ./cmd/server
FROM scratch
COPY --from=build /server /server
COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
EXPOSE 8080
ENTRYPOINT ["/server"]
一起去 scratch base image → image size ~10-15MB.
4. Container Networking
4.1 Docker Network Types
Bridge (default) Host None Overlay (Swarm/K8s)
┌────────────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────────┐
│ Container A │ │Container │ │Container │ │ Host 1 Host 2 │
│ 172.17.0.2 │ │shares │ │no network│ │ ┌─────┐ ┌─────┐│
│ Container B │ │host's │ │isolated │ │ │ C-A │ │ C-B ││
│ 172.17.0.3 │ │network │ │ │ │ └──┬──┘ └──┬──┘│
│ │ │ │stack │ │ │ │ └────┬────┘ │
│ docker0 bridge │ │ │ │ │ │ VXLAN overlay │
└────────────────┘ └──────────┘ └──────────┘ └──────────────────┘
4.2 Docker Compose Networking
services:
order-service:
build: ./order-service
ports:
- "8080:8080"
networks:
- backend
depends_on:
postgres:
condition: service_healthy
payment-service:
build: ./payment-service
ports:
- "8081:8080"
networks:
- backend
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: orders
POSTGRES_USER: app
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
volumes:
- pgdata:/var/lib/postgresql/data
networks:
- backend
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app"]
interval: 5s
timeout: 3s
retries: 5
networks:
backend:
driver: bridge
volumes:
pgdata:
secrets:
db_password:
file: ./secrets/db_password.txt
在同一網路中,服務透過服務名稱相互呼叫:
order-service → http://payment-service:8080/api/pay
5. Image Registry
5.1 帶有註冊表的 CI/CD 管道
Developer → Git Push → CI Pipeline:
1. docker build -t registry.example.com/order-service:v1.2.3
2. trivy image registry.example.com/order-service:v1.2.3
3. docker push registry.example.com/order-service:v1.2.3
4. Update K8s manifest → ArgoCD sync
Registry Options:
├── Docker Hub (public)
├── Harbor (self-hosted, recommended)
├── AWS ECR
├── Google Artifact Registry
└── GitHub Container Registry (ghcr.io)
5.2 Image Tagging Strategy
# ✅ Semantic versioning
registry.example.com/order-service:1.2.3
registry.example.com/order-service:1.2.3-alpine
# ✅ Git commit hash (immutable)
registry.example.com/order-service:abc123f
# ❌ KHÔNG dùng :latest trong production
registry.example.com/order-service:latest
6. 總結
| Concept | Key Point |
|---|---|
| 容器與虛擬機器 | 容器更輕、啟動更快、密度更高 |
| 多階段建置 | 分離建置與執行時間以減少映像大小 |
| 層緩存 | 整理Dockerfile優化緩存 |
| 非 root 使用者 | 始終使用非 root 使用者執行容器 |
| 影像掃描 | 推播前掃描,屏蔽危險圖片 |
| 網路 | 同一網路中的容器透過服務名稱互相呼叫 |
下一篇文章:Kubernetes 架構 — Kubernetes 如何編排數百個容器、自動擴展、自我修復和管理整個生命週期。