8微服务架构设计模式

查询微服务

CQRS 模式

CQRS命令查询物化视图

🎯 AI 时代的学习建议:不要只读理论。理解这一章的设计动机(为什么需要这个概念?)和边界条件(什么情况下会失效?)。当 AI 生成的代码涉及这些概念时,你能判断它是否用对了场景。AI 能帮你总结内容,但无法替代你亲手阅读、思考、建立直觉的过程。

第8章:微服务的部署(Deploying Microservices)

一、导读

1.1 本章学习目标

微服务的独立部署特性对部署基础设施提出了更高要求。第8章介绍了多种部署模式,重点讲解了基于 Kubernetes 的容器化部署和 CI/CD 流水线设计。

本章的核心学习目标包括:

  • 理解微服务的部署模式:多服务实例模式 vs 服务实例共享模式。
  • 掌握容器化部署:Docker + Kubernetes 的核心概念和配置。
  • 学会 Kubernetes 核心资源:Pod、Deployment、Service、Ingress 的配置。
  • 理解 CI/CD 流水线设计:构建、测试、部署的自动化。
  • 掌握部署策略:蓝绿部署、金丝雀发布、滚动更新。
  • 了解基础设施即代码:Terraform、Pulumi 的使用。

1.2 为什么本章如此重要

Richardson 指出:微服务的价值只有通过高效的部署才能实现。如果几十个微服务仍然使用手动部署,运维复杂度将远超单体架构。容器化(Docker)和容器编排(Kubernetes)是微服务部署的事实标准,它们提供了服务隔离、弹性伸缩、自动恢复、滚动更新等关键能力。

1.3 核心问题引导

微服务的部署模式有哪些?各自适用于什么场景?

Kubernetes 的 Pod、Deployment、Service 之间是什么关系?

如何设计一个完整的 CI/CD 流水线?

蓝绿部署和金丝雀发布有什么区别?如何选择?

健康检查和就绪检查的区别是什么?

如何实现微服务的自动伸缩?


二、核心概念详解

2.1 部署模式

2.1.1 多服务实例模式

每个服务有自己的独立实例(虚拟机或容器)。

// 模式1:每个服务一个虚拟机
// [VM1: order-service]  [VM2: payment-service]  [VM3: inventory-service]
// 优点:完全隔离
// 缺点:资源利用率低,管理成本高

// 模式2:每个服务一个容器(推荐)
// [Host1: Docker]
//   ├── order-service container (3 replicas)
//   ├── payment-service container (2 replicas)
//   └── inventory-service container (2 replicas)
// 优点:轻量级隔离,资源利用率高
// 缺点:需要容器编排工具

// 模式3:Serverless(函数计算)
// 每个服务部署为云函数(AWS Lambda、阿里云函数计算)
// 优点:零运维,按需付费,自动伸缩
// 缺点:冷启动延迟,执行时间限制

2.1.2 服务实例共享模式

多个服务共享同一组实例(类似 PaaS)。

// 模式:应用服务器集群
// [Application Server Cluster]
//   ├── order-service.war
//   ├── payment-service.war
//   └── inventory-service.war
// 优点:资源利用率高
// 缺点:隔离性差,资源争抢

2.2 容器化部署

2.2.1 Docker 基础

dockerfile
# 多阶段构建 Dockerfile
FROM eclipse-temurin:17-jdk-alpine AS builder
WORKDIR /app
COPY build.gradle settings.gradle ./
COPY src ./src
RUN ./gradlew bootJar --no-daemon

