k8s部署SpringCloud微服务集群

1,445 阅读19分钟

k8s部署SpringCloud微服务集群

一、前言

本文简要介绍 kubernetes(后文简称 k8s )的基本原理,随后重点介绍了基于 k8s 部署 SpringBoot 微服务应用集群的方法。

为了更好的演示 K8s 部署应用集群的过程,我们开发了一个 SpringCloud 微服务项目 springCloudK8sMall ,springCloudK8sMall 和部署方案都是采用最简化的处理,目的是为了帮助大家快速入门 k8s。

k8s-project.png

二、Kubernetes 简介

1. 什么是 k8s?

从官方的定义来说,Kubernetes就是云原生微服务应用的编排器。但是编排器这个感念似乎并不好理解,所以个人认为下面这个介绍更能帮助理解 k8s 的本质。

k8s 是云的操作系统,使用户不必关心应用是在谁的云或服务器上运行。就像Linux和Windows意味着用户不必关心应用是运行在戴尔还是IBM的服务器上一样。

k8s 帮我们解决服务器,存储,网络的调度(编排)问题,使我们能够专注于应用的部署。就类似于Linux或者windows帮我们解决的CPU,内存,IO的调度,使我们可以专注于应用的开发和使用。

2. 为什么我们需要 K8s 呢?

1)公司可以不必关心应用是在谁的云或服务器上运行,避免被某个云厂商或服务器厂商绑架;
2)简化部署流程,快速扩缩容,快速恢复环境:

在日常开发运维中,你是否遇到过以下场景“

  1. 项目一开始需要搭建开发环境,你登录每一台服务器安装JDK、filebeat、安装nginx、安装nacos集群...,花了两三天时间才把集群搭建好。
  2. 项目开发好了,进入SIT、UAT环节,又需要重复两遍遍上述环节,又花了几天;项目顺利发布上线,搭建PROD环境,这次服务器更多,又花了更多时间部署环境;
  3. 项目运行了一段时间,安全排查出filebeat或者nginx版本存在安全漏洞,然后又登录各个环境的各台服务器一个个升级中间件;
  4. 有时候在PROD改了某个中间件的配置,但是不确定是否同步到了其他环境,随着时间的推移,各个环境开始不一致,为项目稳定运行埋下了未知风险。

从上述过程可以看出了,每一个环境的搭建,我们都需要执行相同的过程,同时,很难方便的对比各个环境的差异。

k8s一键创建/销毁环境:如果使用 k8s 部署,则只需要为每个环境配置一组 yaml 文件,执行一行简单命令,即可在几分钟之内完成环境搭建或销毁。同时只需要对比不同环境的yaml文件,即可知道他们之间的差异。接下来,我们就通过 演示项目 springCloudK8sMall 看看如何通过k8s实现这种能力。

# 一键创建或者销毁环境   
kubectl apply/delete -f ./deploy/

#每个环境配置一组部署配置文件
|--[dev/test/prod]/deploy/
   |--mall-frontend-deployment.yaml
   |--mall-gateway-deployment.yaml
   |--nacos-statefulset.yaml
   |--xxx.yaml

三、Kubernetes原理简述

1. k8s架构

k8s-arch.png Kubernetes 集群由控制平面和一个或多个工作节点组成。以下是主要组件的简要概述:

  1. 控制平面组件: 管理集群的整体状态(不重要,部署应用不需要和这些组件打交道,了解即可):
    1. kube-apiserver: 公开 Kubernetes HTTP API 的核心组件服务器;
    2. etcd: 具备一致性和高可用性的键值存储,用于所有 API 服务器的数据存储;
    3. kube-scheduler: 查找尚未绑定到节点的 Pod,并将每个 Pod 分配给合适的节点;
    4. kube-controller-manager: 运行控制器来实现 Kubernetes API 行为。
    5. cloud-controller-manager: 与底层云驱动集成
  2. Node 组件:在每个节点上运行,维护运行的 Pod 并提供 Kubernetes 运行时环境:
    1. kubelet: 确保 Pod 及其容器正常运行;
    2. kube-proxy: 维护节点上的网络规则以实现 Service 的功能;
    3. 容器运行时(Container runtime);

