当前位置: 首页 > news >正文

SpringBoot应用:Docker与Kubernetes全栈实战秘籍

文章目录

    • 什么是docker?
    • 为什么要用docker?
    • docker有什么?
    • 什么是Kubernetes?
    • 怎么安装docker
      • 第一步,下载安装包
      • 第二步,准备环境
      • 第三步,安装
      • 第四步,注册账号
      • 第五步,验证是否可以使用
      • 第六步,配置国内镜像源
    • 怎么安装Kubernetes?
      • 第一步,找到对应的版本
      • 第二步,下载k8s
      • 第三步,安装Kubernetes
    • 安装kubectl
      • 直接下载:
      • 使用 curl:
    • 编写web应用
      • 第一步,新建一个springboot项目
      • 第二步,申请api-key
      • 第三步,编写yml配置文件
      • 第四步,新建一个web控制层
      • 第五步,新建service
      • 第六步,新建前端页面
      • 第七步,访问web页面
    • 部署到docker
      • 第一步,编写Dockerfile文件
      • 第二步,打包jar包
      • 第三步,构建镜像
      • 第四步,启动镜像
    • 部署Kubernetes
      • `deployment.yaml`
      • `service.yaml`
      • 第一步,编写deployment.yaml
      • 第二步,编写service.yaml
      • 第三步,构建pod
      • 第四步,验证
    • 总结

什么是docker?

首先,咱们得了解一下什么是docker。它其实就是一种开源的平台,用来自动部署、管理、扩展和运行各种应用程序的技术。它允许开发人员把他们编写的应用程序和相关的依赖库,全都封装到一个叫做"容器"的小家伙里面,然后就能在任何只要装了Docker的环境里跑这个应用!Docker有很多牛逼的功能,例如流畅的跨平台兼容性、严格的资源隔离、精确的版本控制以及超高的资源利用率等等!

为什么要用docker?

接下来,科普一些Docker的背景知识,首先,docker之所以能诞生,主要是因为传统的应用部署方式面临着以下几个难题:

  1. 旧有的应用部署手段:时间回到Docker刚刚面世的那会儿,应用程序的部署往往依赖于特定的操作系统环境配置和依赖项。然而,这种依赖性容易引发各种不统一的问题,无论是开发环境和生产环境之间的差异,还是依赖项之间的冲突,都可能造成应用程序在别的环境下“水土不服”,无法好好运转。
  2. 传统虚拟化技术的短板:以前我们常用的虚拟化技术,比如说VMWare或者VirtualBox,虽然能在一台物理机器上跑出好几个虚拟机,每个虚拟机都有自己独立的操作系统。但是,虚拟机通常比较重,启动和运行都要消耗大量的资源,导致性能损耗严重。
  3. 微服务架构的崛起:近年来,微服务架构逐渐成为了主流,应用程序被拆分成了许多个独立的小服务。而这些小服务则需要在各种各样的环境中快速进行部署和伸缩。如果还是采用传统的部署方式,就很难满足微服务灵活性和扩展性的要求了。

docker有什么?

c577dba308a089274cd99ba773f11054

图片来自csdn@小生凡一

镜像就像是一个应用程序的“模板”。它包含了运行应用所需的一切,比如操作系统、库和应用代码。你可以把它想象成一个打包好的应用快照,随时可以用来创建容器。

容器是镜像的实际运行实例。你可以把它当成是根据模板(镜像)生产出来的一个具体的产品。容器是轻量级的,启动速度快,而且每个容器都有自己独立的运行环境。比如,你可以用同一个镜像启动多个容器,每个容器里跑的应用都是独立的。

仓库是用来存储和共享镜像的地方。你可以把它理解为一个镜像的“库”,在这里你可以找到别人上传的镜像,也可以把自己创建的镜像上传到这里。Docker Hub 是最常用的公共仓库,但你也可以设置自己的私有仓库。

什么是Kubernetes?