FROM eclipse-temurin:17-jre-alpine
WORKDIR /app
COPY --from=builder /app/build/libs/*.jar app.jar

RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser

EXPOSE 8080

HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
  CMD wget -qO- http://localhost:8080/actuator/health || exit 1

ENTRYPOINT ["java", "-jar", "app.jar"]
bash
# 构建和运行
docker build -t ftgo/order-service:1.0.0 .
docker run -d -p 8080:8080 \
  -e SPRING_PROFILES_ACTIVE=prod \
  -e EUREKA_CLIENT_SERVICE_URL_DEFAULTZONE=http://eureka:8761/eureka/ \
  --name order-service \
  ftgo/order-service:1.0.0

2.2.2 Kubernetes 核心概念

yaml
# Deployment:管理 Pod 副本
apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-service
  labels:
    app: order-service
spec:
  replicas: 3
  selector:
    matchLabels:
      app: order-service
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  template:
    metadata:
      labels:
        app: order-service
    spec:
      containers:
        - name: order-service
          image: ftgo/order-service:1.0.0
          ports:
            - containerPort: 8080
          resources:
            requests:
              memory: "256Mi"
              cpu: "250m"
            limits:
              memory: "512Mi"
              cpu: "500m"
          env:
            - name: SPRING_PROFILES_ACTIVE
              value: "prod"
            - name: EUREKA_CLIENT_SERVICE_URL_DEFAULTZONE
              valueFrom:
                configMapKeyRef:
                  name: app-config
                  key: eureka-url
          livenessProbe:
            httpGet:
              path: /actuator/health/liveness
              port: 8080
            initialDelaySeconds: 60
            periodSeconds: 10
          readinessProbe:
            httpGet:
              path: /actuator/health/readiness
              port: 8080
            initialDelaySeconds: 30
            periodSeconds: 5
yaml
# Service:暴露网络访问
apiVersion: v1
kind: Service
metadata:
  name: order-service
spec:
  selector:
    app: order-service
  ports:
    - port: 80
      targetPort: 8080
  type: ClusterIP

# Ingress:外部访问入口
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ftgo-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
    - host: api.ftgo.com
      http:
        paths:
          - path: /api/orders
            pathType: Prefix
            backend:
              service:
                name: order-service
                port:
                  number: 80
          - path: /api/payments
            pathType: Prefix
            backend:
              service:
                name: payment-service
                port:
                  number: 80
yaml
# HPA:自动伸缩
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: order-service-hpa
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

2.3 CI/CD 流水线

2.3.1 GitHub Actions

yaml
# .github/workflows/deploy-order-service.yml
name: Deploy Order Service

on:
  push:
    branches: [main]
    paths:
      - 'order-service/**'
  pull_request:
    branches: [main]
    paths:
      - 'order-service/**'

env:
  SERVICE_NAME: order-service
  REGISTRY: registry.example.com

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'temurin'
      - name: Run Tests
        working-directory: ./order-service
        run: ./gradlew test

  build:
    needs: test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build Docker Image
        working-directory: ./order-service
        run: |
          docker build -t ${{ env.REGISTRY }}/${{ env.SERVICE_NAME }}:${{ github.sha }} .
      - name: Push to Registry
        run: |
          echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login ${{ env.REGISTRY }} -u "${{ secrets.REGISTRY_USERNAME }}" --password-stdin
          docker push ${{ env.REGISTRY }}/${{ env.SERVICE_NAME }}:${{ github.sha }}

  deploy-staging:
    needs: build
    runs-on: ubuntu-latest
    environment: staging
    steps:
      - name: Deploy to Staging
        run: |
          kubectl set image deployment/$SERVICE_NAME \
            $SERVICE_NAME=${{ env.REGISTRY }}/${{ env.SERVICE_NAME }}:${{ github.sha }} \
            -n staging
      - name: Smoke Test
        run: |
          sleep 30
          curl -f https://staging-api.ftgo.com/api/orders/health || exit 1

  deploy-production:
    needs: deploy-staging
    runs-on: ubuntu-latest
    environment: production
    steps:
      - name: Canary Deploy (10%)
        run: |
          kubectl set image deployment/$SERVICE_NAME \
            $SERVICE_NAME=${{ env.REGISTRY }}/${{ env.SERVICE_NAME }}:${{ github.sha }} \
            -n production
          kubectl scale deployment/$SERVICE_NAME --replicas=1 -n production
      - name: Verify Canary
        run: |
          sleep 60
          curl -f https://api.ftgo.com/api/orders/health || exit 1
      - name: Full Deploy
        run: |
          kubectl scale deployment/$SERVICE_NAME --replicas=3 -n production

2.4 部署策略

2.4.1 蓝绿部署

// 蓝绿部署:
// [Blue: v1.0]  ← 当前生产流量
// [Green: v2.0] ← 新版本,无流量
//
// 切换:将负载均衡器指向 Green
// [Blue: v1.0]  ← 保留,用于回滚
// [Green: v2.0] ← 接收全部流量
//
// 回滚:将负载均衡器指回 Blue
// 优点:零停机,快速回滚
// 缺点:需要双倍资源

2.4.2 金丝雀发布

// 金丝雀发布:
// 阶段1:90% → v1.0, 10% → v2.0
// 阶段2:观察 10 分钟,检查错误率和延迟
// 阶段3:70% → v1.0, 30% → v2.0
// 阶段4:继续观察
// 阶段5:0% → v1.0, 100% → v2.0
//
// 优点:渐进式发布,风险可控
// 缺点:需要流量分割能力

2.4.3 滚动更新

yaml
# Kubernetes 滚动更新配置
spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1          # 最多多出1个Pod
      maxUnavailable: 0    # 不允许有Pod不可用
  replicas: 3

# 更新过程:
# 1. 创建1个新Pod(v2.0)→ 共4个Pod(3旧+1新)
# 2. 新Pod就绪后,删除1个旧Pod → 共3个Pod(2旧+1新)
# 3. 创建1个新Pod → 共4个Pod(2旧+2新)
# 4. 重复直到全部更新完成

三、实战案例

3.1 案例一:完整的 Kubernetes 部署

yaml
# ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  eureka-url: "http://eureka-server:8761/eureka/"
  kafka-brokers: "kafka-0:9092,kafka-1:9092,kafka-2:9092"

# Secret
apiVersion: v1
kind: Secret
metadata:
  name: db-credentials
type: Opaque
data:
  username: ZnRnb191c2Vy        # base64 encoded
  password: c2VjdXJlX3Bhc3M=

# 完整 Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: order-service
spec:
  replicas: 3
  selector:
    matchLabels:
      app: order-service
  template:
    spec:
      containers:
        - name: order-service
          image: ftgo/order-service:1.0.0
          env:
            - name: SPRING_DATASOURCE_USERNAME
              valueFrom:
                secretKeyRef:
                  name: db-credentials
                  key: username
            - name: SPRING_DATASOURCE_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: db-credentials
                  key: password
            - name: KAFKA_BOOTSTRAP_SERVERS
              valueFrom:
                configMapKeyRef:
                  name: app-config
                  key: kafka-brokers
          resources:
            requests:
              memory: "256Mi"
              cpu: "250m"
            limits:
              memory: "512Mi"
              cpu: "500m"

3.2 案例二:使用 Helm 管理部署

yaml
# Chart.yaml
apiVersion: v2
name: order-service
version: 1.0.0

# values.yaml
replicaCount: 3
image:
  repository: ftgo/order-service
  tag: "1.0.0"
resources:
  requests:
    memory: "256Mi"
    cpu: "250m"
  limits:
    memory: "512Mi"
    cpu: "500m"
service:
  port: 80
  targetPort: 8080
ingress:
  enabled: true
  hosts:
    - host: api.ftgo.com
      paths:
        - /api/orders
autoscaling:
  enabled: true
  minReplicas: 3
  maxReplicas: 20
  targetCPUUtilization: 70
bash
# 部署
helm install order-service ./charts/order-service -n production

# 升级
helm upgrade order-service ./charts/order-service -n production --set image.tag=1.1.0

# 回滚
helm rollback order-service 1 -n production

四、本章小结

本章讲解了微服务的部署策略和工具:

核心知识点:

  • 容器化(Docker + Kubernetes)是微服务部署的事实标准。
  • Kubernetes 的 Pod、Deployment、Service、Ingress 各有分工。
  • CI/CD 流水线应包含构建、测试、部署的完整自动化。
  • 蓝绿部署实现零停机切换,金丝雀发布实现渐进式上线。
  • HPA 实现基于 CPU/内存的自动伸缩。
  • Helm 简化 Kubernetes 应用的管理和部署。

五、思考与练习

思考题

你的项目适合使用蓝绿部署还是金丝雀发布?

Kubernetes 的 liveness 和 readiness 探针应该如何设计?

如何实现微服务的零停机部署?

练习题

编写一个多阶段 Dockerfile,构建一个 Spring Boot 微服务。

编写 Kubernetes Deployment、Service、Ingress 配置。

设计一个 GitHub Actions CI/CD 流水线,包含测试、构建、部署步骤。

8/12查询微服
0%