Spring Boot: 综合实战:OrderFlow 项目部署

最后更新:2026-08-26

部署是最后一公里——CI/CD 自动化、K8s 编排、监控告警,让应用从开发到生产一路畅通。

1. 你将学到


2. 一个 DevOps 工程师的真实故事

(1) 痛点:手动部署像踩雷

Bob 手动部署 OrderFlow 到生产:本地 mvn packagedocker build → 推镜像 → kubectl apply → 检查健康状态。整个流程 30 分钟,而且经常出错:忘了改配置、推错镜像版本、滚动更新时旧 Pod 没有优雅关闭导致 502 错误。

(2) CI/CD 的解法

自动化流水线一条龙:

100%
graph LR
    A["Git Push"] --> B["GitHub Actions<br/>Build + Test"]
    B --> C["Docker Build<br/>+ Push to Registry"]
    C --> D["K8s Rolling<br/>Deploy"]
    D --> E["Health Check<br/>+ Smoke Test"]
    E --> F["Monitor<br/>Grafana"]

(3) 收益

Bob 建立 CI/CD 后,代码推送触发自动部署,5 分钟完成从代码到生产。HPA 自动伸缩,Prometheus 自动告警,Bob 从"救火队长"变成了"监控观察员"。


3. CI/CD 流水线

▶ 示例: GitHub Actions Workflow

YAML
# .github/workflows/deploy.yml
name: OrderFlow CI/CD

on:
  push:
    branches: [main]
    tags: ['v*']

env:
  REGISTRY: registry.example.com
  IMAGE_NAME: orderflow-service

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4

    - name: Set up JDK 17
      uses: actions/setup-java@v4
      with:
        java-version: '17'
        distribution: 'temurin'

    - name: Run tests
      run: mvn verify -B

    - name: Build Docker image
      run: docker build -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} .

    - name: Login to Registry
      run: echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login ${{ env.REGISTRY }} -u ${{ secrets.REGISTRY_USERNAME }} --password-stdin

    - name: Push image
      run: docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}

  deploy:
    needs: build
    runs-on: ubuntu-latest
    if: startsWith(github.ref, 'refs/tags/v')
    steps:
    - uses: actions/checkout@v4

    - name: Deploy to Kubernetes
      run: |
        kubectl set image deployment/orderflow \
          orderflow=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} \
          -n orderflow
        kubectl rollout status deployment/orderflow -n orderflow --timeout=300s

    - name: Smoke test
      run: |
        sleep 10
        curl -sf https://api.orderflow.example.com/actuator/health | grep '"status":"UP"'

输出:

TEXT 📖 仅展示
CONTAINER ID   IMAGE          STATUS         PORTS
abc123         nginx:latest   Up 2 hours     0.0.0.0:80->80/tcp
流水线阶段 操作 失败处理
Build + Test mvn verify 阻断部署
Docker Build 多阶段构建镜像 阻断部署
Push Registry 推送到镜像仓库 重试 3 次
K8s Deploy kubectl set image + rollout 自动回滚
Smoke Test 健康检查验证 回滚 + 通知

4. K8s 生产部署

▶ 示例: 生产级 Deployment + HPA

YAML
apiVersion: apps/v1
kind: Deployment
metadata:
  name: orderflow
  namespace: orderflow
spec:
  replicas: 3
  selector:
    matchLabels: { app: orderflow }
  strategy:
    rollingUpdate: { maxUnavailable: 0, maxSurge: 1 }
  template:
    metadata:
      labels: { app: orderflow }
    spec:
      terminationGracePeriodSeconds: 60
      containers:
      - name: orderflow
        image: registry.example.com/orderflow-service:latest
        ports:
        - { containerPort: 8080 }
        - { containerPort: 8081 }
        envFrom:
        - configMapRef: { name: orderflow-config }
        - secretRef: { name: orderflow-secrets }
        resources:
          requests: { memory: "512Mi", cpu: "250m" }
          limits: { memory: "1Gi", cpu: "1000m" }
        lifecycle:
          preStop:
            exec:
              command: ["sh", "-c", "sleep 10"]
        livenessProbe:
          httpGet: { path: /actuator/health/liveness, port: 8080 }
          initialDelaySeconds: 60
          periodSeconds: 30
        readinessProbe:
          httpGet: { path: /actuator/health/readiness, port: 8080 }
          initialDelaySeconds: 30
          periodSeconds: 10
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: orderflow-hpa
  namespace: orderflow
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: orderflow
  minReplicas: 3
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80

输出:

TEXT 📖 仅展示
Deployment.apps/my-app created
Service/my-app-service exposed
Ingress/my-app-ingress created
K8s 生产配置 原因
maxUnavailable: 0 零停机 始终保持目标副本数
terminationGracePeriodSeconds: 60 优雅关闭 等待请求排空
preStop: sleep 10 延迟终止 K8s 从 Service 摘除后仍排空流量
resources.requests/limits 设置 QoS 保证资源保障 + 限制超额