Kubernetes(简称 K8s)是一个开源的容器编排系统,用于自动化容器化应用程序的部署、扩展和管理。Kubernetes 提供了一种声明式的配置模型,使得用户可以定义应用程序的期望状态,Kubernetes 会自动确保系统始终处于该状态。

Docker 负责创建和管理容器,Kubernetes 负责管理和调度这些容器,他们的关系犹如这样:

Kubernetes

例如在java微服务的开发过程中,我们要新增这个微服务的节点,如果没用docker,我们是不是要把jar包上传到服务器,然后再把它启动起来,一套流程下来很麻烦,但是你用了docker配合k8s之后,你只需要点一个加号键,就新增了一个节点(pod),点两次就新增了两个,就像这样:

f510fd3944ba4bb6945a90dbda53d124

怎么安装docker

第一步,下载安装包

在Windows中docker有个桌面程序叫做Docker Desktop,这个是在mac和Windows上面独有的程序,在Linux上面是没有的,所以我们点击下载之后,我们会得到一个exe安装包

官网地址https://www.docker.com/

第二步,准备环境

先打开两个设置,控制面板》程序》启用或关闭windows功能》图中倒数第二和第三个点击勾选》重启电脑即可。
ac6c3d951e4f4fa9a7c49830a39e3da7
到本文发布截止时间,官网的exe包是4.33.1的版本,如果你的电脑太老了,这个时候就会出现下面的情况,这个时候我们需要安装4.24.1以下的版本。

877b79065e5b464c861ea23fc9248790
这里我们选的是4.24.0版本的

第三步,安装

一路狂点下一步,页面叫我们注销一下以启用docker,我们按照他的提示执行就行了

第四步,注册账号

上面我们安装完成并且重启之后,进入这个软件,他会让我们注册一个账户,如果我们没有就可以先跳过这个环境以后注册也是可以的

注册这个账号的目的就是可以推送你自己的镜像到docker的中央仓库(和maven的中央仓库差不多),如果后面我们需要注册一个账号的话,点击右上角的sign in浏览器自动就会跳出页面,如果我们需要注册我们就点击sign up,之后会让我们输入邮箱,用户名和密码

第五步,验证是否可以使用

登录/跳过登录之后 这个时候我们看左下角显示的是engine running,意思就是docker以及启动起来了
之后我们用cmd运行docker images命令,出现下面的情况就算成功安装了
a91e0998b70b4177a3fa3f4b3ad5c9f6

第六步,配置国内镜像源

docker的默认仓库也是在国外,所以国内有时候甚至经常pull拉不了镜像,就像github一样,所以我们需要配置国内的镜像库,但是前段时候听说docker镜像很多不能用了,但是博主还是找了一个目前可以用的镜像库,有可能以后要经常换,这个是暂时没有办法的
在docker右上角的设置里面选择docker engine(释义:引擎,发动机;机车,火车头;工具),加入蓝色框框框住的文字,下面已贴出
3941e087b57843799ef24ed5c2c2586a

	,"registry-mirrors": ["https://docker.m.daocloud.io"]

注意有个逗号,之后右下角的 Apply & restart 就会亮起,我们点击等他重启即可,之后我们cmd 输入docker info就会出现我们刚刚配置的镜像。

怎么安装Kubernetes?

第一步,找到对应的版本

image-20241124142002624

第二步,下载k8s

image-20241124142036752

https://github.com/AliyunContainerService/k8s-for-docker-desktop

选择好对应的版本分支,进行源码下载,解压好之后你会得到这样的一个文件夹

image-20241124142216510

第三步,安装Kubernetes

以管理员身份运行” 的 PowerShell 中执行 Set-ExecutionPolicy RemoteSigned 命令。

在Windows上,使用 PowerShell执行

 .\load_images.ps1

执行完成之后打开docker desktop,选择图中所选的,然后重启docker desktop 等待即可。安装启动完成后,即可在左下角看到docker engine 和 Kubernetes 是蓝色的运行标志

image-20241124142613104