我们所有的应用和中间件都是运行在 node 组件的容器运行时中,通过kube-proxy向集群内外提供网络访问。

2. k8s的一些基本概念

k8s引入了许多概念,但是本文只简单介绍容器、Pod、Deployment、Service等四个核心概念,因为通过这四个内容,你就可以把你的微服务集群运行起来了。

1)容器

容器和虚拟机相比,它实际上是一种资源隔离的进程,运行在容器中的应用比独占一个虚拟机消耗的资源更少,启动速度更快。所谓的资源隔离主要只指进程隔离、文件隔离、网络隔离

  • 进程隔离:最基本的隔离就是进程之间看不到彼此,这是由Linux的Namespace机制实现的;
  • 文件隔离:第二种隔离就是隔离系统真实的文件系统。Docker利用Linux的mount机制,给每个隔离进程挂载了一个虚拟的文件系统,使得一个隔离进程只能访问这个虚拟的文件系统,无法看到系统真实的文件系统;
  • 网络隔离:第三种隔离就是网络协议栈的隔离;

一个容器进程本质上是一个运行在沙盒中的隔离进程,由Linux系统本身负责隔离,Docker只是提供了一系列工具,帮助我们设置好隔离环境后,启动这个进程。

2)Pod

上面我们已经提过了,所有的应用和中间件都是运行在容器运行时中,那么我们如何管理容器运行时呢?

其实就是通过Pod,Pod 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。Pod 是一个或者一组容器的封装器;这些容器共享存储、网络、以及怎样运行这些容器的规约。可以把 Pod 简单理解为传统虚拟化部署中的虚拟机,只不过类似容器和虚拟机的差别,Pod占用的资源更小而已。

3)Deployment

一个 Deployment 为 Pod 提供声明式的更新能力,也就是服务更新和扩缩容的能力。

所谓的声明式,就是说用户可以通过 Deployment 声明 Pod 的期望状态,Deployment 会自动帮你把 Pod 保持在期望状态。而期望状态,一般是指你需要这个 Pod 有几个副本,如何更新,如何定义 Pod 的健康状态的信息。

4)Service

Kubernetes 网络模型由几个部分构成:

  • 集群中的每个 Pod 都会获得自己的、独一无二的集群范围 IP 地址。
  • Pod 网络(也称为集群网络)处理 Pod 之间的通信。它确保所有 Pod 可以与所有其他 Pod 进行通信, 无论它们是在同一个节点还是在不同的节点上。
  • Service API 允许你为由一个或多个后端 Pod 实现的服务提供一个稳定(长效)的 IP 地址或主机名, 其中组成服务的各个 Pod 可以随时变化。

k8s网络模型有两个重要的特点:

  1. 对外界不可见
  2. Pod之间可以互访,但却是不稳定的。集群会为每个Pod生成IP,但是Pod没有重启的概念,所谓服务重启就是销毁旧 Pod,创建新 Pod。在某些场景下,我们需要服务保持稳定的网络,比如注册中心,各个微服务需要配置固定的注册中心地址。

Service就是为了解决上述两个问题:

  1. 对集群外暴露访问入口;
  2. 对集群内提供稳定的服务访问地址;

四、Kubernetes安装

:如果你已经有了k8s运行环境,可以跳过这部分

minikube是一个本地Kubernetes,它提供和k8s一样的交互命令,安装更加简单,占用的资源也更少,所以在学习环境,我们通过WMware虚拟机安装minikube进行学习。

环境及版本说明

  1. VMware:
    • VMware® Workstation 16 Pro 16.2.4 build-20089737
  2. 操作系统:
  3. minikube:
    • minikube v1.34.0
    • Kubernetes v1.31.0

1. 安装docker

卸载docker
sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
安装docker
yum install -y yum-utils device-mapper-persistent-data lvm2
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum makecache fast
yum -y install docker-ce

参考文档:通过aliyun镜像安装docker

