【Kubernetes】入门-部署Spring应用

Kubernetes

基本概念

Pod

是什么: Kubernetes 中最小的、最简单的部署和管理单元。

类比: 一台"逻辑主机"或一个"虚拟机实例"。

关键点

  • 一个 Pod 可以包含一个或多个紧密相关的容器(例如,一个应用容器和一个日志收集 sidecar 容器)。
  • 这些容器共享网络命名空间(拥有相同的 IP 地址和端口空间)、存储卷和其他资源。
  • Pod 是短暂的,会被频繁地创建和销毁

Deployment

是什么: 用于部署和管理 Pod 副本集的声明式定义。

解决的问题: 如何确保指定数量的、完全相同的 Pod 副本始终在运行?如何无缝更新应用(滚动更新)?如何在更新出问题时快速回滚?

关键点

  • 你定义一个"期望状态"(例如,需要运行 3 个 Nginx Pod),Deployment 控制器会确保实际状态始终匹配这个期望状态。

  • 它是实现无状态应用部署的首选控制器。

Service

是什么: 一个稳定的网络端点,用于访问一组 Pod。

解决的问题: Pod 是短暂的,IP 地址会变。客户端如何稳定地找到并访问这些动态变化的 Pod?

关键点

  • Service 提供一个固定的 虚拟 IP (ClusterIP) 和 DNS 名称。

  • 通过 标签选择器 (Label Selector) 来匹配一组 Pod,并将流量负载均衡到这些 Pod 上。

  • 常见的类型:

    • ClusterIP: 默认类型,仅在集群内部可访问。

    • NodePort: 在每个节点上开放一个静态端口,从而可以从集群外部访问。

    • LoadBalancer: 使用云提供商的负载均衡器,向外部公开服务

Volume (存储卷)

是什么: 允许 Pod 中的容器持久化存储数据。

解决的问题: 容器内部的文件系统是临时的,容器重启后数据会丢失。如何持久化保存数据(如数据库文件、日志)?

关键点

  • 存储卷的生命周期独立于 Pod。即使 Pod 被销毁,存储卷中的数据依然存在。

  • 支持多种后端存储类型:本地存储、云存储(如 AWS EBS、GCE PD)、NFS、分布式存储(如 Ceph)等。

Namespace (命名空间)

是什么: 在物理集群内部创建的虚拟集群,用于实现资源隔离和分组。

解决的问题: 在有多个团队或项目的大型集群中,如何避免资源(如 Pod、Service 名称)冲突?如何实现资源配额管理?

关键点

  • 默认有 default, kube-system (系统组件), kube-public 等命名空间。

  • 可以为每个命名空间设置资源配额,限制其能使用的 CPU、内存等资源总量。

ConfigMap & Secret

  • ConfigMap: 用于将非机密的配置数据(如配置文件、环境变量、命令行参数)与容器镜像解耦。让你可以不重写镜像就能改变应用配置。

  • Secret: 与 ConfigMap 类似,但专门用于存储敏感信息,如密码、OAuth 令牌、SSH 密钥。数据会以 Base64 编码(非加密,需额外措施保障安全)存储。

使用K8S部署Spring Boot应用

前置条件,docker和kubernetes已安装配置

参考:macOS上优雅运行Docker容器

准备一个Spring Boot应用

SpringK8sDemoApplication

java 复制代码
@SpringBootApplication
@RestController
public class SpringK8sDemoApplication {

	private static Date firstTime;
	private static SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

	public static void main(String[] args) {
		SpringApplication.run(SpringK8sDemoApplication.class, args);
	}

	@GetMapping("/")
	public String hello() {
		if (firstTime == null) {
			firstTime = new Date();
		}
		// 容器里看日志是否有负载均衡
		System.out.println("request in " + formatter.format(new Date()));
		return "Hello from Spring Boot on Kubernetes! first time: " + formatter.format(firstTime);
	}

	@GetMapping("/health")
	public String health() {
		return "OK";
	}
}

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.5.7</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>spring-k8s-demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>spring-k8s-demo</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>21</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</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>
			</plugin>
		</plugins>
	</build>
</project>

构建 Docker 镜像

Dockerfile

sh 复制代码
FROM eclipse-temurin:21-jre-alpine AS runtime

# 创建应用目录
WORKDIR /app

# 复制jar文件
COPY target/spring-k8s-demo-0.0.1-SNAPSHOT.jar app.jar

# 暴露端口
EXPOSE 8080

# 启动应用
ENTRYPOINT ["java", "-jar", "app.jar"]

build.sh

sh 复制代码
# 切换指定JDK版本(可选)
export JAVA_HOME=`/usr/libexec/java_home -v 21`

# 可替换mvn
mvnd clean package -DskipTests

# 构建镜像
docker build -t spring-k8s-demo:latest .

编写 k8s Deployment 文件

k8s-deployment.yaml

yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: spring-app
spec:
  replicas: 2  # 运行 2 个 Pod 副本
  selector:
    matchLabels:
      app: spring-app
  template:
    metadata:
      labels:
        app: spring-app
    spec:
      containers:
      - name: spring-app
        image: spring-k8s-demo:latest
        ports:
        - containerPort: 8080   # 容器内暴露的端口
        livenessProbe:          # 存活探针
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 300
          periodSeconds: 10
        readinessProbe:         # 就绪探针
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 300
          periodSeconds: 10
        resources:              # 分配资源
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"

k8s-services.yaml

yaml 复制代码
# service.yaml
apiVersion: v1
kind: Service
metadata:
  name: sprint-service
  labels:
    app: sprint-service
spec:
  type: NodePort
  selector:
    app: spring-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
      nodePort: 30080

配置文件解释

  • Deployment:

    • replicas: 2:确保任何时候都有 2 个 Pod 在运行。
    • selector & labels:Deployment 通过 app: spring-app 这个标签来管理它创建的 Pod。
    • image:指定从哪个镜像运行容器。
    • resources:为容器设置 CPU 和内存的资源请求与限制,这是生产环境的最佳实践。
  • Service:

    • type: NodePort: 在每个节点上开放一个静态端口,从而可以从集群外部访问
    • selector: app: spring-app:Service 通过这个标签找到要代理的 Pod。
    • ports:将 Service 的 80 端口流量转发到 Pod 的 8080 端口。

部署到集群

应用配置

sh 复制代码
kubectl apply -f k8s-deployment.yaml
kubectl apply -f k8s-services.yaml

测试

  1. 查看pod状态
sh 复制代码
kubectl get pods

Pod 状态变为 Running

  1. 查看Deployment状态
sh 复制代码
kubectl get deployment
  1. 查看 Service
sh 复制代码
kubectl get service
  1. curl
sh 复制代码
curl http://192.168.64.3:30080/

根据时间,可以看到每次轮询到不同pod,也就是不同容器

注意:因为我使用是colima所以需要使用colima list命令查出来IP是192.168.64.3

k8s 常用命令

sh 复制代码
# 查看所有节点
kubectl get nodes

# 查看节点详情
kubectl describe node <node-name>

# 查看Pod
kubectl get pods

# 查看Pod详情
kubectl describe pod <pod-name>

# 查看Pod日志
kubectl logs <pod-name> -n <namespace>

# 查看单个 Pod 的日志
kubectl logs <pod-name>

# 查看部署
kubectl get deployments

# 查看部署详情
kubectl describe deployment <deployment-name> 

# 查看由 Deployment 创建的所有 Pod 的日志
kubectl logs -l app=spring-app

# 转发端口(用于本地测试)
kubectl port-forward svc/sprint-service 8080:80

# 水平扩缩容(将副本数从 2 增加到 3)
kubectl scale deployment spring-app --replicas=3

# 查看部署历史
kubectl rollout history deployment/<deployment-name>

# 滚动更新(例如,更新到新版本的镜像)
kubectl set image deployment/spring-app java-app=spring-k8s-demo:2.0.0

# 回滚到上一个版本
kubectl rollout undo deployment/<deployment-name>

# 删除部署
kubectl delete -f k8s-deployment.yaml
kubectl delete -f k8s-services.yaml

引用

https://github.com/WilsonPan/java-developer

例子: https://github.com/WilsonPan/java-developer/tree/main/samples/spring-demo

相关推荐
谅望者3 天前
Linux文件查看命令完全指南:cat、less、head、tail、grep使用详解
linux·excel·less·shell·文件操作·命令行·系统运维
IT小哥哥呀14 天前
5 个 Windows 故障排除工具
windows·故障排除·系统运维·windows系统·电脑问题
WilsonPan1 个月前
macOS上优雅运行Docker容器
系统运维
Johny_Zhao2 个月前
达梦数据库高可用集群部署方案
linux·mysql·网络安全·docker·信息安全·kubernetes·云计算·shell·containerd·达梦数据库·yum源·系统运维·centos8
Johny_Zhao2 个月前
Conda、Anaconda、Miniconda对比分析
linux·网络安全·信息安全·kubernetes·云计算·conda·shell·containerd·anaconda·yum源·系统运维·miniconda
Johny_Zhao2 个月前
Linux防止rm误操作防护方案
linux·网络·人工智能·网络安全·信息安全·云计算·yum源·系统运维
Johny_Zhao3 个月前
基于 Docker 的 LLaMA-Factory 全流程部署指南
linux·网络·网络安全·信息安全·kubernetes·云计算·containerd·yum源·系统运维·llama-factory
Johny_Zhao3 个月前
Rsync + Sersync 实时数据同步方案
linux·网络安全·信息安全·云计算·rsync·系统运维·sersync
Johny_Zhao3 个月前
SeaTunnel的搭建部署以及测试
linux·网络·网络安全·信息安全·kubernetes·云计算·containerd·devops·seatunnel·系统运维