安装kubectl

kubectl 是 Kubernetes 的命令行工具,用于与 Kubernetes API 服务器进行交互。通过 kubectl,用户可以执行各种操作,如创建、查看、更新和删除 Kubernetes 资源。

按照道理来说,Windows 版的 Docker Desktop 有自带版本的 kubectl ,但是如果你在cmd命令行执行下面命令,没有信息打印出来可以安装一下

kubectl version --client

直接下载:

通过访问 Kubernetes 发布页面 直接下载你对应的k8s版本。 请务必选择适用于你的体系结构的二进制文件(例如,amd64、arm64 等)。Windows下载exe,一路安装即可

使用 curl:

如果你已安装 curl,可以使用以下命令:

curl.exe -LO "https://dl.k8s.io/release/v1.29.2/bin/windows/am

编写web应用

我们这里编写一个简单的web应用(AI对话,一问一答),最终的效果是前端可以直接访问,并且可以通过页面输出你的问题

msedge_5TLY4MyPQF

第一步,新建一个springboot项目

SpringBoot入门:如何新建SpringBoot项目(保姆级教程)

我们的pom文件为:

<?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"><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.12</version><relativePath/> <!-- lookup parent from repository --></parent><modelVersion>4.0.0</modelVersion><groupId>com.masiyi</groupId><artifactId>spring-ai</artifactId><version>0.0.1-SNAPSHOT</version><name>spring-ai</name><description>spring-ai</description><properties><java.version>23</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><spring-boot.version>2.7.12</spring-boot.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-ai</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-webflux</artifactId></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>2023.0.1.2</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.1</version><configuration><source>17</source><target>17</target><encoding>UTF-8</encoding></configuration></plugin></plugins></build><repositories><repository><id>spring-milestones</id><name>Spring Milestones</name><url>https://repo.spring.io/milestone</url><snapshots><enabled>false</enabled></snapshots></repository><repository><id>spring-snapshots</id><name>Spring Snapshots</name><url>https://repo.spring.io/snapshot</url><releases><enabled>false</enabled></releases></repository></repositories>
</project>

如果不配置仓库地址,则会出现包拉不下来的情况,如果jdk版本不对也会出现编译不了的情况,这个pom里面我们使用的jdk编译版本为17版本,但是spring-cloud-starter-alibaba-ai的jdk编译版本为17,所以我们使用比17高的jdk版本就行了

第二步,申请api-key

阿里的apikey是需要付费的,所以我们通过https://bailian.console.aliyun.com/
购买对应的服务之后就可以申请我们的api-key

image-20240920102559875

第三步,编写yml配置文件

server:port: 8999spring:application:name: tongyi-examplecloud:ai:tongyi:connection:api-key:  sk-6670e214d0414bdbad173b7xxxx

我们按照上面配置好,如果是2023.0.1.2版本就按照上面写,官网的文档估计没有更新到最新版本,这部分还是作者看源码才知道要这么配置的。

配置好之后我们就可以来上手spring-cloud-starter-alibaba-ai了

第四步,新建一个web控制层