▶ 示例: Ingress + TLS

YAML
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: orderflow-ingress
  namespace: orderflow
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    nginx.ingress.kubernetes.io/rate-limit: "100"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  ingressClassName: nginx
  tls:
  - hosts: [api.orderflow.example.com]
    secretName: orderflow-tls
  rules:
  - host: api.orderflow.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service: { name: orderflow, port: { number: 80 } }

输出:

TEXT 📖 仅展示
Deployment.apps/my-app created
Service/my-app-service exposed
Ingress/my-app-ingress created

5. 可观测性上线

▶ 示例: Prometheus + AlertManager

YAML
# prometheus.yml
scrape_configs:
- job_name: orderflow
  metrics_path: /actuator/prometheus
  scrape_interval: 15s
  kubernetes_sd_configs:
  - role: pod
    namespaces:
      names: [orderflow]
  relabel_configs:
  - source_labels: [__meta_kubernetes_pod_label_app]
    action: keep
    regex: orderflow

输出:

TEXT 📖 仅展示
Deployment.apps/my-app created
Service/my-app-service exposed
Ingress/my-app-ingress created
YAML
# alert_rules.yml
groups:
- name: orderflow-slo
  rules:
  - alert: SLOErrorRateExceeded
    expr: |
      sum(rate(http_server_requests_seconds_total{namespace="orderflow",status=~"5.."}[5m]))
      / sum(rate(http_server_requests_seconds_total{namespace="orderflow"}[5m])) > 0.001
    for: 5m
    labels: { severity: critical }
    annotations:
      summary: "OrderFlow error rate exceeds SLO (0.1%)"

  - alert: SLOLatencyExceeded
    expr: |
      histogram_quantile(0.99,
        sum(rate(http_server_requests_seconds_bucket{namespace="orderflow"}[5m])) by (le))
      > 0.1
    for: 5m
    labels: { severity: warning }
    annotations:
      summary: "OrderFlow P99 latency exceeds SLO (100ms)"

▶ 示例: Grafana SLO Dashboard 指标

面板 PromQL SLO 目标
P99 延迟 histogram_quantile(0.99, sum(rate(http_server_requests_seconds_bucket{namespace="orderflow"}[5m])) by (le)) < 100ms
错误率 sum(rate(http_server_requests_seconds_total{namespace="orderflow",status=~"5.."}[5m])) / sum(rate(http_server_requests_seconds_total{namespace="orderflow"}[5m])) < 0.1%
可用性 1 - (sum(rate(http_server_requests_seconds_total{namespace="orderflow",status=~"5.."}[5m])) / sum(rate(http_server_requests_seconds_total{namespace="orderflow"}[5m]))) > 99.9%
订单吞吐 rate(orderflow_orders_created_total[1m]) * 60 > 100/min

6. 生产安全加固

▶ 示例: NetworkPolicy + Pod Security

YAML
# NetworkPolicy: restrict access
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: orderflow-netpol
  namespace: orderflow
spec:
  podSelector:
    matchLabels: { app: orderflow }
  policyTypes: [Ingress]
  ingress:
  - from:
    - namespaceSelector:
        matchLabels: { name: ingress-nginx }
    ports:
    - { port: 8080, protocol: TCP }
  - from:
    - namespaceSelector:
        matchLabels: { name: monitoring }
    ports:
    - { port: 8081, protocol: TCP }
---
# Pod security: run as non-root
apiVersion: v1
kind: LimitRange
metadata:
  name: orderflow-limits
  namespace: orderflow
spec:
  limits:
  - type: Container
    default:
      memory: "1Gi"
      cpu: "500m"
    defaultRequest:
      memory: "256Mi"
      cpu: "100m"

输出:

TEXT 📖 仅展示
Deployment.apps/my-app created
Service/my-app-service exposed
Ingress/my-app-ingress created
安全加固项 措施 说明
非根运行 Dockerfile USER appuser 防止容器逃逸
NetworkPolicy 限制入站来源 只允许 Ingress 和监控访问
Secret 加密 etcd 加密配置 防止 Secret 明文存储
TLS cert-manager 自动证书 加密传输
资源限制 LimitRange 防止资源争抢

7. 综合示例:OrderFlow 完整部署清单

YAML
# k8s/orderflow-complete.yaml
---
apiVersion: v1
kind: Namespace
metadata:
  name: orderflow
  labels: { name: orderflow }

---
apiVersion: v1
kind: ConfigMap
metadata: { name: orderflow-config, namespace: orderflow }
data:
  SPRING_PROFILES_ACTIVE: "prod"
  DB_HOST: "mysql.orderflow.svc.cluster.local"
  REDIS_HOST: "redis.orderflow.svc.cluster.local"
  MANAGEMENT_SERVER_PORT: "8081"

---
apiVersion: v1
kind: Secret
metadata: { name: orderflow-secrets, namespace: orderflow }
type: Opaque
data:
  DB_PASSWORD: <base64-encoded>
  REDIS_PASSWORD: <base64-encoded>
  JWT_PRIVATE_KEY: <base64-encoded>

---
apiVersion: apps/v1
kind: Deployment
metadata: { name: orderflow, namespace: orderflow }
spec:
  replicas: 3
  selector: { matchLabels: { app: orderflow } }
  strategy: { rollingUpdate: { maxUnavailable: 0, maxSurge: 1 } }
  template:
    metadata: { labels: { app: orderflow } }
    spec:
      terminationGracePeriodSeconds: 60
      containers:
      - name: orderflow
        image: registry.example.com/orderflow-service:1.0.0
        ports: [{ containerPort: 8080 }, { containerPort: 8081 }]
        envFrom:
        - { configMapRef: { name: orderflow-config } }
        - { secretRef: { name: orderflow-secrets } }
        resources:
          requests: { memory: "512Mi", cpu: "250m" }
          limits: { memory: "1Gi", cpu: "1000m" }
        lifecycle:
          preStop: { exec: { command: ["sh", "-c", "sleep 10"] } }
        livenessProbe:
          httpGet: { path: /actuator/health/liveness, port: 8080 }
          initialDelaySeconds: 60; periodSeconds: 30
        readinessProbe:
          httpGet: { path: /actuator/health/readiness, port: 8080 }
          initialDelaySeconds: 30; periodSeconds: 10

---
apiVersion: v1
kind: Service
metadata: { name: orderflow, namespace: orderflow }
spec:
  selector: { app: orderflow }
  ports:
  - { name: http, port: 80, targetPort: 8080 }
  - { name: management, port: 8081, targetPort: 8081 }

---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata: { name: orderflow-hpa, namespace: orderflow }
spec:
  scaleTargetRef: { apiVersion: apps/v1, kind: Deployment, name: orderflow }
  minReplicas: 3
  maxReplicas: 10
  metrics:
  - { type: Resource, resource: { name: cpu, target: { type: Utilization, averageUtilization: 70 } } }

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: orderflow-ingress
  namespace: orderflow
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  ingressClassName: nginx
  tls:
  - { hosts: [api.orderflow.example.com], secretName: orderflow-tls }
  rules:
  - host: api.orderflow.example.com
    http:
      paths:
      - { path: /, pathType: Prefix, backend: { service: { name: orderflow, port: { number: 80 } } } }

❓ 常见问题

Q GitHub Actions 和 Jenkins 该选哪个?
A GitHub Actions 集成 GitHub 生态,配置简单,适合中小项目。Jenkins 功能更强大但配置复杂,适合大型企业。已有 GitHub 仓库推荐 Actions。
Q 滚动更新时如何保证零停机?
A 1)maxUnavailable=0;2)readinessProbe 确保 Pod 就绪后才加入 Service;3)preStop sleep 10 让 K8s 从 Service 摘除后仍有时间排空请求;4)应用配置 server.shutdown=graceful
Q HPA 的 minReplicas 和 maxReplicas 怎么设?
A minReplicas = 正常负载所需副本数(OrderFlow = 3),maxReplicas = 峰值负载预估(OrderFlow = 10)。根据历史监控数据调整。CPU 目标利用率建议 70%。
Q Secret 管理的最佳实践是什么?
A 1)K8s Secret + etcd 加密(基础方案);2)External Secrets Operator + AWS Secrets Manager/Vault(推荐方案);3)Sealed Secrets(GitOps 友好)。不要把 Secret 明文写在 Git 中。
Q 如何实现蓝绿部署或金丝雀发布?
A K8s 原生不支持蓝绿/金丝雀,需要 Istio/Argo Rollouts 等工具。Argo Rollouts 支持 canary(逐步切流量)、blue-green(瞬间切换),配合 Prometheus 验证。
Q 生产环境的监控告警应该覆盖哪些?
A 三大类:1)SLO 告警(P99 延迟、错误率、可用性);2)资源告警(CPU > 80%、内存 > 85%、磁盘 > 90%);3)业务告警(订单量异常下降、支付成功率下降)。

📖 小节


📝 作业

  1. 基础题(难度⭐):编写 GitHub Actions 工作流,实现代码推送后自动测试和构建 Docker 镜像。

  2. 进阶题(难度⭐⭐):编写完整的 K8s 生产部署 YAML(Deployment + Service + Ingress + HPA + ConfigMap + Secret),实现零停机滚动更新。

  3. 挑战题(难度⭐⭐⭐):搭建完整的可观测性体系(Prometheus + Grafana + AlertManager + Jaeger),配置 SLO 看板和告警规则,模拟故障验证告警和自动恢复能力。

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