配置dockers容器镜像(xxxxx.mirror.aliyuncs.com地址自行到阿里云容器镜像服务——》镜像加速器获取)

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://xxxxx.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

2.安装kubectl

使用阿里云镜像安装kubectl,你可以按照以下步骤操作:

1) 添加阿里云的Kubernetes仓库。
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=0
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
2) 安装kubectl
yum install -y kubectl

#验证安装是否成功。
kubectl version --client

3.安装minikube

1) 获取官方最新版minikube
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64

install minikube-linux-amd64 /usr/local/bin/minikube
2) 设置默认驱动
minikube config set driver docker
3) 启动minikube 启动一个k8s节点
minikube delete ; minikube start --force  --base-image='registry.cn-hangzhou.aliyuncs.com/google_containers/kicbase:v0.0.44'
#--force是以root身份启动的docker的必须选项
#--base-image为指定minikube start 采用的基础镜像,上面docker pull拉取了什么镜像,这里就改成什么镜像(不指定可能会报错)
4) 验证minikube
[root@minikube ~]# minikube status
minikube
type: Control Plane
host: Running
kubelet: Running
apiserver: Running
kubeconfig: Configured
5) 检查minikuke相关的资源是否正常启动(全部都是Running状态表示正常)
[root@minikube ~]# kubectl get pod,svc,deployment,rc -n kube-system
NAME                                   READY   STATUS    RESTARTS        AGE
pod/coredns-6f6b679f8f-6gdhm           1/1     Running   0               7m5s
pod/etcd-minikube                      1/1     Running   0               7m11s
pod/kube-apiserver-minikube            1/1     Running   0               7m11s
pod/kube-controller-manager-minikube   1/1     Running   0               7m11s
pod/kube-proxy-f4vnw                   1/1     Running   0               7m5s
pod/kube-scheduler-minikube            1/1     Running   0               7m11s
pod/storage-provisioner                1/1     Running   1 (6m47s ago)   7m9s

NAME               TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
service/kube-dns   ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   7m10s

NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/coredns   1/1     1            1           7m10s

五、Kubernetes部署SpringCloud微服务应用集群

1. 演示项目 springCloudK8sMall 应用介绍

如下图所示,springCloudK8sMall 是前后端分离的 B/S 应用。前端是一个基于 Vue 3 和 Element Plus 的商城演示项目,展示了一个微服务架构的商城系统,包括用户管理、商品管理、订单管理等功能。后端是一个基于Spring Cloud的微服务商城应用,以nacos为注册中心,包含用户微服务、商品微服务、订单微服务、所有后端微服务通过网关微服务向外暴露接口。

k8s-project.png

2. 镜像管理

1) 打包镜像

我们知道,k8s是管理容器应用的编排器,所以第一步就是要打包镜像,即应用容器化。

前提说明:从2024年7月起阿里云镜像加速器调整了 规则 ,只能在阿里云服务器使用阿里云镜像加速器。我使用的方式是购买了一台基础版的云服务器,用于打包镜像,打包后推动到免费的 阿里云容器镜像中心 ,再从本地虚拟机拉取镜像,运行容器。

下面,以前端工程为例,在工程根目录编写如下 Dockerfile 文件。

# Dockerfile
# 使用 Node.js 17 作为基础镜像
FROM node:17 as build-stage
# 设置工作目录
WORKDIR /app
# 复制 package.json 和 package-lock.json (如果存在)
COPY package*.json ./
# 安装项目依赖
RUN npm install
# 复制项目文件和文件夹到工作目录
COPY . .
# 构建应用
RUN npm run build
# 生产阶段
FROM nginx:stable-alpine as production-stage
# 从构建阶段复制构建好的文件到 nginx
COPY --from=build-stage /app/dist /usr/share/nginx/html
# 暴露 80 端口
EXPOSE 80
# 启动 nginx
CMD ["nginx", "-g", "daemon off;"]

执行 docker build 命令完成镜像打包

docker build -t mall-frontend .

执行 docker images 命令可以查看镜像信息