package com.masiyi.springai.controller;/** Copyright 2023-2024 the original author or authors.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      https://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/import com.masiyi.springai.service.TongYiService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;import java.time.Duration;
import java.time.LocalTime;
import java.util.Map;/*** TongYi models Spring Cloud Alibaba Controller.** @author yuluo* @author <a href="mailto:yuluo08290126@gmail.com">yuluo</a>* @since 2023.0.0.0*/@RestController
@RequestMapping("/ai")
@CrossOrigin
public class TongYiController {@Autowired@Qualifier("tongYiSimpleServiceImpl")private TongYiService tongYiSimpleService;@GetMapping("/example")public String completion(@RequestParam(value = "message", defaultValue = "Tell me a joke")String message) {return tongYiSimpleService.completion(message);}@GetMapping("/stream")public Map<String, String> streamCompletion(@RequestParam(value = "message", defaultValue = "请告诉我西红柿炖牛腩怎么做?")String message) {return tongYiSimpleService.streamCompletion(message);}@PostMapping(value = "/flux-demo", produces = "text/event-stream; charset=utf-8")public Flux<ServerSentEvent> hello(@RequestParam(name = "name", defaultValue = "unknown user") String name) {return Flux.interval(Duration.ofSeconds(1))  // 每隔一秒发送一个事件.take(10)  // 限制发送 10 次.map(seq -> {String message = String.format("Hello %s, here is your message #%d at %s",name, seq + 1, LocalTime.now());return ServerSentEvent.<String>builder().id(String.valueOf(seq)) // 设置事件 ID.event("chat-message")  // 自定义事件名称.data(message)          // 传递的消息数据.build();});}@PostMapping(value = "/flux", produces = "text/event-stream; charset=utf-8")public Flux<ServerSentEvent> flux(@RequestParam(name = "message", defaultValue = "你好") String message) {return tongYiSimpleService.flux(message);}}

这里面的有两个方法,一个是返回一个字符串,一个是返回一个steam流,但是官网的写法后面还需要改造一下,这里留个坑,就不做研究。

第五步,新建service

package com.masiyi.springai.service.impl;/** Copyright 2023-2024 the original author or authors.** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at**      https://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/import com.alibaba.cloud.ai.tongyi.chat.TongYiChatOptions;
import com.masiyi.springai.service.AbstractTongYiServiceImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.StreamingChatModel;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;import java.util.Map;/*** The Chat simple example service implementation.* There is optional message parameter whose default value is "Tell me a joke".* pl The response to the request is from the TongYi models Service.** @author yuluo* @author <a href="mailto:yuluo08290126@gmail.com">yuluo</a>* @since 2023.0.0.0*/@Service
public class TongYiSimpleServiceImpl extends AbstractTongYiServiceImpl {private static final Logger logger = LoggerFactory.getLogger(TongYiSimpleServiceImpl.class);private final ChatModel chatModel;private final StreamingChatModel streamingChatModel;@Autowiredpublic TongYiSimpleServiceImpl(ChatModel chatModel, StreamingChatModel streamingChatModel) {this.chatModel = chatModel;this.streamingChatModel = streamingChatModel;}@Overridepublic String completion(String message) {Prompt prompt = new Prompt(new UserMessage(message));return chatModel.call(prompt).getResult().getOutput().getContent();}@Overridepublic Map<String, String> streamCompletion(String message) {StringBuilder fullContent = new StringBuilder();streamingChatModel.stream(new Prompt(message)).flatMap(chatResponse -> Flux.fromIterable(chatResponse.getResults())).map(content -> content.getOutput().getContent()).doOnNext(fullContent::append).last().map(lastContent -> Map.of(message, fullContent.toString())).block();logger.info(fullContent.toString());return Map.of(message, fullContent.toString());}@Overridepublic Flux<ServerSentEvent> flux(String message) {TongYiChatOptions chatOptions = new TongYiChatOptions();chatOptions.setIncrementalOutput(true);Flux<ServerSentEvent> streamEvents = streamingChatModel.stream(new Prompt(message, chatOptions)).map(outputContent -> {String content = outputContent.getResult().getOutput().getContent();System.out.println(content);return ServerSentEvent.builder().event("message").data(content).build();});// 返回 Flux<ServerSentEvent>return streamEvents;}
}

第六步,新建前端页面

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Chat SSE Demo</title>
</head>
<body><h1>Server-Sent Events with POST</h1><div id="messages"></div><script>// 获取 URL 中的查询参数function getQueryParam(param) {const urlParams = new URLSearchParams(window.location.search);return urlParams.get(param);}function startSSE() {const url = 'http://localhost:8999/ai/flux'; // 后端服务器的完整 URLconst message = getQueryParam('message') || ''; // 获取查询参数中的 'message' 值if (!message) {displayMessage('No message provided in the URL');return;}fetch(url, {method: 'POST',headers: {'Content-Type': 'application/x-www-form-urlencoded','Accept': 'text/event-stream' // 接受 SSE 类型的数据流},body: new URLSearchParams({'message': message})}).then(response => {if (!response.ok) {throw new Error('Network response was not ok');}const reader = response.body.getReader();const decoder = new TextDecoder();let buffer = ''; // 用于缓存不完整的数据let accumulatedData = ''; // 用于累计所有 data 内容return new ReadableStream({start(controller) {function read() {reader.read().then(({ done, value }) => {if (done) {controller.close();return;}buffer += decoder.decode(value, { stream: true });// 检查是否有完整的事件块(每个事件块之间有两个换行符)const eventBlocks = buffer.split("\n\n");// 将最后一个块留在缓存里,可能是不完整的buffer = eventBlocks.pop();eventBlocks.forEach(eventBlock => {const lines = eventBlock.split("\n");let eventData = { data: '' };lines.forEach(line => {if (line.startsWith("data:")) {// 累加所有的 data 行,不插入换行符eventData.data += line.substring(5).trim();}});// 仅当有数据时才显示if (eventData.data) {accumulatedData += eventData.data; // 累加数据displayMessage(accumulatedData); // 显示完整数据}});read();});}read();}});}).catch(error => {console.error('There has been a problem with your fetch operation:', error);});}function displayMessage(message) {const messageDiv = document.getElementById('messages');messageDiv.innerHTML = ''; // 清空之前的内容const newMessage = document.createElement('p');newMessage.innerHTML = message; // 显示累计后的数据messageDiv.appendChild(newMessage);}// 开始 SSE 连接startSSE();
</script></body>
</html>

在resource的static下面新建index2.html 文件,内容如上

第七步,访问web页面

http://localhost:8999/index2.html?message=你好,介绍一下你自己

msedge_5TLY4MyPQF

这样,我们的web应用就写好了

部署到docker

第一步,编写Dockerfile文件

FROM openjdk:22-slim
COPY spring-ai-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
  1. FROM openjdk:22-slim
    • 这一行指定了基础镜像。openjdk:22-slim 是一个基于 Debian 的轻量级镜像,包含了 OpenJDK 22。slim 版本比标准版本更小,适合生产环境使用。FROM 里面的jdk版本比项目中的大就行了(项目中17)
  2. COPY spring-ai-0.0.1-SNAPSHOT.jar app.jar
    • 这一行将本地文件系统中的 spring-ai-0.0.1-SNAPSHOT.jar 文件复制到 Docker 镜像的根目录下,并重命名为 app.jar
  3. ENTRYPOINT [“java”,“-jar”,“/app.jar”]
    • 这一行设置了容器启动时的默认命令。["java", "-jar", "/app.jar"] 表示使用 Java 运行 /app.jar 文件。ENTRYPOINT 指令确保即使在命令行中传递其他参数,这些参数也会作为参数传递给 java -jar /app.jar

第二步,打包jar包

直接上手就是一个 mvn clean package,然后将打出来的jar放到和Dockerfile 同目录下面,就像这样

image-20241124145328787

第三步,构建镜像

docker build -t aijava:1.0 .    

当你运行上述命令时,Docker 会执行以下步骤:

