K8s 部署
Kubernetes 是容器编排的事实标准,Spring Boot 应用容器化后可利用 K8s 实现滚动发布、自动扩缩容、健康自愈等能力。本文以常见生产配置为主线,覆盖 Deployment、Service、ConfigMap、Ingress、HPA 等核心资源。
前置:构建镜像
K8s 部署前需先将应用打包为 Docker 镜像并推送到镜像仓库,详见 Docker部署。
# 构建并推送
docker build -t registry.example.com/myapp:1.2.0 .
docker push registry.example.com/myapp:1.2.0一、Deployment
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
namespace: production
labels:
app: myapp
version: "1.2.0"
spec:
replicas: 3
selector:
matchLabels:
app: myapp
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 滚动时最多多创建 1 个 Pod
maxUnavailable: 0 # 滚动时保持所有旧 Pod 可用(零停机)
template:
metadata:
labels:
app: myapp
version: "1.2.0"
spec:
containers:
- name: myapp
image: registry.example.com/myapp:1.2.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
name: http
- containerPort: 8081
name: actuator
# 资源限制
resources:
requests:
cpu: 250m
memory: 512Mi
limits:
cpu: 1000m
memory: 1Gi
# 环境变量
env:
- name: SPRING_PROFILES_ACTIVE
value: "production"
- name: JAVA_TOOL_OPTIONS
value: "-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0 -Dfile.encoding=UTF-8"
# 从 Secret 注入数据库密码
- name: SPRING_DATASOURCE_PASSWORD
valueFrom:
secretKeyRef:
name: myapp-secrets
key: db-password
# 从 ConfigMap 注入配置
- name: SPRING_DATASOURCE_URL
valueFrom:
configMapKeyRef:
name: myapp-config
key: db-url
# 存活探针:失败则重启 Pod
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: actuator
initialDelaySeconds: 60 # 等待 JVM 启动
periodSeconds: 10
failureThreshold: 3
# 就绪探针:失败则从 Service 摘除,不接收流量
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: actuator
initialDelaySeconds: 30
periodSeconds: 5
failureThreshold: 3
# 启动探针:应用启动慢时防止存活探针误杀
startupProbe:
httpGet:
path: /actuator/health/liveness
port: actuator
initialDelaySeconds: 10
periodSeconds: 5
failureThreshold: 30 # 最多等 30*5=150 秒
# 优雅停机:SIGTERM 后等待请求处理完毕
lifecycle:
preStop:
exec:
command: ["sh", "-c", "sleep 5"] # 等待 LB 摘除此 Pod
# 终止等待时间(需大于 Spring 优雅停机超时)
terminationGracePeriodSeconds: 60
imagePullSecrets:
- name: registry-credentials二、Service
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: myapp
namespace: production
spec:
selector:
app: myapp
ports:
- name: http
port: 80
targetPort: 8080
- name: actuator
port: 8081
targetPort: 8081
type: ClusterIP # 集群内部访问;对外暴露用 Ingress三、ConfigMap 与 Secret
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: myapp-config
namespace: production
data:
db-url: "jdbc:postgresql://postgres-service:5432/mydb"
redis-host: "redis-service"
# 完整 application.yml(挂载为文件)
application.yml: |
spring:
jpa:
open-in-view: false
cache:
type: redis
logging:
level:
root: INFO# secret.yaml(值需 base64 编码)
apiVersion: v1
kind: Secret
metadata:
name: myapp-secrets
namespace: production
type: Opaque
stringData: # stringData 无需手动 base64
db-password: "s3cr3t"
redis-password: "r3d1s"
jwt-secret: "very-long-jwt-secret-key"将 ConfigMap 挂载为配置文件
# deployment.yaml 中添加
spec:
template:
spec:
containers:
- name: myapp
volumeMounts:
- name: config-volume
mountPath: /app/config
readOnly: true
env:
- name: SPRING_CONFIG_ADDITIONAL_LOCATION
value: "file:/app/config/"
volumes:
- name: config-volume
configMap:
name: myapp-config
items:
- key: application.yml
path: application.yml四、Ingress(对外暴露)
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp
namespace: production
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/proxy-connect-timeout: "10"
nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
nginx.ingress.kubernetes.io/proxy-body-size: "10m"
# HTTPS 重定向
nginx.ingress.kubernetes.io/ssl-redirect: "true"
# 限流
nginx.ingress.kubernetes.io/limit-rps: "100"
spec:
ingressClassName: nginx
tls:
- hosts:
- api.example.com
secretName: api-tls-cert
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: myapp
port:
name: http五、HPA 自动扩缩容
# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: myapp
namespace: production
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: myapp
minReplicas: 2
maxReplicas: 20
metrics:
# CPU 使用率超过 60% 触发扩容
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
# 内存使用率超过 70% 触发扩容
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 70
behavior:
scaleUp:
stabilizationWindowSeconds: 60 # 扩容冷却 60 秒
policies:
- type: Pods
value: 2
periodSeconds: 60 # 每 60 秒最多扩 2 个 Pod
scaleDown:
stabilizationWindowSeconds: 300 # 缩容冷却 300 秒(防抖)
policies:
- type: Percent
value: 10
periodSeconds: 60 # 每 60 秒最多缩 10%六、健康检查端点配置
Spring Boot Actuator 需开放健康探针端点:
# application.yml
server:
port: 8080
management:
server:
port: 8081 # Actuator 独立端口,不对外暴露
endpoint:
health:
probes:
enabled: true # 启用 liveness/readiness 探针
show-details: always
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
health:
livenessstate:
enabled: true
readinessstate:
enabled: true探针路径:
| 路径 | K8s 用途 |
|---|---|
/actuator/health/liveness | livenessProbe — 失败重启 Pod |
/actuator/health/readiness | readinessProbe — 失败摘除流量 |
/actuator/prometheus | Prometheus 指标采集 |
Actuator 详细配置见 Actuator监控;指标采集见 指标采集。
七、优雅滚动发布
滚动发布零停机的关键:maxUnavailable: 0 + Spring 优雅停机 + preStop 延迟。
# application.yml
server:
shutdown: graceful # 开启优雅停机
spring:
lifecycle:
timeout-per-shutdown-phase: 30s # 等待正在处理的请求最多 30 秒发布流程:
1. K8s 创建新 Pod(拉取新镜像)
2. 新 Pod startupProbe 通过 → readinessProbe 通过
3. 新 Pod 加入 Service(开始接收流量)
4. 老 Pod 收到 SIGTERM → preStop 执行(sleep 5,等 LB 摘除)
5. Spring 停止接收新请求 → 等待现有请求处理完毕
6. 老 Pod 退出
优雅停机详见 优雅停机。
八、常用 kubectl 命令
# 部署 / 更新
kubectl apply -f k8s/
# 查看部署状态
kubectl rollout status deployment/myapp -n production
# 查看 Pod 日志
kubectl logs -f deployment/myapp -n production --tail=100
# 进入 Pod
kubectl exec -it deployment/myapp -n production -- sh
# 回滚到上一版本
kubectl rollout undo deployment/myapp -n production
# 查看滚动历史
kubectl rollout history deployment/myapp -n production
# 手动扩缩容
kubectl scale deployment/myapp --replicas=5 -n production
# 强制重启(触发滚动更新)
kubectl rollout restart deployment/myapp -n production
# 查看 HPA 状态
kubectl get hpa myapp -n production -w九、Kustomize 多环境管理
k8s/
├── base/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── kustomization.yaml
└── overlays/
├── staging/
│ ├── kustomization.yaml
│ └── patch-replicas.yaml
└── production/
├── kustomization.yaml
└── patch-resources.yaml
# k8s/base/kustomization.yaml
resources:
- deployment.yaml
- service.yaml
commonLabels:
app: myapp# k8s/overlays/production/kustomization.yaml
resources:
- ../../base
images:
- name: registry.example.com/myapp
newTag: "1.2.0"
patches:
- path: patch-resources.yaml
# k8s/overlays/production/patch-resources.yaml
- op: replace
path: /spec/replicas
value: 5# 部署到生产
kubectl apply -k k8s/overlays/production/相关链接
- Docker部署 — 构建容器镜像
- 优雅停机 — SIGTERM 处理与零停机发布
- Actuator监控 — 健康探针端点配置
- 指标采集 — Prometheus + Grafana 监控
- 链路追踪 — 分布式环境下的请求追踪
- 日志聚合 — ELK / Loki 日志采集
- 配置管理 — 外部化配置与 ConfigMap
- GraalVM原生编译 — 缩小镜像体积、加速冷启动