[root@aliyun mall]# docker images | grep mall-frontend
mall-frontend  latest    de465df980c9   2 weeks ago    29.7MB

现在我们可以直接在本地运行 Docker 容器,验证镜像是否可以正常执行

# 运行容器
docker run -d -p 18080:80 mall-frontend

# 查看容器运行状态
[root@aliyun mall]# docker ps
CONTAINER ID   IMAGE           COMMAND                  CREATED         STATUS         PORTS                                     NAMES
66340f2a68f7   mall-frontend   "/docker-entrypoint.…"   5 seconds ago   Up 3 seconds   0.0.0.0:18080->80/tcp, :::18080->80/tcp   awesome_swartz

# 测试访问
curl http://localhost:18080
2) 使用阿里云镜像中心管理镜像
1、免费申请试用阿里云镜像服务

登录 阿里云镜像服务 申请免费试用,进入 命名空间 创建一个自己的命名空间就可以开始使用了。

2、在打包镜像的服务器和运行k8s的服务器中登录镜像服务
# 登录阿里云Docker Registry,用于登录的用户名为阿里云账号全名,密码为开通服务时设置的密码。
docker login --username=<username> registry.cn-hangzhou.aliyuncs.com
3、在打包镜像的服务器中将镜像推送到镜像中心
# 标记镜像(注意将推送地址更换为你自己的命名空间(namespace)) 
docker tag mall-frontend:latest registry.cn-hangzhou.aliyuncs.com/namsapce01/mall-frontend:latest

# 推送镜像
docker push registry.cn-hangzhou.aliyuncs.com/namsapce01/mall-frontend:latest
4、在运行k8s的服务器中拉取镜像
# 拉取镜像
docker pull registry.cn-hangzhou.aliyuncs.com/namsapce01/mall-frontend:latest
5、从docker加载镜像到minikube

上述拉取镜像的动作只是将镜像拉取到了本地docker中,由于我们是使用minikube运行k8s集群,因此还需要将镜像加载到minikube中

# 加载镜像到minikube
[root@minikube ~]# minikube image load  registry.cn-hangzhou.aliyuncs.com/namsapce01/qsk-book:1.1
[root@minikube ~]# minikube image ls
registry.cn-hangzhou.aliyuncs.com/namsapce01/qsk-book:1.1
3. 小结

我们以前端工程为例介绍了镜像打包和镜像管理的全过程,后端工程镜像打包和管理唯一的差异点就是Dockerfile文件不同,这里不再赘述,大家可以自行查看对于的Dockerfile文件。

2. k8s部署前端

1. 定义 Pod

如前所述,Pod 是K8s中应用执行的最小单位,Pod 的作用即是封装容器。

因此,要在k8s中部署应用,第一步就是要定义应用的Pod。如下所示,Pod 的定义文件由两部分组成,spec 之前定义了诸如 API 版本、资源类型、Pod 名称等基本信息,spec 定义了容器的信息。

# mall-frontend-pod.yaml
apiVersion: v1  # 定义K8s API的版本
kind: Pod # 定义创建资源的类型
metadata:
  name: mall-frontend-pod  # POD的名称
spec: # 规格说明,定义容器信息
  containers:
    - name: mall-frontend-pod
      image: registry.cn-hangzhou.aliyuncs.com/namsapce01/mall-frontend:latest # 镜像 这里的namespace01需要替换为自己的命名空间
      imagePullPolicy: IfNotPresent # 镜像拉取策略:Always、Never、IfNotPresent
      ports:
        - containerPort: 80

定义好 Pod 对应的 yaml 文件之后,只需要执行 kubectl apply 命令,即可在 k8s 集群中运行对应的 Pod。Pod 的状态为 Running 即说明已经成功运行 Pod,不过此时的 Pod 只能在K8s集群内访问,并不能在集群外访问。

# 运行Pod
[root@minikube deploy]# kubectl apply -f mall-frontend-pod.yaml 
pod/mall-frontend-pod created