  1. 读取 Dockerfile:Docker 会读取当前目录下的 Dockerfile。
  2. 构建镜像层
    • FROM openjdk:22-slim:基于 openjdk:22-slim 镜像创建一个新的镜像层。
    • COPY spring-ai-0.0.1-SNAPSHOT.jar app.jar:将当前目录下的 spring-ai-0.0.1-SNAPSHOT.jar 文件复制到新镜像的根目录,并重命名为 app.jar
    • ENTRYPOINT ["java","-jar","/app.jar"]:设置容器启动时的默认命令,即运行 /app.jar 文件。
  3. 标记镜像:构建完成后,Docker 会将新镜像标记为 aijava:1.0

image-20241124145715296

第四步,启动镜像

运行一个 Docker 容器:

docker run -d -p 8999:8999 aijava:1.0
  • docker run:这是运行 Docker 容器的命令。
  • -d:表示在后台运行容器。
  • -p 8999:8999:将宿主机的 8999 端口映射到容器的 8999 端口。
  • aijava:1.0:这是要运行的镜像名称和标签。

image-20241124150121201

然后我们就可以在浏览器验证这个容器了,如图就是没问题的!!

部署Kubernetes

部署之前我们先认识一下两个文件:

deployment.yamlservice.yaml 文件是 Kubernetes 中常用的两个配置文件,分别用于定义应用程序的部署和网络访问方式。

deployment.yaml

deployment.yaml 文件用于定义一个 Kubernetes Deployment 资源。Deployment 是一种控制器,用于管理应用程序的副本集和滚动更新,确保应用程序的高可用性和负载均衡。

service.yaml

service.yaml 文件用于定义一个 Kubernetes Service 资源。Service 是一种抽象,用于定义应用程序的网络访问方式,确保应用程序的高可用性和负载均衡

第一步,编写deployment.yaml

# apiVersion: apps/v1
# 定义了 Kubernetes API 的版本。apps/v1 是稳定版本,用于创建和管理 Deployment 资源。
apiVersion: apps/v1# kind: Deployment
# 声明这个 Kubernetes 资源的类型。Deployment 用于管理应用程序的副本集和滚动更新。
kind: Deployment# metadata:
# 包含资源的元数据信息,Kubernetes 通过 metadata 字段中的各类信息来跟踪和管理资源。
metadata:# name: aijava# 定义 Deployment 的名称,这里是 aijava。# 用途:用于唯一标识这个 Deployment,方便在其他地方引用。name: aijava# spec:
# 定义 Deployment 的规格,即 Deployment 的具体配置。
spec:# replicas: 1# Pod 的副本数量,即 Deployment 将运行的相同 Pod 数量。# 用途:确保应用程序具有高可用性和负载均衡。replicas: 1# selector:# 定义如何选择和管理 Pod。selector:# matchLabels:# 定义标签选择器,选择带有 app: aijava 标签的 Pod。# 用途:确保 Deployment 只管理带有指定标签的 Pod。matchLabels:app: aijava# template:# 定义 Pod 的模板,即每个副本 Pod 的配置。template:# metadata:# 包含 Pod 的元数据信息。metadata:# labels:# 定义 Pod 的标签。# 用途:用于标识和选择 Pod。labels:app: aijava# spec:# 定义 Pod 的规格,即 Pod 的具体配置。spec:# containers:# 定义 Pod 中的容器列表。containers:- # name: aijava# 定义容器的名称,这里是 aijava。# 用途:用于唯一标识这个容器,方便在其他地方引用。name: aijava# image: aijava:1.0# 定义容器使用的镜像,Kubernetes 会从容器镜像仓库中拉取它。# 用途:指定容器运行的应用程序版本。image: aijava:1.0# ports:# 定义容器内部监听的应用端口。# 用途:确保 Kubernetes 知道如何将流量路由到容器。ports:- # containerPort: 8999# 指定容器内部监听的应用端口。# 用途:应用程序在容器内监听的端口。containerPort: 8999

第二步,编写service.yaml

# apiVersion: v1
# 指定 Kubernetes API 的版本。v1 是稳定版本,用于创建和管理基本的 Kubernetes 资源。
apiVersion: v1# kind: Service
# 指定资源的类型。在这里,资源类型是 Service,表示这是一个 Kubernetes 服务。
kind: Service# metadata:
# 包含资源的元数据信息。
metadata:# name: aijava# 定义服务的名称,这里是 aijava。# 用途:用于唯一标识这个服务,方便在其他地方引用。name: aijava# spec:
# 定义服务的规格,即服务的具体配置。
spec:# type: NodePort# 定义服务的类型。NodePort 类型的服务会在每个节点上开放一个端口,通过这个端口可以访问服务。# 用途:适用于本地开发环境或不需要外部负载均衡器的场景。type: NodePort# ports:# 定义服务的端口配置。ports:- # port: 9999# 定义服务对外暴露的端口。外部客户端通过这个端口访问服务。# 用途:客户端可以通过 http://<node-ip>:9999 访问服务。port: 9999# targetPort: 8999# 定义集群内部目标 Pod 上运行的容器所监听的端口。# 用途:Kubernetes 会将请求从 port 转发到 targetPort,即从 9999 转发到 8999。targetPort: 8999# selector:# 定义服务选择哪些 Pod。selector:# app: aijava# 定义标签选择器,选择带有 app: aijava 标签的 Pod。# 用途:确保服务将流量路由到正确的 Pod。app: aijava

第三步,构建pod

kubectl apply -f deployment.yaml
kubectl apply -f service.yaml

这是他们的流程图:

kubectl apply -f deployment.yaml
└── Kubernetes 创建 Deployment 资源└── 创建 ReplicaSet└── 创建 Pod└── 拉取镜像并启动容器
kubectl apply -f service.yaml
└── Kubernetes 创建 Service 资源└── 选择匹配的 Pod└── 分配节点端口└── 负载均衡流量到后端 Pod

第四步,验证

kubectl get pods
kubectl get services

image-20241124153249155

这里我们看到pod的状态,Kubernetes 已经成功创建了 Deployment 和 Service,并且 Pod 已经处于运行状态。现在可以通过节点的 IP 地址和节点端口来访问我们的应用程序。

服务 aijava 的节点端口是 31431,所以我们可以通过

http://127.0.0.1:31431/index2.html?message=你好

去访问我们的应用了!!

image-20241124153606751

总结

至此,我们成功的将一个web应用部署到k8s中,当然,k8s还有docker中有很多东西在本文中没有展现出来,富贵同学认为,学东西之前你得学会怎么用,然后才问为什么,先上手,然后再深入,而不是先深入,再上手

那么在后续的过程中,欢迎关注作者:掉头发的王富贵,一起学习更多k8s的知识

http://www.xdnf.cn/news/216541.html

相关文章:

