【Kubernetes】入门-部署Spring应用

news/2025/11/6 0:03:07/文章来源:https://www.cnblogs.com/WilsonPan/p/19194963

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

@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 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

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

# 切换指定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

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

k8s-services.yaml

# service.yaml
apiVersion: v1
kind: Service
metadata:name: sprint-servicelabels:app: sprint-service
spec:type: NodePortselector:app: spring-appports:- protocol: TCPport: 80targetPort: 8080nodePort: 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 端口。

部署到集群

应用配置

kubectl apply -f k8s-deployment.yaml
kubectl apply -f k8s-services.yaml

测试

  1. 查看pod状态
kubectl get pods

Pod 状态变为 Running

  1. 查看Deployment状态
kubectl get deployment
  1. 查看 Service
kubectl get service
  1. curl
curl http://192.168.64.3:30080/

test curl

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

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

k8s 常用命令

# 查看所有节点
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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/957234.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第16天(简单题中等题 二分查找)

打卡第十六天 4道简单题+1道中等题 耗时≈一小时 明天继续

Java项目常用异常处理场景与实战指南

在Java开发中,异常处理直接决定了系统的健壮性和可维护性。不合理的处理方式可能导致系统崩溃、数据丢失或调试困难,而规范的处理能让系统在异常场景下优雅降级。本文结合实际项目经验,梳理高频异常场景及解决方案,…

newDay18

1.今天主要是背背单词,把作业写了一部分 2.明天把不会的东西补补 3.没啥问题

11月5日

上午离散和马原 下午学四级

层级结构

层级结构import json from collections import defaultdict from typing import List, Dict, Any, Optional from docx import Documentfrom llama_index.core.schema import Document as LlamaDocument, TextNode fro…

2025.11.5总结 - A

今天上了离散数学和马原,感觉良好,加油

C# POST Form

public string HttpPostForm(string url,Dictionary<string,string> _form,string _filepath="") {try{var formData = new MultipartFormDataContent();_form.Cast<KeyValuePair<string, strin…

C++练习2

选择题部分

买完学习机还需要去线下补课吗? AI 学习机 + 自习室是最优解!

当孩子成绩不理想时,单一依赖 AI 学习机常陷入 “诊断不深、练习盲目、缺乏监督” 的困境 —— 而 2025 年异军突起的黑马品牌松鼠 AI,凭借 “AI 学习机 + 全国自习室” 双线矩阵,打破这一局限,成为成绩差孩子的提…

一次性删除所有的GitHub Action记录

一键脚本 gxxxxVP是GitHub TOKEN PAGE=1 while true; do# 获取当前页面的数据RESPONSE=$(curl -H "Authorization: token gxxxxVP" \"https://api.github.com/repos/kitcoun/OCI-Auto-Manager/actions/…

第三十四篇

今天是11月5号,上了离散和马原

2025-11-05 PQ v.Next日志记录

项目核心信息目前初步预计在这里进行开发测试(后续到develop): https://z.gitee.cn/zgca/projects/777586/repos/zgca/aipq/tree/feature%2Fteacher_feel今日进度(4*6): 当前任务:全员微信开发能力培训最初计划…

11月5日日记

1.今天学习离散数学和马哲 2.明天篮球课比赛 3.Servlet 与 JSP 页面如何实现数据高效传递?

20232319 2024-2025-1 《网络与系统攻防技术》实验四实验报告

1.实验内容1.恶意代码文件类型标识、脱壳与字符串提取 2.使用IDA Pro静态或动态分析crackme1.exe与crakeme2.exe,寻找特定输入,使其能够输出成功信息。 3.分析一个自制恶意代码样本rada,并撰写报告,回答以下问题:…

汉字识别

点击查看代码 import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim from torch.utils.data import Dataset, DataLoader import numpy as np from PIL import Image, Im…

AGC与AVC是什么

定义AGC:自动发电控制 功能:实时调节有功功率,将电网频率控制在50HZ 电网频率的高低由“有功功率”决定 有功多了,频率升高。AVC : 自动电压控制 功能:调节无功补偿设备,将电网电压在额定值5% 内 电网电压高低由…

链表1

链表1线性表的链式表示与实现1 基本概念 线性表的链式表示又称为非顺序映像或链式映像 特点链表中元素的逻辑次序和物理次序不一定相同链表中的存储单元既可以是连续的,也可以是不连续的,甚至是零散分布在内存中的任…

競プロ典型 90 問-难题

005倍增优化dp 题目大意(自己总结 只用数字 c1​,c2​,…,cK​ 可以构造出多少个 N 位正整数是 B 的倍数? 求除以 109+7 的余数。$1 \leq K \leq 9$ $1 \leq c_1 \lt c_2 \lt \cdots \lt c_K \leq 9$ $1 \leq N \leq…

c++函数调用的大致工作过程

c++函数调用的大致工作过程在C++中,函数调用是一个基本的编程概念,它允许我们将一组语句封装成一个独立的模块,以便重复使用或提高代码的可读性和可维护性。函数调用的工作过程可以分为以下几个步骤: 1、函数声明(…