查看POD状态
[root@minikube deploy]# kubectl get pods
NAME                             READY   STATUS    RESTARTS      AGE
mall-frontend-pod                1/1     Running   0             10s
2.使用 Deployment 管理一组 Pod

在上一节我们了解了如何定义并运行一个 Pod,但在实际运维中,我们并不会这样直接运行一个 Pod。因为 Pod 实际上是一个临时资源,你不应该期待单个 Pod 既可靠又耐用。

在实际应用中,k8s 是通过 Deployment 管理一组 Pod,通过 Deployment 定义一组 Pod 的期望状态,K8s 会自动帮忙实现并保持在这个期望状态。

所谓 Pod 的期望状态,即一个Pod 运行几个副本,如何更新等状态。

下面这个文件定义了前端项目的 Deployment 文件,从文件中可以看到两个关键信息:

  • replicas: 定义 Pod 的副本数,即有2个 mall-frontend 的 Pod 运行;
  • selector: 选择器,这是一个k8s中很关键的概念,这里指定这个 Deployment 需要管理的 Pod,这里即表示管理的是 app=mall-frontend 的 Pod。
# mall-frontend-deployment.yaml
apiVersion: apps/v1  # 定义使用的 Kubernetes API 版本
kind: Deployment # 定义要创建的资源类型
metadata: # 元数据
  name: mall-frontend # Deployment 的名称
  labels:
    app: mall-frontend # 为 Deployment 添加标签
spec: # Deployment规格说明
  replicas: 2 # 定义期望运行的副本数
  selector: # 定义如何选择要管理的 Pod
    matchLabels:
      app: mall-frontend
  template: # 定义 Pod 的模板
    metadata: # Pod 的元数据
      labels: # 为 Pod 添加标签
        app: mall-frontend
    spec: # Pod 的规格
      containers: # 定义容器
      - name: mall-frontend
        image: registry.cn-hangzhou.aliyuncs.com/namsapce01/mall-frontend:latest # 镜像
        imagePullPolicy: IfNotPresent # 镜像拉取策略:Always、Never、IfNotPresent
        ports:  # 定义容器端口
        - containerPort: 80

同样的,我们执行 kubectl apply 即运行对应的 Deployment

# 创建Deployment
[root@minikube deploy]# kubectl apply -f mall-frontend-deployment.yaml 
deployment.apps/mall-frontend created

# 查看Dployment
[root@minikube deploy]# kubectl get deploy -o wide
NAME            READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS      IMAGES                                                              SELECTOR
mall-frontend   2/2     2            2           13m   mall-frontend   registry.cn-hangzhou.aliyuncs.com/namsapce01/mall-frontend:latest   app=mall-frontend

从Deployment的状态可以看出,DEADY为2/2,即表示期望的POD数量为2,当前成功运行的数量也为2。这时继续查看 Pod 的状态可以发现,Deployment 自动生成了两个 Pod。

[root@minikube deploy]# kubectl get pod 
NAME                             READY   STATUS    RESTARTS      AGE
mall-frontend-6bb5768dbc-25jh8   1/1     Running   0             22m
mall-frontend-6bb5768dbc-vmqvj   1/1     Running   0             22m

为什么k8s特别强调了期望数量和实际数量呢?这就是k8s提供的强大的声明式的更新能力,我们只需要定义我们期望的状态,k8s会自动创建并保持在这个状态。

现在我们来看一下如果其中的一个 Pod 被删除或者意外宕机会发生什么?

# 删除POD mall-frontend-6bb5768dbc-25jh8
[root@minikube deploy]# kubectl delete pod mall-frontend-6bb5768dbc-25jh8
pod "mall-frontend-6bb5768dbc-25jh8" deleted

# 查看POD状态
[root@minikube deploy]# kubectl get pod 
NAME                             READY   STATUS    RESTARTS      AGE
mall-frontend-6bb5768dbc-vmqvj   1/1     Running   0             23m
mall-frontend-6bb5768dbc-xf5jd   1/1     Running   0             4s