  • git fetch和git pull的区别
  • 域对齐是什么
  • 判断用户选择的Excel单元格区域是否跨页?
  • 力扣hot100——239.滑动窗口最大值
  • 在大数据环境下,使用spingboot为Android APP推送数据方案
  • 【Machine Learning Q and AI 读书笔记】- 02 自监督学习
  • 主流微前端框架比较
  • java面试题目
  • Nacos源码—2.Nacos服务注册发现分析四
  • 三种机器学习类型
  • Glide 如何加载远程 Base64 图片
  • MobileNetV2: 反向残差和线性瓶颈
  • 应急演练考试排查-DC01
  • 【动态导通电阻】GaN功率器件中动态导通电阻退化的机制、表征及建模方法
  • AI 的未来是开源?DeepSeek 正在书写新篇章!
  • 算法基础学习|02归并排序——分治
  • 封装js方法 构建树结构和扁平化树结构
  • 20_大模型微调和训练之-基于LLamaFactory+LoRA微调LLama3后格式合并
  • 水力压裂多裂缝扩展诱发光纤应变演化试验研究
  • 基于Mamba2的文本生成实战
  • 什么是 MCP?AI 应用的“USB-C”标准接口详解
  • AI赋能的问答系统:2025年API接口实战技巧
  • Vulkan与OpenGL的对比
  • 服务器主动发送响应?聊天模块如何实现?
  • 【Vue3/Typescript】合并多个pdf并预览打印,兼容低版本浏览器
  • CentOS NFS共享目录
  • 【GESP】C++三级练习 luogu-B2118 验证子串
  • 后验概率最大化(MAP)估计算法原理以及相具体的应用实例附C++代码示例
  • 源码编译安装LAMP
  • Python 3.12数据结构与算法革命