这是《Spring Boot 与 Spring Cloud 零基础实战指南》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 容器化让 Spring Boot 应用以一致环境运行,Kubernetes 提供调度、扩缩容、发布和服务发现能力。云原生不是把 jar 放进容器,而是围绕健康检查、资源、配置、弹性和可观测重新设计运行方式。
28.1 Dockerfile
简单示例:
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY target/app.jar /app/app.jar
ENV TZ=Asia/Shanghai \
JAVA_OPTS=""
EXPOSE 8080
ENTRYPOINT ["sh", "-c", "exec java $JAVA_OPTS -jar /app/app.jar"]
最佳实践:
- 使用多阶段构建;
- 镜像最小化;
- 使用非 root 用户;
- 不把 secret 写入镜像;
exec确保 Java 是 PID 1;- 固定基础镜像版本;
- 扫描漏洞。
28.2 JVM 容器参数
java -XX:+UseContainerSupport \
-XX:InitialRAMPercentage=60.0 \
-XX:MaxRAMPercentage=60.0 \
-XX:ActiveProcessorCount=4 \
-jar /app/app.jar
内存预算:
容器 limit
>= Heap
+ Metaspace
+ Thread stacks
+ Direct memory
+ CodeCache
+ Native
+ 余量
若 MaxRAMPercentage=75 且 Netty、压缩缓存、大量线程同时存在,可能仍会 OOMKilled,需要按应用实测。
28.3 Kubernetes Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1
template:
spec:
containers:
- name: order
image: registry.example.com/order-service:1.8.0
ports:
- containerPort: 8080
resources:
requests:
cpu: "1"
memory: "2Gi"
limits:
memory: "2Gi"
内存 request 和 limit 通常保持一致,避免调度与实际限制不一致。
28.4 探针
startupProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
failureThreshold: 30
periodSeconds: 2
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
区别:
| 探针 | 失败结果 |
|---|---|
| startup | 延长启动判断 |
| liveness | 重启容器 |
| readiness | 摘除流量 |
liveness 检查不应包含外部依赖,否则下游故障会引发服务重启风暴。
28.5 ConfigMap 与 Secret
ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:
name: order-config
data:
SPRING_PROFILES_ACTIVE: "prod"
PAY_TIMEOUT: "3s"
生产建议使用平台密钥系统注入,而不是明文 Secret YAML。配置变更要有版本和回滚能力。
28.6 Service 与 Ingress
apiVersion: v1
kind: Service
metadata:
name: order-service
spec:
selector:
app: order-service
ports:
- port: 80
targetPort: 8080
Ingress 或 Gateway API 负责外部路由、TLS 和流量策略。服务间调用可选择 Kubernetes Service、注册中心或服务网格,保持一种主模型,避免策略分裂。
28.7 HPA
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: order-service
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: order-service
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 65
HPA 依赖指标可用。扩容还需考虑数据库连接总量、下游容量、冷启动、缓存预热、第三方限流和成本。
28.8 Service Mesh
网格提供 mTLS、流量拆分、重试超时、故障注入、遥测和权限策略。
Spring Cloud 与网格能力可能重叠:
| 能力 | Spring Cloud | Mesh |
|---|---|---|
| 服务发现 | 可用 | 平台提供 |
| 熔断 | 应用内 | sidecar 策略 |
| 灰度 | 网关/注册元数据 | 流量规则 |
| mTLS | 按需实现 | 常见能力 |
选择时避免同一能力双层配置且语义不一致。
28.9 资源与调度
CPU:
- request 影响调度;
- limit 触发 throttling;
- GC/JIT 线程受 CPU 感知影响;
- 突发流量要评估毛刺。
常见问题:
| 现象 | 原因 |
|---|---|
| OOMKilled | 内存超限 |
| 延迟毛刺 | CPU throttling |
| Pod Pending | 资源不足 |
| 反复重启 | liveness 失败 |
| 发布卡住 | PDB 或探针 |
| 调度不均 | request 设置不合理 |
28.10 云原生清单
1. 镜像不可变且可追溯
2. 配置外部化
3. secret 独立管理
4. 健康探针正确
5. 优雅停机
6. 资源 request/limit 合理
7. HPA 策略验证
8. 日志输出 stdout 或挂载卷
9. 指标和 trace 接入
10. 发布可回滚
11. PDB 保证最小可用
12. 网络策略和安全策略
本章小结
容器与云原生部署要关注镜像、JVM 资源感知、探针、配置注入、自动扩缩容和优雅停机。Kubernetes 提供调度和发布能力,但应用仍需暴露正确健康状态并控制资源。引入服务网格时要明确与 Spring Cloud 治理能力的边界。
思考题
- 为什么 ENTRYPOINT 中要使用
exec java? - 内存 request 和 limit 为什么常保持一致?
- liveness 为什么不应检查外部依赖?
- HPA 扩容有哪些隐藏限制?
- Spring Cloud 和 Service Mesh 能力如何分工?