编辑
2025-08-16
K8S(重新复习)
00

目录

一、概念
二、使用StatefulSets的样列
1.找一台虚拟机搭建NFS
2.K8S集群的机器都安装nfs客户端
3.编写yml配置文件
部署一个NFS客户端供应器(provisioner),作为Kubernetes与NFS服务器之间的桥梁
RBAC权限配置
MySQL StatefulSet存储配置
4.当运行配置后效果
5.手动删除后StatefulSet的恢复操作

一、概念

**StatefulSet 是用来管理有状态应用的工作负载 API 对象。

无状态应用: 应用本身不存储任何数据的应用称之为无状态应用。

有状态应用: 应用本身需要存储相关数据应用称之为有状态应用。

博客: 前端vue 后端 java mysql redis es ....

数据采集: 采集程序 有状态应用

StatefulSet 用来管理某 Pod 集合的部署和扩缩, 并为这些 Pod 提供持久存储和持久标识符。

和 Deployment 类似, StatefulSet 管理基于相同容器规约的一组 Pod。但和 Deployment 不同的是, StatefulSet 为它们的每个 Pod 维护了一个有粘性的 ID。这些 Pod 是基于相同的规约来创建的, 但是不能相互替换:无论怎么调度,每个 Pod 都有一个永久不变的 ID。

如果希望使用存储卷为工作负载提供持久存储,可以使用 StatefulSet 作为解决方案的一部分。 尽管 StatefulSet 中的单个 Pod 仍可能出现故障, 但持久的 Pod 标识符使得将现有卷与替换已失败 Pod 的新 Pod 相匹配变得更加容易。 **

js
StatefulSet 对于需要满足以下一个或多个需求的应用程序很有价值: 稳定的、唯一的网络标识符。 稳定的、持久的存储。 有序的、优雅的部署和扩缩。 有序的、自动的滚动更新。

**给定 Pod 的存储必须由 PersistentVolume Provisioner 基于所请求的 storage class 来制备,或者由管理员预先制备。

删除或者扩缩 StatefulSet 并不会删除它关联的存储卷。 这样做是为了保证数据安全,它通常比自动清除 StatefulSet 所有相关的资源更有价值。

StatefulSet 当前需要无头服务来负责 Pod 的网络标识。你需要负责创建此服务。

当删除一个 StatefulSet 时,该 StatefulSet 不提供任何终止 Pod 的保证。 为了实现 StatefulSet 中的 Pod 可以有序且体面地终止,可以在删除之前将 StatefulSet 缩容到 0。

在默认 Pod 管理策略(OrderedReady) 时使用滚动更新, 可能进入需要人工干预才能修复的损坏状态。**

二、使用StatefulSets的样列

1.找一台虚拟机搭建NFS

sh
#安装nfs-utils yum install -y rpcbind nfs-utils #创建nfs目录 mkdir -p /root/nfs/data #编辑/etc/exports输入如下内容 # insecure:通过 1024 以上端口发送 rw: 读写 sync:请求时写入共享 no_root_squash:root用户有完全根目录访问权限 echo "/root/nfs/data *(insecure,rw,sync,no_root_squash)" >> /etc/exports #启动相关服务并配置开机自启动 systemctl start rpcbind systemctl start nfs-server systemctl enable rpcbind systemctl enable nfs-server #重新挂载 使 /etc/exports生效 exportfs -r #查看共享情况 exportfs

2.K8S集群的机器都安装nfs客户端

js
# 1.安装客户端 所有节点安装 yum install -y nfs-utils # 2.创建本地目录 mkdir -p /root/nfs # 3.挂载远程nfs目录到本地 #前面是nfs服务器挂载的目录 后面是本机挂载的目录 mount -t nfs 192.168.201.104:/root/nfs /root/nfs # 4.写入一个测试文件 echo "hello nfs server" > /root/nfs/test.txt # 5.去远程 nfs 目录查看 cat /root/nfs/test.txt # 挂取消载 umount -f -l nfs目录

