目录
-
- 前言
- 摘要
- [1. 引言](#1. 引言)
-
- [1.1 为什么需要云原生迁移](#1.1 为什么需要云原生迁移)
- [1.2 本文目标读者](#1.2 本文目标读者)
- [1.3 技术栈概览](#1.3 技术栈概览)
- [2. 云原生架构概述](#2. 云原生架构概述)
-
- [2.1 什么是云原生](#2.1 什么是云原生)
- [2.2 云原生的核心优势](#2.2 云原生的核心优势)
- [2.3 云原生成熟度模型](#2.3 云原生成熟度模型)
- [3. Spring Boot框架介绍](#3. Spring Boot框架介绍)
-
- [3.1 Spring Boot核心特性](#3.1 Spring Boot核心特性)
- [3.2 Spring Boot 3.x新特性](#3.2 Spring Boot 3.x新特性)
- [3.3 Spring Boot与云原生的契合点](#3.3 Spring Boot与云原生的契合点)
- [4. Kubernetes核心概念详解](#4. Kubernetes核心概念详解)
-
- [4.1 Kubernetes架构概](#4.1 Kubernetes架构概)
- [4.2 核心资源对象](#4.2 核心资源对象)
- [4.3 Kubernetes网络模型](#4.3 Kubernetes网络模型)
- [5. Spring Boot应用容器化](#5. Spring Boot应用容器化)
-
- [5.1 创建Spring Boot项目](#5.1 创建Spring Boot项目)
- [5.2 编写应用主类和控制器](#5.2 编写应用主类和控制器)
- [5.3 编写Dockerfile](#5.3 编写Dockerfile)
- [5.4 构建和测试容器镜像](#5.4 构建和测试容器镜像)
- [6. Kubernetes部署配置](#6. Kubernetes部署配置)
-
- [6.1 创建命名空间](#6.1 创建命名空间)
- [6.2 创建ConfigMap](#6.2 创建ConfigMap)
- [6.3 创建Secret](#6.3 创建Secret)
- [6.4 创建Deployment](#6.4 创建Deployment)
- [6.5 创建Service](#6.5 创建Service)
- [6.6 创建Ingress](#6.6 创建Ingress)
- [7. 部署与验证](#7. 部署与验证)
-
- [7.1 应用部署流程](#7.1 应用部署流程)
- [7.2 执行部署命令](#7.2 执行部署命令)
- [7.3 验证部署结果](#7.3 验证部署结果)
- [8. 高级配置与优化](#8. 高级配置与优化)
-
- [8.1 水平自动扩缩容(HPA)](#8.1 水平自动扩缩容(HPA))
- [8.2 配置管理最佳实践](#8.2 配置管理最佳实践)
- [8.3 日志与监控集成](#8.3 日志与监控集成)
- [9. CI/CD流水线集成](#9. CI/CD流水线集成)
-
- [9.1 GitOps工作流](#9.1 GitOps工作流)
- [9.2 GitHub Actions示例](#9.2 GitHub Actions示例)
- [10. 常见问题与解决方案](#10. 常见问题与解决方案)
-
- [10.1 应用启动失败](#10.1 应用启动失败)
- [10.2 服务无法访问](#10.2 服务无法访问)
- [10.3 配置更新不生效](#10.3 配置更新不生效)
- [11. 总结](#11. 总结)
- 参考资料
前言
作为一名有多年Java开发经验的工程师,我深刻体会到传统部署模式的痛点:环境不一致导致的"在我机器上能运行"问题、手动部署的繁琐流程、扩容困难等。自从将Spring Boot应用迁移到Kubernetes后,这些问题都得到了系统性的解决。
本文是我将多个Spring Boot项目迁移至Kubernetes的经验总结,涵盖了从容器化到生产部署的完整流程。无论你是刚开始接触云原生,还是已经在使用Kubernetes,都能从本文中获得有价值的实践指导。
摘要
随着云原生技术的快速发展,越来越多的企业开始将传统应用迁移至Kubernetes平台。本文详细介绍了如何将Spring Boot应用从传统部署方式迁移至Kubernetes云原生环境的完整过程。内容涵盖云原生概念解析、Spring Boot应用容器化、Kubernetes核心资源对象配置、服务发现与负载均衡、配置管理、持久化存储、健康检查机制以及CI/CD流水线集成等关键技术点。通过本文的学习,读者将掌握Spring Boot应用云原生迁移的最佳实践,能够独立完成从开发到生产的全流程部署。
通过本文你将学到:
- 云原生架构的核心概念与优势
- Spring Boot应用Docker容器化最佳实践
- Kubernetes核心资源对象(Deployment、Service、ConfigMap、Secret)的配置与管理
- 生产环境的高可用部署策略
- CI/CD流水线与Kubernetes的集成方案
1. 引言
1.1 为什么需要云原生迁移
在传统的应用部署模式中,开发团队往往面临着诸多挑战:环境不一致导致的"在我机器上能运行"问题、资源利用率低下、扩缩容困难、部署流程繁琐等。随着业务规模的快速增长,这些问题变得愈发突出,严重影响了开发效率和系统稳定性。
云原生(Cloud Native)作为一种现代化的应用架构理念,为解决上述问题提供了系统性的解决方案。通过容器化、微服务、DevOps等技术手段,云原生架构能够显著提升应用的弹性、可扩展性和运维效率。根据CNCF(云原生计算基金会)的调查报告,超过93%的组织正在使用或评估Kubernetes,云原生已经成为企业数字化转型的必然选择。
1.2 本文目标读者
本文适合以下读者群体:
| 读者类型 | 前置知识要求 | 学习目标 |
|---|---|---|
| Java后端开发工程师 | 熟悉Spring Boot开发 | 掌握云原生部署技能 |
| DevOps工程师 | 了解Docker基础 | 深入Kubernetes实践 |
| 架构师 | 具备分布式系统经验 | 设计云原生架构方案 |
| 运维工程师 | 熟悉Linux系统 | 掌握K8s运维管理 |
1.3 技术栈概览
本文涉及的主要技术栈如下:
🔧 运维层
⚙️ 编排层
📦 容器层
🖥️ 开发层
Spring Boot 3.x
Maven/Gradle
JDK 17+
Docker
Dockerfile
Docker Compose
Kubernetes
Helm
kubectl
Prometheus
Grafana
ELK Stack
2. 云原生架构概述
2.1 什么是云原生
云原生(Cloud Native)是一种构建和运行应用程序的方法,它充分利用云计算模型的优势,包括弹性、敏捷性和分布式特性。根据CNCF的定义,云原生技术包括容器、服务网格、微服务、不可变基础设施和声明式API等。
云原生的核心理念可以概括为以下几点:
容器化封装:将应用程序及其依赖项打包到容器中,实现环境的一致性和可移植性。容器镜像成为应用交付的标准单元,消除了"在我的机器上能运行"的问题。
动态编排:使用Kubernetes等容器编排平台管理容器的生命周期,实现自动化部署、扩缩容和故障恢复。编排系统能够根据负载情况动态调整资源分配。
微服务架构:将单体应用拆分为多个小型、独立的服务,每个服务专注于单一业务功能。微服务之间通过轻量级通信机制(如REST API、gRPC)进行交互。
DevOps实践:建立开发与运维之间的协作机制,实现持续集成、持续交付(CI/CD)。通过自动化流水线,代码变更能够快速、安全地部署到生产环境。
2.2 云原生的核心优势
相比传统部署模式,云原生架构具有以下显著优势:
| 特性 | 传统部署 | 云原生部署 | 优势说明 |
|---|---|---|---|
| 弹性伸缩 | 手动扩容,耗时数小时 | 自动扩缩容,秒级响应 | 应对流量波动更灵活 |
| 故障恢复 | 人工介入,恢复时间长 | 自动重启/迁移,秒级恢复 | 提升系统可用性 |
| 资源利用 | 固定资源分配,浪费严重 | 动态调度,按需分配 | 降低基础设施成本 |
| 部署效率 | 手动部署,易出错 | 自动化流水线,标准化 | 缩短发布周期 |
| 环境一致性 | 环境差异大,问题频发 | 容器化封装,环境统一 | 减少环境相关问题 |
2.3 云原生成熟度模型
企业在进行云原生转型时,通常会经历以下阶段:
阶段0
传统部署
阶段1
容器化
阶段2
编排管理
阶段3
DevOps集成
阶段4
云原生成熟
阶段0 - 传统部署:应用直接部署在物理服务器或虚拟机上,缺乏容器化和自动化能力。
阶段1 - 容器化:应用完成容器化封装,使用Docker进行本地开发和测试,但尚未使用编排系统。
阶段2 - 编排管理:引入Kubernetes进行容器编排,实现应用的自动化部署和管理。
阶段3 - DevOps集成:建立CI/CD流水线,实现代码到生产的自动化交付,开始采用GitOps实践。
阶段4 - 云原生成熟:全面采用云原生技术栈,包括服务网格、可观测性、混沌工程等,实现高度自动化和智能化运维。
3. Spring Boot框架介绍
3.1 Spring Boot核心特性
Spring Boot是Pivotal团队于2014年推出的Java快速开发框架,它基于Spring生态系统,通过"约定优于配置"的理念,大幅简化了Spring应用的初始搭建和开发过程。Spring Boot已经成为Java微服务开发的事实标准。
Spring Boot的核心特性包括:
自动配置(Auto-configuration) :Spring Boot会根据项目依赖自动配置Spring应用,减少大量的XML配置和样板代码。例如,当项目中引入了spring-boot-starter-web依赖,Spring Boot会自动配置嵌入式Tomcat、Spring MVC等组件。
起步依赖(Starter Dependencies) :Spring Boot提供了一系列"起步依赖",将常用的依赖组合打包。开发者只需引入一个starter依赖,就能获得一组协调好版本的依赖集合。例如,spring-boot-starter-data-jpa包含了JPA、Hibernate、Spring Data JPA等依赖。
嵌入式容器(Embedded Containers):Spring Boot内置了Tomcat、Jetty、Undertow等Servlet容器,应用可以打包为独立的可执行JAR文件,无需部署到外部应用服务器。
生产就绪特性(Production-ready Features):Spring Boot Actuator提供了健康检查、指标收集、外部化配置等生产环境必需的功能,开箱即用。
3.2 Spring Boot 3.x新特性
2022年发布的Spring Boot 3.x带来了多项重要更新:
| 特性 | 说明 | 影响 |
|---|---|---|
| JDK 17基线 | 最低要求JDK 17 | 利用Java新特性,提升性能 |
| Jakarta EE 9+ | 从javax迁移到jakarta命名空间 | 与Java EE生态保持一致 |
| 原生编译支持 | 支持GraalVM原生镜像编译 | 启动时间缩短至毫秒级 |
| 可观测性增强 | 集成Micrometer Observation API | 简化分布式追踪集成 |
| 虚拟线程支持 | 支持JDK 21虚拟线程(Project Loom) | 大幅提升并发性能 |
3.3 Spring Boot与云原生的契合点
Spring Boot的设计理念与云原生架构高度契合:
快速启动:Spring Boot应用的启动时间通常在几秒到十几秒,非常适合容器化环境中的快速扩容场景。
无状态设计:Spring Boot鼓励无状态应用设计,将状态存储在外部(如Redis、数据库),这与Kubernetes的Pod生命周期管理完美匹配。
配置外置:Spring Boot支持多种外部化配置方式,包括环境变量、配置文件、配置中心等,便于在Kubernetes中使用ConfigMap和Secret。
健康检查:Spring Boot Actuator提供了开箱即用的健康检查端点,可以轻松集成到Kubernetes的探针机制中。
4. Kubernetes核心概念详解
4.1 Kubernetes架构概
Kubernetes(简称K8s)是Google开源的容器编排平台,用于自动化部署、扩展和管理容器化应用。Kubernetes采用Master-Worker架构,由控制平面(Control Plane)和工作节点(Worker Node)组成。
💻 工作节点 2
💻 工作节点 1
🎛️ 控制平面 (Control Plane)
kube-apiserver
API服务器
etcd
键值存储
kube-scheduler
调度器
kube-controller-manager
控制器管理器
cloud-controller-manager
云控制器管理器
kubelet
kube-proxy
Container Runtime
Pod 1
Pod 2
kubelet
kube-proxy
Container Runtime
Pod 3
Pod 4
控制平面组件:
-
kube-apiserver:集群的统一入口,所有请求都通过API Server进行处理。它负责认证、授权、准入控制等功能。
-
etcd:高可用的键值存储,保存集群的所有状态数据。etcd是Kubernetes的数据 backbone,需要做好备份和高可用部署。
-
kube-scheduler:负责Pod的调度,根据资源需求、亲和性规则、污点容忍等策略,将Pod分配到合适的工作节点。
-
kube-controller-manager:运行各种控制器,如Deployment Controller、ReplicaSet Controller、Node Controller等,负责维护集群的期望状态。
工作节点组件:
-
kubelet:节点代理,负责与API Server通信,管理本节点上的Pod生命周期,执行健康检查。
-
kube-proxy:维护节点上的网络规则,实现Service的负载均衡和服务发现。
-
Container Runtime:容器运行时,负责运行容器。Kubernetes支持多种运行时,如containerd、CRI-O、Docker(已弃用,通过containerd兼容)。
4.2 核心资源对象
Kubernetes定义了一系列资源对象来描述应用的部署状态:
Pod:Kubernetes中最小的部署单元,包含一个或多个容器。Pod内的容器共享网络命名空间和存储卷,可以通过localhost互相访问。
Deployment:管理无状态应用的控制器,负责维护Pod的副本数量,支持滚动更新和回滚。Deployment通过ReplicaSet间接管理Pod。
Service:定义一组Pod的访问策略,提供稳定的访问入口。Service通过Label Selector找到对应的Pod,支持ClusterIP、NodePort、LoadBalancer等多种类型。
ConfigMap:存储非敏感的配置数据,可以以环境变量或配置文件的形式挂载到Pod中。
Secret:存储敏感信息(如密码、证书、Token),数据经过Base64编码,使用时需要谨慎处理。
PersistentVolume(PV)与PersistentVolumeClaim(PVC):提供持久化存储能力,将存储资源与应用解耦。
4.3 Kubernetes网络模型
Kubernetes采用扁平的网络模型,要求所有Pod都在同一个扁平的IP地址空间中,可以直接互相通信,无需NAT(网络地址转换)。
🌐 Kubernetes 集群网络
Service ClusterIP
10.96.0.1
Pod 1
10.244.1.2
Pod 2
10.244.1.3
Pod 3
10.244.2.2
Ingress Controller
外部流量
Service类型说明:
| Service类型 | 访问范围 | 使用场景 | 示例 |
|---|---|---|---|
| ClusterIP | 集群内部 | 内部服务通信 | 数据库、缓存服务 |
| NodePort | 集群外部(通过节点端口) | 开发测试环境 | 30000-32767端口 |
| LoadBalancer | 集群外部(通过云负载均衡器) | 生产环境对外服务 | Web应用、API服务 |
| ExternalName | 映射到外部DNS | 访问外部服务 | 外部数据库 |
5. Spring Boot应用容器化
5.1 创建Spring Boot项目
首先,我们创建一个标准的Spring Boot项目。可以使用Spring Initializr(https://start.spring.io)或IDE插件快速生成项目骨架。
项目依赖配置(pom.xml):
xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>demo-application</artifactId>
<version>1.0.0</version>
<name>demo-application</name>
<description>Spring Boot Kubernetes Demo</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
上述Maven配置文件定义了一个标准的Spring Boot Web项目。其中spring-boot-starter-web提供了Web开发所需的所有依赖,包括嵌入式Tomcat、Spring MVC、Jackson等。spring-boot-starter-actuator提供了生产就绪特性,如健康检查、指标收集等,这对于Kubernetes环境至关重要。spring-boot-maven-plugin插件用于打包可执行的JAR文件。
5.2 编写应用主类和控制器
应用主类(Application.java):
java
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
健康检查控制器(HealthController.java):
java
package com.example.demo.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
public class HealthController {
@Value("${spring.application.name:demo-application}")
private String applicationName;
@Value("${app.version:1.0.0}")
private String version;
@GetMapping("/health")
public Map<String, Object> health() {
Map<String, Object> response = new HashMap<>();
response.put("status", "UP");
response.put("application", applicationName);
response.put("version", version);
response.put("timestamp", System.currentTimeMillis());
return response;
}
@GetMapping("/hello")
public String hello() {
return "Hello from " + applicationName + " v" + version;
}
}
上述代码定义了两个简单的REST端点。/health端点返回应用的健康状态信息,包括应用名称、版本和时间戳,这个端点可以用于Kubernetes的健康检查。/hello端点返回一个简单的问候消息,用于验证应用是否正常运行。通过@Value注解,我们从配置文件或环境变量中读取应用名称和版本信息,这样可以实现配置的外置化。
5.3 编写Dockerfile
Dockerfile是构建容器镜像的脚本文件,定义了镜像的构建步骤。对于Spring Boot应用,我们需要编写一个优化的Dockerfile。
多阶段构建Dockerfile:
dockerfile
# ==================== 构建阶段 ====================
FROM eclipse-temurin:17-jdk-alpine AS builder
# 设置工作目录
WORKDIR /build
# 复制Maven配置文件和源代码
COPY pom.xml .
COPY src ./src
# 安装Maven并构建应用
# 使用Alpine的apk包管理器安装Maven
RUN apk add --no-cache maven && \
mvn clean package -DskipTests
# ==================== 运行阶段 ====================
FROM eclipse-temurin:17-jre-alpine
# 创建非root用户运行应用(安全最佳实践)
RUN addgroup -S spring && adduser -S spring -G spring
# 设置工作目录
WORKDIR /app
# 从构建阶段复制JAR文件
COPY --from=builder /build/target/*.jar app.jar
# 更改文件所有者
RUN chown -R spring:spring /app
# 切换到非root用户
USER spring:spring
# 暴露应用端口
EXPOSE 8080
# 设置JVM参数(针对容器环境优化)
ENV JAVA_OPTS="-Xms256m -Xmx512m -XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0"
# 启动应用
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
这个Dockerfile采用了多阶段构建(Multi-stage Build)模式,这是Docker镜像构建的最佳实践。第一阶段(builder)使用JDK镜像编译应用,第二阶段使用更小的JRE镜像运行应用,最终镜像体积大幅减小。我们还创建了非root用户来运行应用,这是容器安全的基本要求。JAVA_OPTS环境变量设置了JVM参数,UseContainerSupport和MaxRAMPercentage参数让JVM能够正确识别容器的资源限制。
5.4 构建和测试容器镜像
构建镜像命令:
bash
# 构建镜像
docker build -t demo-application:1.0.0 .
# 查看镜像大小
docker images demo-application:1.0.0
# 本地运行测试
docker run -d --name demo-app \
-p 8080:8080 \
-e SPRING_PROFILES_ACTIVE=dev \
demo-application:1.0.0
# 测试健康检查端点
curl http://localhost:8080/health
# 查看容器日志
docker logs demo-app
# 停止并删除容器
docker stop demo-app && docker rm demo-app
上述命令演示了Docker镜像的完整生命周期管理。首先使用docker build命令构建镜像,-t参数指定镜像名称和标签。然后使用docker run命令启动容器,-d参数让容器在后台运行,-p参数映射端口,-e参数设置环境变量。最后通过curl命令测试应用是否正常运行。
6. Kubernetes部署配置
6.1 创建命名空间
命名空间(Namespace)是Kubernetes中用于资源隔离的逻辑分区。在生产环境中,通常会为不同的环境(dev、test、prod)或不同的团队创建独立的命名空间。
命名空间定义(namespace.yaml):
yaml
apiVersion: v1
kind: Namespace
metadata:
name: demo-application
labels:
name: demo-application
environment: production
team: backend
这个YAML文件定义了一个名为demo-application的命名空间,并添加了标签用于资源分类和管理。标签(Labels)是Kubernetes中用于组织和选择资源的关键机制。
6.2 创建ConfigMap
ConfigMap用于存储非敏感的配置数据,可以将配置与镜像解耦,实现配置的动态更新。
ConfigMap定义(configmap.yaml):
yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: demo-application-config
namespace: demo-application
data:
# 应用配置
application.yml: |
server:
port: 8080
shutdown: graceful
spring:
application:
name: demo-application
lifecycle:
timeout-per-shutdown-phase: 30s
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
endpoint:
health:
show-details: always
probes:
enabled: true
logging:
level:
root: INFO
com.example: DEBUG
# 环境变量形式
SPRING_APPLICATION_NAME: "demo-application"
APP_VERSION: "1.0.0"
JAVA_OPTS: "-Xms256m -Xmx512m -XX:+UseContainerSupport"
这个ConfigMap包含了两种配置方式:一种是以配置文件形式(application.yml),另一种是以环境变量形式。配置文件方式适合复杂的配置场景,环境变量方式适合简单的键值对配置。注意management.endpoint.health.probes.enabled: true配置,它启用了Kubernetes存活探针和就绪探针的支持。
6.3 创建Secret
Secret用于存储敏感信息,如数据库密码、API密钥等。Secret中的数据需要使用Base64编码。
Secret定义(secret.yaml):
yaml
apiVersion: v1
kind: Secret
metadata:
name: demo-application-secret
namespace: demo-application
type: Opaque
data:
# Base64编码的敏感数据
# 原始值: db_password_123
DB_PASSWORD: ZGJfcGFzc3dvcmRfMTIz
# 原始值: api_key_secret
API_KEY: YXBpX2tleV9zZWNyZXQ=
---
# 也可以使用stringData字段,Kubernetes会自动编码
apiVersion: v1
kind: Secret
metadata:
name: demo-application-secret-v2
namespace: demo-application
type: Opaque
stringData:
DB_USERNAME: "admin"
DB_PASSWORD: "secure_password_here"
上述Secret定义展示了两种方式:data字段需要手动Base64编码,stringData字段可以明文写入,Kubernetes会自动编码。在生产环境中,建议使用密钥管理系统(如Vault、AWS Secrets Manager)来管理敏感信息,而不是直接写入Secret文件。
6.4 创建Deployment
Deployment是管理无状态应用的核心控制器,负责维护Pod的副本数量和滚动更新。
Deployment定义(deployment.yaml):
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-application
namespace: demo-application
labels:
app: demo-application
version: v1
spec:
# 副本数量
replicas: 3
# 选择器,用于关联Pod
selector:
matchLabels:
app: demo-application
# 滚动更新策略
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 滚动更新时最多可以超出期望副本数的数量
maxUnavailable: 0 # 滚动更新时最多不可用的副本数
# Pod模板
template:
metadata:
labels:
app: demo-application
version: v1
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
prometheus.io/path: "/actuator/prometheus"
spec:
# 优雅终止时间
terminationGracePeriodSeconds: 30
# 容器定义
containers:
- name: demo-application
image: demo-application:1.0.0
imagePullPolicy: IfNotPresent
# 端口配置
ports:
- name: http
containerPort: 8080
protocol: TCP
# 环境变量
env:
- name: SPRING_PROFILES_ACTIVE
value: "kubernetes"
- name: JAVA_OPTS
valueFrom:
configMapKeyRef:
name: demo-application-config
key: JAVA_OPTS
# 从ConfigMap挂载配置文件
volumeMounts:
- name: config-volume
mountPath: /config
readOnly: true
# 资源限制
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
# 存活探针 - 检测容器是否存活
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
# 就绪探针 - 检测容器是否准备好接收流量
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
# 启动探针 - 检测应用是否启动完成
startupProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 30 # 最多等待150秒
# 卷定义
volumes:
- name: config-volume
configMap:
name: demo-application-config
items:
- key: application.yml
path: application.yml
这个Deployment配置非常全面,包含了生产环境部署的所有关键配置。replicas: 3确保应用有3个副本,提供高可用性。滚动更新策略设置了maxSurge: 1和maxUnavailable: 0,确保更新过程中服务不中断。资源限制(resources)设置了请求和上限,防止应用占用过多资源。三种探针(liveness、readiness、startup)实现了完善的健康检查机制。ConfigMap以卷的形式挂载到容器中,实现了配置的外置化。
6.5 创建Service
Service为Pod提供稳定的访问入口,实现服务发现和负载均衡。
Service定义(service.yaml):
yaml
apiVersion: v1
kind: Service
metadata:
name: demo-application
namespace: demo-application
labels:
app: demo-application
spec:
type: ClusterIP
selector:
app: demo-application
ports:
- name: http
port: 8080 # Service端口
targetPort: 8080 # Pod端口
protocol: TCP
---
# NodePort类型的服务,用于外部访问(开发测试环境)
apiVersion: v1
kind: Service
metadata:
name: demo-application-nodeport
namespace: demo-application
spec:
type: NodePort
selector:
app: demo-application
ports:
- name: http
port: 8080
targetPort: 8080
nodePort: 30080 # 节点端口(范围:30000-32767)
上述定义创建了两个Service:一个是ClusterIP类型,只能在集群内部访问,适合内部服务通信;另一个是NodePort类型,可以通过任意节点的30080端口从外部访问,适合开发测试环境。在生产环境中,通常会使用Ingress或LoadBalancer类型的Service来暴露服务。
6.6 创建Ingress
Ingress是Kubernetes的API对象,用于管理外部访问集群内服务的HTTP/HTTPS路由。
Ingress定义(ingress.yaml):
yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo-application-ingress
namespace: demo-application
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "10m"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
spec:
ingressClassName: nginx
# TLS配置
tls:
- hosts:
- demo.example.com
secretName: demo-application-tls
# 路由规则
rules:
- host: demo.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: demo-application
port:
number: 8080
这个Ingress配置使用Nginx Ingress Controller作为入口控制器,配置了TLS证书(通过cert-manager自动管理)和路由规则。所有访问demo.example.com的请求都会被路由到demo-application服务的8080端口。annotations字段配置了Nginx特定的行为,如SSL重定向、请求体大小限制等。
7. 部署与验证
7.1 应用部署流程
将Spring Boot应用部署到Kubernetes的完整流程如下:
是
否
编写应用代码
编写Dockerfile
构建容器镜像
推送镜像到仓库
编写K8s资源文件
应用K8s资源
验证部署状态
部署成功?
配置Ingress/负载均衡
排查问题
监控与运维
7.2 执行部署命令
bash
# 1. 创建命名空间
kubectl apply -f namespace.yaml
# 2. 创建ConfigMap和Secret
kubectl apply -f configmap.yaml
kubectl apply -f secret.yaml
# 3. 创建Deployment
kubectl apply -f deployment.yaml
# 4. 创建Service
kubectl apply -f service.yaml
# 5. 创建Ingress(如果需要外部访问)
kubectl apply -f ingress.yaml
# 6. 查看部署状态
kubectl get all -n demo-application
# 7. 查看Pod详情
kubectl describe pod -n demo-application -l app=demo-application
# 8. 查看应用日志
kubectl logs -n demo-application -l app=demo-application -f
# 9. 进入容器调试
kubectl exec -it -n demo-application deployment/demo-application -- /bin/sh
7.3 验证部署结果
检查Pod状态:
bash
# 查看Pod列表
kubectl get pods -n demo-application -o wide
# 预期输出:
# NAME READY STATUS RESTARTS AGE
# demo-application-6b8b9c8d4-abc12 1/1 Running 0 2m
# demo-application-6b8b9c8d4-def34 1/1 Running 0 2m
# demo-application-6b8b9c8d4-ghi56 1/1 Running 0 2m
测试应用访问:
bash
# 端口转发(本地测试)
kubectl port-forward -n demo-application svc/demo-application 8080:8080
# 测试健康检查
curl http://localhost:8080/actuator/health
# 预期输出:
# {
# "status": "UP",
# "groups": ["liveness", "readiness"],
# ...
# }
8. 高级配置与优化
8.1 水平自动扩缩容(HPA)
Kubernetes的Horizontal Pod Autoscaler(HPA)可以根据CPU/内存使用率或自定义指标自动调整Pod副本数量。
HPA定义(hpa.yaml):
yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: demo-application-hpa
namespace: demo-application
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: demo-application
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 10
periodSeconds: 60
scaleUp:
stabilizationWindowSeconds: 60
policies:
- type: Percent
value: 100
periodSeconds: 15
- type: Pods
value: 4
periodSeconds: 15
selectPolicy: Max
这个HPA配置设置了最小2个副本、最大10个副本的弹性伸缩范围。当CPU使用率超过70%或内存使用率超过80%时,HPA会自动增加Pod数量。behavior字段定义了扩缩容的行为策略:缩容时等待300秒的稳定窗口,每次最多减少10%的Pod;扩容时等待60秒的稳定窗口,每次最多增加100%或4个Pod(取较大值)。
8.2 配置管理最佳实践
在Kubernetes环境中管理Spring Boot应用配置,需要遵循以下最佳实践:
| 配置类型 | 推荐方式 | 说明 |
|---|---|---|
| 环境特定配置 | ConfigMap | 不同环境使用不同的ConfigMap |
| 敏感信息 | Secret + 外部密钥管理 | 使用Vault等工具管理敏感信息 |
| 启动参数 | Deployment env | JVM参数、Profile等 |
| 配置热更新 | Spring Cloud Kubernetes | 支持ConfigMap变更自动刷新 |
8.3 日志与监控集成
Prometheus监控集成:
Spring Boot Actuator原生支持Prometheus指标暴露,只需添加依赖并配置:
xml
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
</dependency>
Prometheus ServiceMonitor配置:
yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: demo-application
namespace: demo-application
labels:
release: prometheus
spec:
selector:
matchLabels:
app: demo-application
endpoints:
- port: http
path: /actuator/prometheus
interval: 30s
9. CI/CD流水线集成
9.1 GitOps工作流
GitOps是一种现代化的持续交付方法,以Git仓库作为单一事实来源,通过Git提交触发应用部署。
开发者提交代码
Git仓库
CI流水线构建镜像
推送镜像到仓库
更新GitOps仓库
ArgoCD检测变更
同步到Kubernetes
应用更新完成
9.2 GitHub Actions示例
CI/CD流水线配置(.github/workflows/deploy.yaml):
yaml
name: Build and Deploy
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Build with Maven
run: mvn clean package -DskipTests
- name: Run tests
run: mvn test
- name: Build Docker image
run: |
docker build -t $REGISTRY/$IMAGE_NAME:${{ github.sha }} .
docker tag $REGISTRY/$IMAGE_NAME:${{ github.sha }} $REGISTRY/$IMAGE_NAME:latest
- name: Login to Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Push Docker image
run: |
docker push $REGISTRY/$IMAGE_NAME:${{ github.sha }}
docker push $REGISTRY/$IMAGE_NAME:latest
deploy:
needs: build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- name: Set up kubectl
uses: azure/setup-kubectl@v3
- name: Configure kubeconfig
run: |
mkdir -p ~/.kube
echo "${{ secrets.KUBE_CONFIG }}" | base64 -d > ~/.kube/config
- name: Deploy to Kubernetes
run: |
kubectl set image deployment/demo-application \
demo-application=$REGISTRY/$IMAGE_NAME:${{ github.sha }} \
-n demo-application
- name: Wait for rollout
run: |
kubectl rollout status deployment/demo-application \
-n demo-application --timeout=300s
这个GitHub Actions工作流实现了完整的CI/CD流程:代码提交后自动构建、测试、打包Docker镜像、推送到镜像仓库,然后更新Kubernetes部署。kubectl set image命令触发滚动更新,kubectl rollout status等待更新完成。
10. 常见问题与解决方案
10.1 应用启动失败
问题现象 :Pod状态为CrashLoopBackOff或Error。
排查步骤:
bash
# 查看Pod事件
kubectl describe pod <pod-name> -n demo-application
# 查看容器日志
kubectl logs <pod-name> -n demo-application --previous
# 检查资源限制
kubectl get pod <pod-name> -n demo-application -o yaml | grep -A 10 resources
常见原因与解决方案:
| 原因 | 解决方案 |
|---|---|
| 内存不足 | 增加resources.limits.memory |
| 健康检查失败 | 调整探针的initialDelaySeconds |
| 配置错误 | 检查ConfigMap和Secret配置 |
| 端口冲突 | 确认containerPort配置正确 |
10.2 服务无法访问
问题现象:Service创建成功,但无法访问应用。
排查步骤:
bash
# 检查Service端点
kubectl get endpoints -n demo-application
# 检查Pod标签
kubectl get pods -n demo-application --show-labels
# 测试Service DNS解析
kubectl run test --rm -it --image=busybox -- nslookup demo-application.demo-application.svc.cluster.local
常见原因:Service的selector与Pod标签不匹配是最常见的原因。确保Deployment中Pod模板的labels与Service的selector.matchLabels完全一致。
10.3 配置更新不生效
问题现象:修改ConfigMap后,应用配置未更新。
解决方案:
Spring Boot默认不会自动重新加载配置。有以下几种解决方案:
-
重启Pod:修改ConfigMap后手动重启Deployment
bashkubectl rollout restart deployment/demo-application -n demo-application -
使用Spring Cloud Kubernetes:添加依赖实现配置热更新
xml<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-kubernetes-fabric8-config</artifactId> </dependency> -
使用ConfigMap版本控制:在ConfigMap名称中包含版本号,更新时修改Deployment引用
11. 总结
本文详细介绍了将Spring Boot应用迁移至Kubernetes云原生环境的完整过程,从云原生概念、Spring Boot框架特性、Kubernetes核心概念,到容器化实践、部署配置、CI/CD集成,覆盖了云原生迁移的方方面面。
核心要点总结:
-
容器化是基础:使用多阶段构建Dockerfile,优化镜像体积,确保安全(非root用户运行)。
-
配置外置化:使用ConfigMap和Secret管理配置,实现配置与镜像解耦,便于环境迁移。
-
健康检查必不可少:配置存活探针、就绪探针和启动探针,确保Kubernetes能够正确管理应用生命周期。
-
资源限制要合理:设置合适的resources.requests和resources.limits,防止资源争抢和浪费。
-
弹性伸缩提升可用性:配置HPA实现自动扩缩容,应对流量波动。
-
CI/CD自动化部署:建立GitOps工作流,实现代码到生产的自动化交付。
思考题:
-
在你的项目中,哪些Spring Boot应用适合迁移到Kubernetes?哪些应用可能不适合?
-
如何设计一个支持蓝绿发布和金丝雀发布的Kubernetes部署方案?
-
对于有状态应用(如数据库、消息队列),在Kubernetes中部署需要注意哪些问题?