微服务拆分精讲 / 第 15 章:容器化与编排
第 15 章:容器化与编排
容器化是微服务的交付标准,Kubernetes 是微服务的运行平台。不懂容器化,就无法真正实践微服务。
15.1 为什么需要容器化
15.1.1 “在我机器上能跑"问题
传统部署:
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Dev 环境 │ │ Staging │ │ Prod │
│ JDK 17 │ │ JDK 11 │ │ JDK 17 │
│ MySQL 8 │ │ MySQL 5.7│ │ MySQL 8 │
│ Ubuntu │ │ CentOS │ │ RHEL │
└──────────┘ └──────────┘ └──────────┘
(环境不一致导致 "在我机器上能跑")
容器化部署:
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Dev 环境 │ │ Staging │ │ Prod │
│ │ │ │ │ │
│ ┌──────┐ │ │ ┌──────┐ │ │ ┌──────┐ │
│ │Container│ │ │Container│ │ │Container│ │
│ │JDK 17│ │ │ │JDK 17│ │ │ │JDK 17│ │
│ │MySQL 8│ │ │ │MySQL 8│ │ │ │MySQL 8│ │
│ │App │ │ │ │App │ │ │ │App │ │
│ └──────┘ │ │ └──────┘ │ │ └──────┘ │
└──────────┘ └──────────┘ └──────────┘
(环境完全一致)
15.1.2 容器化的核心价值
| 价值 | 说明 |
|---|
| 环境一致性 | 开发/测试/生产使用相同的镜像 |
| 快速部署 | 秒级启动(vs 虚拟机分钟级) |
| 资源高效 | 共享内核,资源开销小 |
| 版本管理 | 镜像版本 = 应用版本 |
| 不可变基础设施 | 镜像一旦构建不可修改 |
| DevOps 基石 | CI/CD 的标准交付物 |
15.2 Docker 最佳实践
15.2.1 Dockerfile 优化
# ❌ 不好的 Dockerfile
FROM ubuntu:22.04
RUN apt-get update
RUN apt-get install -y openjdk-17-jdk maven git
COPY . /app
WORKDIR /app
RUN mvn clean package
CMD ["java", "-jar", "target/order-service.jar"]
# 问题:镜像大、包含构建工具、不安全
# ✅ 好的 Dockerfile(多阶段构建)
# 构建阶段
FROM eclipse-temurin:21-jdk-alpine AS builder
WORKDIR /app
COPY pom.xml .
COPY src ./src
RUN --mount=type=cache,target=/root/.m2 \
mvn clean package -DskipTests
# 运行阶段
FROM eclipse-temurin:21-jre-alpine
RUN addgroup -S app && adduser -S app -G app
WORKDIR /app
COPY --from=builder /app/target/order-service.jar app.jar
USER app
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=3s \
CMD wget -qO- http://localhost:8080/actuator/health || exit 1
ENTRYPOINT ["java", "-XX:+UseContainerSupport", "-jar", "app.jar"]
15.2.2 Dockerfile 最佳实践
| 实践 | 说明 |
|---|
| 多阶段构建 | 构建镜像和运行镜像分离 |
| 最小基础镜像 | 使用 Alpine 或 distroless |
| 非 root 用户 | 安全最佳实践 |
| 健康检查 | HEALTHCHECK 指令 |
| .dockerignore | 排除不需要的文件 |
| 层缓存优化 | 不常变的层放前面 |
| 固定版本号 | FROM image:tag 使用具体版本 |
15.2.3 镜像大小对比
基础镜像选择:
┌─────────────────────┬───────────┐
│ 镜像 │ 大小 │
├─────────────────────┼───────────┤
│ ubuntu:22.04 │ ~77 MB │
│ eclipse-temurin:21 │ ~460 MB │
│ eclipse-temurin:21-alpine │ ~180 MB │
│ eclipse-temurin:21-jre-alpine │ ~120 MB │
│ gcr.io/distroless/java21 │ ~130 MB │
└─────────────────────┴───────────┘
推荐:JRE Alpine 或 distroless
15.3 Kubernetes 核心概念
15.3.1 K8s 架构
┌──────────────────────────────────────────────────────────────────┐
│ Kubernetes 架构 │
├──────────────────────────────────────────────────────────────────┤
│ │
│ Control Plane (控制平面) │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ API │ │ Scheduler│ │Controller│ │ etcd │ │ │
│ │ │ Server │ │ │ │ Manager │ │ (KV存储) │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │ │
│ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┼ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ │
│ ▼ │
│ Worker Nodes (工作节点) │
│ ┌─────────────────────────┐ ┌─────────────────────────┐ │
│ │ Node 1 │ │ Node 2 │ │
│ │ ┌───────────────────┐ │ │ ┌───────────────────┐ │ │
│ │ │ kubelet │ │ │ │ kubelet │ │ │
│ │ │ kube-proxy │ │ │ │ kube-proxy │ │ │
│ │ │ Container Runtime│ │ │ │ Container Runtime│ │ │
│ │ │ (containerd) │ │ │ │ (containerd) │ │ │
│ │ └───────────────────┘ │ │ └───────────────────┘ │ │
│ │ ┌─────┐ ┌─────┐ │ │ ┌─────┐ ┌─────┐ │ │
│ │ │Pod A│ │Pod B│ │ │ │Pod C│ │Pod D│ │ │
│ │ └─────┘ └─────┘ │ │ └─────┘ └─────┘ │ │
│ └─────────────────────────┘ └─────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
15.3.2 核心资源对象
| 资源 | 说明 | 用途 |
|---|
| Pod | 最小调度单元 | 运行一个或多个容器 |
| Deployment | 声明式部署管理 | 管理 ReplicaSet,滚动更新 |
| Service | 服务发现和负载均衡 | 稳定的网络访问入口 |
| Ingress | HTTP(S) 入口 | 域名路由、SSL 终止 |
| ConfigMap | 配置管理 | 非敏感配置 |
| Secret | 敏感信息管理 | 密码、Token |
| StatefulSet | 有状态应用 | 数据库、MQ |
| DaemonSet | 每节点一个 Pod | 日志收集、监控 Agent |
| HPA | 水平自动扩容 | 按 CPU/内存/自定义指标扩容 |
15.4 微服务 K8s 部署配置
15.4.1 Deployment 配置
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
namespace: production
labels:
app: order-service
version: v2.1.0
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: order-service
template:
metadata:
labels:
app: order-service
version: v2.1.0
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
prometheus.io/path: "/actuator/prometheus"
spec:
serviceAccountName: order-service
securityContext:
runAsNonRoot: true
runAsUser: 1000
containers:
- name: order-service
image: registry.example.com/order-service:v2.1.0
ports:
- containerPort: 8080
name: http
env:
- name: SPRING_PROFILES_ACTIVE
value: "production"
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: order-db-credentials
key: password
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1000m"
memory: "1Gi"
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 15
periodSeconds: 5
startupProbe:
httpGet:
path: /actuator/health
port: 8080
failureThreshold: 30
periodSeconds: 2
15.4.2 Service 配置
apiVersion: v1
kind: Service
metadata:
name: order-service
namespace: production
spec:
selector:
app: order-service
ports:
- name: http
port: 80
targetPort: 8080
type: ClusterIP
15.4.3 HPA 自动扩容
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: order-service-hpa
namespace: production
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: order-service
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: "1000"
behavior:
scaleUp:
stabilizationWindowSeconds: 60
policies:
- type: Pods
value: 4
periodSeconds: 60
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Pods
value: 1
periodSeconds: 60
15.5 Helm Chart 管理
15.5.1 Helm Chart 结构
order-service-chart/
├── Chart.yaml # Chart 元数据
├── values.yaml # 默认配置值
├── templates/
│ ├── deployment.yaml # Deployment 模板
│ ├── service.yaml # Service 模板
│ ├── ingress.yaml # Ingress 模板
│ ├── hpa.yaml # HPA 模板
│ └── _helpers.tpl # 模板助手函数
└── charts/ # 依赖的子 Chart
15.5.2 Helm 常用命令
# 安装 Chart
helm install order-service ./order-service-chart \
-n production \
--set image.tag=v2.1.0 \
--set replicaCount=3
# 升级
helm upgrade order-service ./order-service-chart \
-n production \
--set image.tag=v2.2.0
# 回滚
helm rollback order-service 1 -n production
# 查看历史
helm history order-service -n production
15.6 有状态服务编排
15.6.1 数据库部署
# MySQL StatefulSet
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: mysql
replicas: 3
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: root-password
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql
volumeClaimTemplates:
- metadata:
name: mysql-data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: "fast-ssd"
resources:
requests:
storage: 100Gi
15.7 Kustomize vs Helm
| 维度 | Kustomize | Helm |
|---|
| 模板方式 | Overlay (覆盖) | Template (模板) |
| 学习曲线 | 低 | 中 |
| K8s 原生 | ✅ kubectl apply -k | 需要安装 |
| 复杂逻辑 | 不支持 | 支持 (Go Template) |
| 多环境管理 | 优秀 (Base + Overlay) | 良好 (values-xxx.yaml) |
| 社区生态 | 增长中 | 极丰富 |
15.8 业务场景:电商 K8s 部署全景
┌──────────────────────────────────────────────────────────────┐
│ 电商 K8s 部署架构 │
├──────────────────────────────────────────────────────────────┤
│ │
│ Ingress Layer │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ NGINX Ingress Controller / Istio Gateway │ │
│ │ *.pkold.com → 各服务路由 │ │
│ └──────────────────────────┬───────────────────────────┘ │
│ │ │
│ Service Layer ▼ │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │ User │ │Order │ │Product│ │Payment│ │Notif │ │
│ │ SVC │ │ SVC │ │ SVC │ │ SVC │ │ SVC │ │
│ └──┬───┘ └──┬───┘ └──┬───┘ └──┬───┘ └──┬───┘ │
│ │ │ │ │ │ │
│ Pod Layer ▼ ▼ ▼ ▼ │
│ ┌────┐┌────┐┌────┐┌────┐┌────┐┌────┐┌────┐┌────┐ │
│ │U-1 ││U-2 ││O-1 ││O-2 ││P-1 ││P-2 ││Py-1││N-1 │ │
│ └────┘└────┘└────┘└────┘└────┘└────┘└────┘└────┘ │
│ (HPA: 2-10) (HPA: 3-20) (HPA: 2-10) │
│ │
│ Data Layer │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │MySQL │ │Redis │ │Kafka │ │ ES │ │
│ │(StatefulSet)│ │ │ │ │ │ │ │
│ └──────┘ └──────┘ └──────┘ └──────┘ │
│ │
│ Platform Layer │
│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │Prom │ │Grafana│ │Jaeger│ │Loki │ │Vault │ │
│ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘ │
└──────────────────────────────────────────────────────────────┘
⚠️ 注意事项
- Pod 不是虚拟机——不要在一个 Pod 中放太多容器
- 资源请求和限制——必须设置,避免资源争抢
- 健康检查——liveness + readiness + startup probe 三件套
- 优雅关闭——处理 SIGTERM,完成正在进行的请求
- 日志输出到 stdout——不要写日志文件,让 K8s 收集
- 配置外部化——使用 ConfigMap/Secret,不硬编码在镜像中
📖 扩展阅读
- Kubernetes Documentation (kubernetes.io) — K8s 官方文档
- Docker Best Practices (docs.docker.com) — Dockerfile 最佳实践
- Helm Documentation (helm.sh) — Helm 包管理器
- Kubernetes Patterns — Bilgin Ibryam, Roland Huß — K8s 设计模式
- Production Kubernetes — O’Reilly — 生产级 K8s 实践
本章小结
| 要点 | 说明 |
|---|
| Docker 最佳实践 | 多阶段构建、最小镜像、非 root |
| K8s 核心资源 | Deployment, Service, HPA, Ingress |
| Helm Chart | 微服务 K8s 部署的标准化方案 |
| 自动扩容 | HPA 基于 CPU/Memory/自定义指标 |
| 有状态服务 | StatefulSet + PVC |
📌 下一章:第 16 章:单体拆分实践 — 绞杀者模式、防腐层、渐进迁移实战。