从上面的过程可以看到,k8s 提供的 Deployment 自动新建了一个 Pod,仍然将 Pod 的数量保持在我们期望的数量2。

到这里,前端服务就已经部署好了,但是目前这个服务只能在集群内访问,集群外还无法访问到这个服务。

3.使用Service暴露服务的入口

我们在前文中已经提过,Service主要解决两个问题:

  1. 对集群外暴露访问入口;
  2. 对集群内提供稳定的服务访问地址;

这里我们先来演示第一个能力,即对集群外暴露访问入口。

从mall-frontend-service.yaml我们看到两组关键信息:

  • selector: 定义这个service对于的POD
  • port: 定义如何映射端口
    • targetPort: 对于POD中容器的端口
    • port: Service 暴露的端口,我们可以在集群内通过Service IP + 这个端口访问POD的服务
    • nodePort: 提供一个集群外端口,通过集群IP访问

k8s-ports.png

# mall-frontend-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: mall-frontend-service # Service 的名称
spec: # Service 规格说明
  selector: # 定义如何选择要暴露的 Pod
    app: mall-frontend # 选择标签为 app: mall-frontend 的 Pod
  ports: 
    # 定义单个端口映射
    - protocol: TCP      # 使用 TCP 协议
      port: 80           # Service 暴露的端口
      targetPort: 80     # Pod 中容器的端口
      nodePort: 30080    # 提供一个集群外访问的端口,只能在30000-32767范围内
  type: NodePort     # 定义 Service 类型,通过每个节点上的 IP 和静态端口(NodePort)公开 Service。 为了让 Service 可通过节点端口访问,Kubernetes 会为 Service 配置集群 IP 地址, 相当于你请求了 type: ClusterIP 的 Service。

执行kubectl apply 命令创建Service

[root@minikube deploy]# kubectl apply -f mall-frontend-service.yaml 
service/mall-frontend-service created

查看Service状态

[root@minikube deploy]# kubectl get svc
NAME                    TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)               AGE
mall-frontend-service   NodePort    10.102.36.9     <none>        80:30080/TCP          77m 

现在我们就可以通过集群IP+service端口访问前端服务了

# 查看集群IP         
[root@minikube deploy]# minikube ip
192.168.49.2

# 在集群外访问前端服务
[root@minikube deploy]# curl 192.168.49.2:30080
<!doctype html><html lang=""><head><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><link rel="icon" href="/favicon.ico"><title>mall</title><script defer="defer" src="/js/chunk-vendors.8382f0a2.js"></script><script defer="defer" src="/js/app.0cafe880.js"></script><link href="/css/chunk-vendors.5c8b628d.css" rel="stylesheet"><link href="/css/app.db76374a.css" rel="stylesheet"></head><body><noscript><strong>We're sorry but mall doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div></body></html>

到这里,前端服务就全部部署完成了,但是由于我们的k8s是运行VMware虚拟机中的,如果我们要在外部的windows机器上访问服务,还需要建立一个代理服务:

# 在运行VMware的windows机器上执行以下命令
ssh -L {本地访问的端口}:{minikube的ip}:{service暴露的端口} {虚拟机(如CentOS、Debian、Ubuntu等)的用户名}@{虚拟机的ip}

# 如执行,则可以在windows机器上通过浏览器访问127.0.0.1:9000访问对应的服务
ssh -L 9000:192.168.49.2:30080 root@192.168.8.128

2. k8s部署后端微服务集群

后端微服务集群的部署和前端差异不大,主要的区别就是 nacos 注册中心不应该使用 Deployment 管理负载,而应该使用 StatefulSet 管理负载。

Deployment 和 StatefulSet 都是用于管理应用负载的,主要差别是 Deployment 主要用于管理无状态服务,StatefulSet 用于管理有状态服务。

有状态无状态

  • 无状态:不会对本地环境产生任何依赖。
  • 有状态:会对本地环境(存储、网络等)产生依赖,会存储数据到本地内存、磁盘等,如redis,db;

由于我们使用的是 Nacos 本地 DB 缓存数据,所以应该使用 StatefulSet 部署。