
1. 引言Kubernetes简称 K8s已经成为现代微服务架构的事实标准。对于 Java 开发者来说将 Spring Boot 等应用部署到 K8s 中不仅能实现弹性伸缩、滚动更新还能大幅提升资源利用率。然而Java 应用在 K8s 中的部署并非一帆风顺——内存配置、健康检查、优雅停机、HPA 自动扩缩容等环节都暗藏陷阱。本文将以一个完整的实战视角带你从零开始使用 Deployment、Service、ConfigMap 部署一个 Java 应用并配置健康检查、优雅停机与 HPA 自动扩缩容最后总结 Java 应用在 K8s 中常见的坑与解决方案。2. 核心概念速览在开始之前我们先快速梳理本文涉及的核心 K8s 资源Deployment负责管理无状态应用的副本Pod生命周期支持滚动更新、回滚、水平扩缩容。Service为 Pod 提供稳定的网络访问入口实现服务发现与负载均衡。ConfigMap将配置与镜像解耦便于在不同环境开发、测试、生产间复用同一镜像。健康检查通过 livenessProbe存活探针与 readinessProbe就绪探针保障应用可用性。优雅停机让 Pod 在终止前完成正在处理的请求避免服务中断。HPAHorizontalPodAutoscaler根据 CPU、内存或自定义指标自动调整 Pod 副本数。3. 环境准备3.1 前置条件一个可用的 K8s 集群本地可用 Minikube、Kind生产可用云厂商托管集群。已安装kubectl命令行工具并配置好集群访问凭证。一个 Java 应用镜像本文以 Spring Boot 应用为例Dockerfile 已构建并推送到镜像仓库。3.2 验证集群kubectl cluster-info kubectl get nodes确保集群节点处于Ready状态。4. 编写 Deployment 部署 Java 应用4.1 基础 Deployment 示例创建一个deployment.yaml文件apiVersion:apps/v1kind:Deploymentmetadata:name:java-applabels:app:java-appspec:replicas:2selector:matchLabels:app:java-apptemplate:metadata:labels:app:java-appspec:containers:-name:java-appimage:registry.example.com/java-app:1.0.0ports:-containerPort:8080resources:requests:cpu:250mmemory:512Milimits:cpu:500mmemory:1Gi注意resources配置对 Java 应用至关重要。JVM 默认会读取宿主机内存来设置堆大小若不显式指定可能导致容器内存超限被 OOMKilled。4.2 应用 Deploymentkubectl apply-fdeployment.yaml kubectl get pods5. 创建 Service 暴露服务5.1 Service 配置创建service.yamlapiVersion:v1kind:Servicemetadata:name:java-app-servicespec:selector:app:java-appports:-protocol:TCPport:80targetPort:8080type:ClusterIP5.2 应用并验证kubectl apply-fservice.yaml kubectl get svc java-app-service在集群内部可以通过java-app-service:80访问 Java 应用。6. 使用 ConfigMap 管理配置6.1 创建 ConfigMap将应用配置如application.yml中的非敏感配置抽离到 ConfigMapapiVersion:v1kind:ConfigMapmetadata:name:java-app-configdata:application.yml:|server: port: 8080 spring: datasource: url: jdbc:mysql://mysql-service:3306/mydb username: root password: ${DB_PASSWORD}6.2 在 Deployment 中挂载 ConfigMap更新deployment.yaml将 ConfigMap 挂载到容器内spec:template:spec:containers:-name:java-appimage:registry.example.com/java-app:1.0.0volumeMounts:-name:configmountPath:/app/configvolumes:-name:configconfigMap:name:java-app-config提示敏感信息如密码请使用 Secret而非 ConfigMap。7. 健康检查与优雅停机7.1 配置健康检查探针Java 应用尤其是 Spring Boot应暴露健康检查端点。Spring Boot Actuator 提供了/actuator/health端点。在 Deployment 中添加探针spec:containers:-name:java-applivenessProbe:httpGet:path:/actuator/healthport:8080initialDelaySeconds:30periodSeconds:10timeoutSeconds:3failureThreshold:3readinessProbe:httpGet:path:/actuator/healthport:8080initialDelaySeconds:15periodSeconds:5timeoutSeconds:3failureThreshold:3livenessProbe检测应用是否存活失败则重启容器。readinessProbe检测应用是否就绪失败则从 Service 端点中摘除不接收流量。7.2 优雅停机配置K8s 在终止 Pod 时会先发送SIGTERM信号等待terminationGracePeriodSeconds默认 30 秒后强制发送SIGKILL。Spring Boot 应用需要优雅处理SIGTERMspec:terminationGracePeriodSeconds:60containers:-name:java-applifecycle:preStop:exec:command:[sh,-c,sleep 10]同时在application.yml中配置优雅停机server:shutdown:gracefulspring:lifecycle:timeout-per-shutdown-phase:20s说明preStop中的sleep 10是为了给 Service 端点摘除留出时间避免新请求在 Pod 终止过程中被路由进来。8. HPA 自动扩缩容8.1 安装 Metrics ServerHPA 依赖 Metrics Server 收集 Pod 的 CPU/内存指标kubectl apply-fhttps://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml验证kubectltopnodes kubectltoppods8.2 创建 HPA创建hpa.yamlapiVersion:autoscaling/v2kind:HorizontalPodAutoscalermetadata:name:java-app-hpaspec:scaleTargetRef:apiVersion:apps/v1kind:Deploymentname:java-appminReplicas:2maxReplicas:10metrics:-type:Resourceresource:name:cputarget:type:UtilizationaverageUtilization:60-type:Resourceresource:name:memorytarget:type:UtilizationaverageUtilization:708.3 应用并验证kubectl apply-fhpa.yaml kubectl get hpa8.4 压测验证扩缩容# 使用压测工具模拟流量kubectl run load-generator--imagebusybox -- /bin/sh-cwhile true; do wget -q -O- http://java-app-service; done观察 HPA 状态kubectl get hpa-wkubectl get pods当 CPU 使用率超过 60% 时HPA 会自动增加副本数负载下降后会逐步缩容。9. Java 应用在 K8s 中的坑与解决方案9.1 坑一JVM 内存配置不当导致 OOMKilled问题JVM 默认堆大小取宿主机内存的 1/4容器内存限制为 1Gi 时JVM 可能申请超过限制的内存被 K8s 强制杀死。解决在容器启动命令中显式设置 JVM 内存参数spec:containers:-name:java-appcommand:[java]args:--Xms512m--Xmx512m--XX:MaxMetaspaceSize256m--jar-/app/app.jar建议-Xmx设置为容器内存 limit 的 50%~70%预留堆外内存Metaspace、线程栈、Direct Buffer空间。9.2 坑二健康检查端点未开启问题未引入 Spring Boot Actuator或未暴露/actuator/health导致探针失败Pod 反复重启。解决引入依赖并暴露端点dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId/dependencymanagement:endpoints:web:exposure:include:health,info9.3 坑三优雅停机未生效请求被中断问题未配置server.shutdowngraceful或terminationGracePeriodSeconds过短导致正在处理的请求被强制中断。解决参考 7.2 节配置优雅停机并适当调大terminationGracePeriodSeconds。9.4 坑四HPA 扩缩容滞后或抖动问题Java 应用启动慢JVM 冷启动HPA 扩容后新 Pod 长时间未就绪或缩容过快导致抖动。解决设置合理的initialDelaySeconds和periodSeconds。使用behavior配置扩缩容策略behavior:scaleUp:stabilizationWindowSeconds:60policies:-type:Percentvalue:100periodSeconds:60scaleDown:stabilizationWindowSeconds:300policies:-type:Podsvalue:1periodSeconds:609.5 坑五镜像拉取策略导致更新不及时问题使用latest标签且imagePullPolicy为IfNotPresent导致更新镜像后 Pod 仍使用旧镜像。解决使用不可变标签如版本号并设置imagePullPolicy: Always仅开发环境或IfNotPresent生产环境配合版本标签。9.6 坑六时区与日志问题问题容器默认 UTC 时区日志时间与本地不一致日志未输出到 stdout导致kubectl logs看不到。解决通过环境变量或 JVM 参数设置时区TZAsia/Shanghai。确保日志输出到 stdout/stderrSpring Boot 默认行为避免写入容器内文件。10. 总结本文从零开始完整演示了如何使用 Deployment、Service、ConfigMap 将 Java 应用部署到 K8s并配置了健康检查、优雅停机与 HPA 自动扩缩容。最后总结了 Java 应用在 K8s 中常见的六大坑及解决方案。核心要点回顾资源限制务必显式设置 JVM 内存参数避免 OOMKilled。健康检查开启 Actuator配置合理的 liveness 与 readiness 探针。优雅停机配置server.shutdowngraceful与preStop钩子。HPA依赖 Metrics Server合理设置扩缩容策略与稳定窗口。镜像管理使用不可变标签避免latest带来的混乱。希望本文能帮助你在 K8s 中稳定、高效地运行 Java 应用。如果你在实践中遇到其他坑欢迎在评论区交流讨论。