3.编写yml配置文件

部署一个NFS客户端供应器(provisioner),作为Kubernetes与NFS服务器之间的桥梁

yml
vi nfs-client-provider.yml
js
apiVersion: apps/v1 kind: Deployment metadata: name: nfs-client-provisioner labels: app: nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: kube-system spec: replicas: 1 strategy: type: Recreate selector: matchLabels: app: nfs-client-provisioner template: metadata: labels: app: nfs-client-provisioner spec: serviceAccountName: nfs-client-provisioner containers: - name: nfs-client-provisioner image: chronolaw/nfs-subdir-external-provisioner:v4.0.2 volumeMounts: - name: nfs-client-root mountPath: /persistentvolumes env: - name: PROVISIONER_NAME value: k8s-sigs.io/nfs-subdir-external-provisioner - name: NFS_SERVER value: 192.168.201.104 #nfs服务器ip地址 - name: NFS_PATH value: /root/nfs/data #nfs服务器共享数据目录 volumes: - name: nfs-client-root nfs: server: 192.168.201.104 #nfs服务器ip地址 path: /root/nfs/data #nfs服务器共享数据目录

RBAC权限配置

ServiceAccount:创建专用服务账号

ClusterRole:定义供应器需要的集群级权限(节点、PV、PVC等资源的操作权限)

ClusterRoleBinding:将ClusterRole绑定到ServiceAccount

Role/RoleBinding:为leader选举机制配置端点(endpoints)的操作权限

js
vi rbac.yml
yml
apiVersion: v1 kind: ServiceAccount metadata: name: nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: kube-system --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: nfs-client-provisioner-runner rules: - apiGroups: [""] resources: ["nodes"] verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["persistentvolumes"] verbs: ["get", "list", "watch", "create", "delete"] - apiGroups: [""] resources: ["persistentvolumeclaims"] verbs: ["get", "list", "watch", "update"] - apiGroups: ["storage.k8s.io"] resources: ["storageclasses"] verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["events"] verbs: ["create", "update", "patch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: run-nfs-client-provisioner subjects: - kind: ServiceAccount name: nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: kube-system roleRef: kind: ClusterRole name: nfs-client-provisioner-runner apiGroup: rbac.authorization.k8s.io --- kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: leader-locking-nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: kube-system rules: - apiGroups: [""] resources: ["endpoints"] verbs: ["get", "list", "watch", "create", "update", "patch"] --- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: leader-locking-nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: kube-system subjects: - kind: ServiceAccount name: nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: kube-system roleRef: kind: Role name: leader-locking-nfs-client-provisioner apiGroup: rbac.authorization.k8s.io

MySQL StatefulSet存储配置

js
mysql.yml
yml
# ==================== 命名空间配置 ==================== apiVersion: v1 # Kubernetes核心API版本标识 kind: Namespace # 声明资源类型为命名空间 metadata: # 资源元数据开始 name: ems # 定义命名空间名称为ems(Enterprise Management System) # ==================== 存储类配置 ==================== apiVersion: storage.k8s.io/v1 # 存储类API版本标识 kind: StorageClass # 声明资源类型为存储类 metadata: # 资源元数据开始 name: mysql-nfs-sc # 存储类命名(MySQL专用NFS存储类) namespace: ems # 归属ems命名空间 provisioner: k8s-sigs.io/nfs-subdir-external-provisioner # 指定NFS子目录动态供应器 parameters: # 供应器参数配置开始 onDelete: "remain" # 数据保留策略:删除时不清理 # ==================== 有状态应用配置 ==================== apiVersion: apps/v1 # 应用API版本标识 kind: StatefulSet # 声明资源类型为有状态副本集 metadata: # 资源元数据开始 name: mysql # StatefulSet名称 namespace: ems # 归属ems命名空间 labels: # 标签集合开始 app: mysql # 应用标识标签 spec: # 规格定义开始 serviceName: mysql-headless # 关联的无头服务名(用于DNS解析) replicas: 1 # 副本数配置(MySQL单实例部署) template: # Pod模板定义开始 metadata: # Pod元数据开始 labels: # Pod标签集合开始 app: mysql # 应用标识标签(需与selector匹配) spec: # Pod规格定义开始 containers: # 容器定义列表开始 - name: mysql # 容器名称标识 image: mysql/mysql-server:8.0 # 官方MySQL 8.0镜像 ports: # 端口映射列表开始 - containerPort: 3306 # MySQL服务默认端口 env: # 环境变量列表开始 - name: MYSQL_ROOT_PASSWORD # root密码变量名 value: "root" # 密码明文值(测试环境使用) volumeMounts: # 存储卷挂载列表开始 - name: data # 引用下方PVC模板名称 mountPath: /var/lib/mysql # MySQL数据存储路径 volumeClaimTemplates: # PVC模板列表开始 - metadata: # PVC元数据开始 name: data # PVC资源名称 spec: # PVC规格定义开始 accessModes: [ "ReadWriteMany" ] # 存储访问模式(多节点读写) storageClassName: "mysql-nfs-sc" # 绑定前文定义的存储类 resources: # 资源请求定义开始 requests: # 资源请求参数开始 storage: 2Gi # 存储空间大小请求值 selector: # Pod选择器定义开始 matchLabels: # 标签匹配规则开始 app: mysql # 需匹配的Pod标签键值

4.当运行配置后效果

然后去NFS服务器查看,是否映射生成了mysql的数据,无论怎么重启或删除都是映射对应的数据文件 image.png

image.png

我把副本扩容为两个,nfs对应也会生成两个,同时nfs那边也会生成对应pod唯一的数据文件

js
kubectl scale sts mysql --replicas=2 -n ems

image.png

image.png 当我缩容缩成一个时,数据文件也不会被删除

js
kubectl scale sts mysql --replicas=1 -n ems

image.png

image.png

5.手动删除后StatefulSet的恢复操作

因为知道StatefulSet在你手动删除后,再重新运行会生成一个新的映射文件和唯一ID,虽然原来的文件在nfs不会被删除但映射的文件已经变更。

js
# 我先进入容器的msyql数据库写点数据用于辨认。 kubectl exec -it mysql-0 -n ems -- bash # 然后执行登录数据库命令 mysql -u root -proot # 然后查看全部数据库命令 show databases; # 然后在创建一个数据库 CREATE DATABASE songxuan;

**现在有四个数据库,如果我删除了这个StatefulSet,再重新执行,那他只会有三个,怎么恢复成我原来的呢 ** image.png

删除StatefulSet,再重新执行

js
kubectl delete -f mysql.yml kubectl apply -f mysql.yml

再看这时这个mysql-0已经重新生成映射的容器了,要如何还原原来的数据呢 image.png 先将现在的进行mv更名加个bak备份,然后把原来的文件名称改成现在新映射的名称。

js
# 先改名(该操作在NFS服务器操作) mv ems-data-mysql-0-pvc-7f8adb77-88ca-4cc4-991e-dcf3a4168633 ems-data-mysql-0-pvc-7f8adb77-88ca-4cc4-991e-dcf3a4168633.bak #然后把新的文件名称改到旧的上面(该操作在NFS服务器操作) mv archived-ems-data-mysql-0-pvc-12b63880-8bd7-459a-9911-8b6d1716cd29 ems-data-mysql-0-pvc-7f8adb77-88ca-4cc4-991e-dcf3a4168633 #然后需要重启pod,我直接把pod删了 kubectl delete pod mysql-0 -n ems

再次进容器的mysql查看已经成功还原 image.png

js
整体工作流程: 1.StatefulSet创建时自动触发PVC申请 2.StorageClass调用NFS provisioner动态创建PV 3.ProvisionerNFS服务器上创建对应子目录 4.PV绑定到PVC后挂载到MySQL容器

本文作者:松轩(^U^)

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

Document