第二十章:Docker 容器化與部署 (Containerization & Deployment)
20.1 引言:為什麼需要容器化?
容器化解決了 "在我的機器上可以跑" 的經典問題。
- 一致性:開發、測試、生產環境完全一致。
- 隔離性:每個應用程式有自己的依賴,互不干擾。
- 可移植性:可以在任何支援 Docker 的平台上執行。
- 擴展性:輕鬆水平擴展 (Scale Out)。
20.2 Dockerfile 最佳實踐
1. 多階段建置 (Multi-Stage Build)
減少最終映像大小,提升安全性。
dockerfile
# Stage 1: Build
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
# 複製專案檔案並還原 (利用 Docker 快取層)
COPY ["src/BookStore.Web/BookStore.Web.csproj", "src/BookStore.Web/"]
COPY ["src/BookStore.Application/BookStore.Application.csproj", "src/BookStore.Application/"]
COPY ["src/BookStore.Domain/BookStore.Domain.csproj", "src/BookStore.Domain/"]
COPY ["src/BookStore.EntityFrameworkCore/BookStore.EntityFrameworkCore.csproj", "src/BookStore.EntityFrameworkCore/"]
RUN dotnet restore "src/BookStore.Web/BookStore.Web.csproj"
# 複製所有原始碼並建置
COPY . .
WORKDIR "/src/src/BookStore.Web"
RUN dotnet build "BookStore.Web.csproj" -c Release -o /app/build
# Stage 2: Publish
FROM build AS publish
RUN dotnet publish "BookStore.Web.csproj" -c Release -o /app/publish /p:UseAppHost=false
# Stage 3: Runtime
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS final
WORKDIR /app
# 建立非 root 使用者 (安全性最佳實踐)
RUN adduser --disabled-password --gecos '' appuser && chown -R appuser /app
USER appuser
EXPOSE 8080
COPY --from=publish /app/publish .
# 健康檢查
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \
CMD curl -f http://localhost:8080/health || exit 1
ENTRYPOINT ["dotnet", "BookStore.Web.dll"]2. .dockerignore
避免將不必要的檔案複製到映像中。
**/bin/
**/obj/
**/out/
**/.vs/
**/.vscode/
**/*.user
**/.git/
**/node_modules/20.3 Docker Compose (本地開發)
使用 Docker Compose 編排多個容器 (應用程式 + 資料庫 + Redis)。
yaml
version: "3.8"
services:
web:
build:
context: .
dockerfile: Dockerfile
ports:
- "8080:8080"
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ConnectionStrings__Default=Server=db;Database=BookStore;User Id=sa;Password=YourStrong@Passw0rd;TrustServerCertificate=True
- Redis__Configuration=redis:6379
depends_on:
- db
- redis
networks:
- bookstore-network
db:
image: mcr.microsoft.com/mssql/server:2022-latest
environment:
- ACCEPT_EULA=Y
- SA_PASSWORD=YourStrong@Passw0rd
ports:
- "1433:1433"
volumes:
- sqldata:/var/opt/mssql
networks:
- bookstore-network
redis:
image: redis:7-alpine
ports:
- "6379:6379"
networks:
- bookstore-network
volumes:
sqldata:
networks:
bookstore-network:
driver: bridge執行:
bash
docker-compose up -d
docker-compose logs -f web20.4 Kubernetes 部署
1. Deployment
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: bookstore-web
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: bookstore
tier: web
template:
metadata:
labels:
app: bookstore
tier: web
spec:
containers:
- name: web
image: myregistry.azurecr.io/bookstore:1.0.0
ports:
- containerPort: 8080
env:
- name: ASPNETCORE_ENVIRONMENT
value: "Production"
- name: ConnectionStrings__Default
valueFrom:
secretKeyRef:
name: db-secret
key: connection-string
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 52. Service
yaml
apiVersion: v1
kind: Service
metadata:
name: bookstore-web-svc
spec:
type: LoadBalancer
selector:
app: bookstore
tier: web
ports:
- protocol: TCP
port: 80
targetPort: 80803. ConfigMap & Secret
yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
ASPNETCORE_ENVIRONMENT: "Production"
---
apiVersion: v1
kind: Secret
metadata:
name: db-secret
type: Opaque
stringData:
connection-string: "Server=sql-server;Database=BookStore;User Id=sa;Password=YourSecurePassword"部署:
bash
kubectl apply -f k8s/
kubectl get pods -n production
kubectl logs -f deployment/bookstore-web -n production20.5 Helm Charts
Helm 是 Kubernetes 的套件管理器,讓部署更加靈活。
1. 建立 Chart
bash
helm create bookstore2. values.yaml
yaml
replicaCount: 3
image:
repository: myregistry.azurecr.io/bookstore
tag: "1.0.0"
pullPolicy: IfNotPresent
service:
type: LoadBalancer
port: 80
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
memory: 256Mi
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 80
database:
host: "sql-server.database.svc.cluster.local"
name: "BookStore"3. 部署
bash
# 安裝
helm install bookstore ./bookstore -f values-production.yaml
# 升級
helm upgrade bookstore ./bookstore --set image.tag=1.1.0
# 回滾
helm rollback bookstore 120.6 CI/CD 整合
1. GitHub Actions 範例
yaml
name: Build and Deploy
on:
push:
branches: [main]
tags: ["v*"]
env:
REGISTRY: myregistry.azurecr.io
IMAGE_NAME: bookstore
jobs:
build-and-push:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Log in to Azure Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.ACR_USERNAME }}
password: ${{ secrets.ACR_PASSWORD }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=sha
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
deploy:
needs: build-and-push
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
steps:
- uses: azure/k8s-set-context@v3
with:
method: kubeconfig
kubeconfig: ${{ secrets.KUBE_CONFIG }}
- name: Deploy to Kubernetes
run: |
helm upgrade --install bookstore ./helm/bookstore \
--set image.tag=${{ github.ref_name }} \
--namespace production20.7 實戰練習
練習 1:容器化應用
- 為您的 ABP 應用程式撰寫 Dockerfile。
- 使用 Docker Compose 在本地啟動完整環境 (App + DB + Redis)。
- 驗證應用程式正常運作。
練習 2:Kubernetes 部署
- 建立 Deployment, Service, ConfigMap, Secret。
- 部署到本地 Kubernetes (如 Docker Desktop 或 Minikube)。
- 測試 Pod 的自動重啟與負載均衡。
練習 3:CI/CD
- 設定 GitHub Actions 自動建置並推送映像。
- 實作自動部署到 Kubernetes。
20.8 總結
容器化與 Kubernetes 是現代應用程式部署的標準。
- Docker 提供了一致的執行環境。
- Kubernetes 提供了強大的編排能力。
- Helm 簡化了複雜的部署配置。
- CI/CD 自動化了整個流程。
掌握這些技術,您就能構建出可靠、可擴展的生產級系統。
參考資源: