Spring Boot: 综合实战:OrderFlow 项目部署
最后更新:2026-08-26
部署是最后一公里——CI/CD 自动化、K8s 编排、监控告警,让应用从开发到生产一路畅通。
1. 你将学到
- CI/CD 流水线:GitHub Actions 构建镜像 → 推送 Registry → K8s 滚动部署
- K8s 生产部署:Deployment + HPA 自动伸缩 + Ingress 网关
- 可观测性上线:Prometheus + Grafana + AlertManager 告警规则
- 生产安全加固:Secret 管理 / NetworkPolicy / Pod Security Standards
- Bob 将 OrderFlow 部署至生产环境,支撑日订单量百万级业务运行
2. 一个 DevOps 工程师的真实故事
(1) 痛点:手动部署像踩雷
Bob 手动部署 OrderFlow 到生产:本地 mvn package → docker build → 推镜像 → kubectl apply → 检查健康状态。整个流程 30 分钟,而且经常出错:忘了改配置、推错镜像版本、滚动更新时旧 Pod 没有优雅关闭导致 502 错误。
(2) CI/CD 的解法
自动化流水线一条龙:
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)业务告警(订单量异常下降、支付成功率下降)。
📖 小节
- CI/CD 流水线:代码推送 → 自动测试 → 构建镜像 → 推送 Registry → K8s 滚动部署
- 生产部署:Deployment + HPA 自动伸缩 + Ingress 网关 + TLS
- 零停机部署:maxUnavailable=0 + readinessProbe + preStop + graceful shutdown
- 可观测性:Prometheus 抓取 + Grafana SLO 看板 + AlertManager 告警
- 安全加固:非根用户 + NetworkPolicy + Secret 加密 + TLS + 资源限制
- 从设计到部署的全链路交付,支撑日订单量百万级业务
📝 作业
-
基础题(难度⭐):编写 GitHub Actions 工作流,实现代码推送后自动测试和构建 Docker 镜像。
-
进阶题(难度⭐⭐):编写完整的 K8s 生产部署 YAML(Deployment + Service + Ingress + HPA + ConfigMap + Secret),实现零停机滚动更新。
-
挑战题(难度⭐⭐⭐):搭建完整的可观测性体系(Prometheus + Grafana + AlertManager + Jaeger),配置 SLO 看板和告警规则,模拟故障验证告警和自动恢复能力。