首页 > 其他分享 >09--kubernetes持久化存储和StatefulSet控制器

09--kubernetes持久化存储和StatefulSet控制器

时间:2024-09-04 14:52:59浏览次数:13  
标签:StatefulSet pv kubernetes -- yaml nfs mysql k8s root

前言:本章是k8s持久化存储的详细笔记,由持久化引申出来的statefulset控制器和无头svc都会在本章有详细记录。

1、K8s持久化存储PV和PVC

前面文章已经使用卷挂载的方式将pod文件持久化保存在宿主机中,但实际工作中pod往往会以多副本形式存在,此时需要每一个宿主机上都有对应的挂载卷,这样往往会造成存储资源极大浪费,所以这里需要引入PV和PVC概念解决这个问题。

1.1、PV和PVC的引入

Volume 提供了有效的数据持久化方案,但在管理上存在不足。以 AWS EBS(亚马逊云存储服务,需要收费,这里使用第四台虚拟机模拟提供此服务) 为例,使用 Volume 时,Pod 必须知道以下信息:当前 Volume 来自 AWS EBS、EBS Volume 已提前创建并且知道 volume-id。这导致应用开发人员和存储系统管理员的职责耦合。如果系统规模较小或在开发环境中尚可接受,但在大规模或生产环境中,效率和安全性的问题变得突出。

Kubernetes 提供了 PersistentVolume (PV) 和 PersistentVolumeClaim (PVC) 来解决这些问题。PV 是管理员创建和维护的外部存储空间,具有持久性,生命周期独立于 Pod。PVC 是对 PV 的申请,通常由普通用户创建,用于请求存储资源的容量和访问模式等信息。Kubernetes 会根据 PVC 查找并分配满足条件的 PV,使用户无需关心底层细节,由管理员处理 PersistentVolume 的创建和管理。

1.2、通过NFS实现持久化存储

1.2.1、环境准备

使用新虚拟机nfs节点(192.168.188.200)模拟云存储服务

查看磁盘空间,格式化设备,创建将被共享的目录,挂载磁盘,修改权限

[root@localhost ~]# fdisk -l
[root@localhost ~]# mkfs.ext4 /dev/sdb
[root@localhost ~]# mkdir /root/nfs
[root@localhost ~]# mount /dev/sdb /root/nfs
[root@localhost ~]# chmod 777 /root
[root@localhost ~]# chmod 777 /root/nfs

#生产环境中直接在根下创建

为所有节点安装nfs

yum install -y nfs-common nfs-utils

在nfs节点共享目录

[root@localhost ~]# vim /etc/exports
[root@localhost ~]# cat /etc/exports
/root/nfs *(rw,no_root_squash,no_all_squash,sync)

#注释
#    /root/nfs:这是要共享的目录路径。
#    *:表示允许所有客户端访问这个共享目录。可以用具体的 IP 地址或主机名替换 *,以限制访问权限。
#    rw:表示客户端具有读写权限。客户端可以对这个目录进行读和写操作。
#    no_root_squash:允许客户端以 root 用户身份访问共享目录时,拥有 root 权限。在默认设置下,NFS 会将客户端的 root 用户映射为普通用户,以增加安全性。
#    no_all_squash:允许客户端以任何用户身份访问共享目录时,保留客户端的原始身份,而不是映射为匿名用户。
#    sync:表示数据写入磁盘时是同步的,即在响应客户端请求之前,数据会被写入磁盘。这有助于确保数据的一致性,但可能会降低性能。

[root@localhost ~]# systemctl start rpcbind
#    用来告知nfs客户端nfs的服务端口
[root@localhost ~]# systemctl start nfs

此时需要使用客户端(node1,node2)测试nfs挂载是否可用

[root@k8s-node1 ~]# mkdir /test
[root@k8s-node1 ~]# mount -t nfs 192.168.188.200:/root/nfs /test/
[root@k8s-node1 ~]# df -Th | grep "/test"
192.168.188.200:/root/nfs nfs4       99G   60M   94G    1% /test
[root@k8s-node1 ~]# touch /test/123.txt
[root@k8s-node1 ~]# ls /test/
123.txt  lost+found

回到nfs服务端查看

[root@localhost ~]# ls /root/nfs/
123.txt  lost+found

测试完成后回到客户端卸载该目录

[root@k8s-node1 ~]# umount /test/
[root@k8s-node1 ~]# df -Th | grep "/test"

1.2.2、PV和PVC实操

回到master节点

[root@k8s-master1 ~]# mkdir pv.yaml.d
[root@k8s-master1 ~]# cd pv.yaml.d/
[root@k8s-master1 pv.yaml.d]# vim nfs-pv1.yaml
[root@k8s-master1 pv.yaml.d]# cat nfs-pv1.yaml
---
apiVersion: v1  # Kubernetes API 版本
kind: PersistentVolume  # 资源类型为持久卷
metadata:
  name: mypv1  # 持久卷的名称
spec:
  capacity:
    storage: 10Gi  # 持久卷的存储容量为 10GB(这里建议最多使用90%空间)
  accessModes:
    - ReadWriteOnce  # 访问模式为单节点读写
  persistentVolumeReclaimPolicy: Retain  # 回收策略为保留
  storageClassName: nfs  # 存储类名称为 nfs
  nfs:
    path: /root/nfs  # NFS 共享目录的路径
    server: 192.168.188.200  # NFS 服务器的 IP 地址

参数详解:

1、accessModes 指定访问模式为 ReadWriteOnce,支持的访问模式有:
ReadWriteOnce – PV 能以 read-write 模式 mount 到单个节点。
ReadOnlyMany – PV 能以 read-only 模式 mount 到多个节点。
ReadWriteMany – PV 能以 read-write 模式 mount 到多个节点

2、persistentVolumeReclaimPolicy 指定当 PV 的回收策略为Retain,支持的策略有:
Retain – 需要管理员手工回收。
Recycle – 清除 PV 中的数据,效果相当于执行 rm -rf /nfsdata/*。(已废除,使用不会报错,但无法生效)
Delete – 删除 Storage Provider 上的对应存储资源,例如 AWS EBS、GCE PD、Azure Disk、OpenStack Cinder Volume 等。

3、storageClassName 指定 PV 的 class 为 nfs。相当于为 PV 设置了一个分类,PVC 可以指定 class 申请相应 class 的 PV。

创建pv

[root@k8s-master1 pv.yaml.d]# kubectl apply -f nfs-pv1.yaml 
persistentvolume/mypv1 created
[root@k8s-master1 pv.yaml.d]# kubectl get pv
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
mypv1   10Gi       RWO            Retain           Available           nfs                     7s


#    STATUS 为 Available,表示 mypv1 就绪,可以被 PVC 申请。

创建pvc

[root@k8s-master1 pv.yaml.d]# vim nfs-pvc1.yaml
[root@k8s-master1 pv.yaml.d]# cat nfs-pvc1.yaml
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mypvc1
spec:
  accessModes:
    - ReadWriteOnce    #权限需要与目标pv保持一致
  resources:
    requests:
      storage: 10Gi    #通过大小可以绑定
  storageClassName: nfs    #通过类型也可以绑定


[root@k8s-master1 pv.yaml.d]# kubectl apply -f nfs-pvc1.yaml 
persistentvolumeclaim/mypvc1 created
[root@k8s-master1 pv.yaml.d]# kubectl get pvc
NAME     STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc1   Bound    mypv1    10Gi       RWO            nfs            5s

此时再去查看pv状态

[root@k8s-master1 pv.yaml.d]# kubectl get pv
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM            STORAGECLASS   REASON   AGE
mypv1   10Gi       RWO            Retain           Bound    default/mypvc1   nfs                     8m

#从 kubectl get pvc 和 kubectl get pv 的输出可以看到 mypvc1 已经 Bound 到 mypv1,申请成功。

配置pod并引用pvc

[root@k8s-master1 pv.yaml.d]# vim nfs-pod1.yaml
[root@k8s-master1 pv.yaml.d]# cat nfs-pod1.yaml
---
apiVersion: v1
kind: Pod
metadata:
  name: mypod1
  labels:
    app: liumuquan
spec:
  containers:
    - name: mypod1
      image: registry.cn-chengdu.aliyuncs.com/liumuquan_app/nginx:1.12.0-alpine
      ports:
      - containerPort: 80
      volumeMounts:
      - mountPath: "/usr/share/nginx/html"
        name: mydata
  volumes:
   - name: mydata
     persistentVolumeClaim:
       claimName: mypvc1

此时在nfs目录下写一个nginx主页文件

nfs服务端操作

[root@localhost ~]# rm -rf /root/nfs/*
[root@localhost ~]# echo "liumuquan-pvc1" > /root/nfs/index.html
[root@localhost ~]# chmod 777 /root/nfs/index.html

回到master创建pod并访问

[root@k8s-master1 pv.yaml.d]# kubectl apply -f nfs-pod1.yaml 
pod/mypod1 created
[root@k8s-master1 daemonset.yaml.d]# kubectl get pod -o wide
NAME     READY   STATUS    RESTARTS   AGE     IP            NODE        NOMINATED NODE   READINESS GATES
mypod1   1/1     Running   0          2m15s   10.244.2.28   k8s-node2   <none>           <none>
[root@k8s-master1 pv.yaml.d]# curl 10.244.2.28
liumuquan-pv1

1.2.3、pv回收

回收流程:svc-pod-pvc-pv

[root@k8s-master1 pv.yaml.d]# kubectl delete pod mypod1
pod "mypod1" deleted
[root@k8s-master1 pv.yaml.d]# kubectl delete pvc mypvc1
persistentvolumeclaim "mypvc1" deleted
[root@k8s-master1 pv.yaml.d]# kubectl delete pv mypv1
persistentvolume "mypv1" deleted

此时查看nfs服务端发现文件仍然存在

[root@localhost nfs]# pwd
/root/nfs
[root@localhost nfs]# ls
index.html
[root@localhost nfs]# cat index.html 
liumuquan-pv1

重复创建流程发现访问结果不变

1.3、PV/PVC实战(Mysql)

操作如下:

在nfs节点准备mysql文件夹,此文件夹可以为空,mysql与nginx不同,运行起来后会在该路径自动生成文件。

[root@localhost nfs]# mkdir /root/nfs/mysql-pv
[root@localhost nfs]# chmod 777 mysql-pv

回到master节点配置yaml文件

root@k8s-master1 pv.yaml.d]# vim mysql-pv-test.yaml
[root@k8s-master1 pv.yaml.d]# cat mysql-pv-test.yaml
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-pv
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: nfs
  nfs:
    path: /root/nfs/mysql-pv
    server: 192.168.188.200
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 9Gi
  storageClassName: nfs
---
apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  ports:
  - port: 3306
    targetPort: 3306
  selector:
    app: mysql
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - image: registry.cn-chengdu.aliyuncs.com/liumuquan_app/mysql:5.7
        name: mysql
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "Liumuquan@123"
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pvc

创建并检查状态

[root@k8s-master1 pv.yaml.d]# kubectl apply -f mysql-pv-test.yaml 
persistentvolume/mysql-pv created
persistentvolumeclaim/mysql-pvc created
service/mysql created
deployment.apps/mysql created

[root@k8s-master1 pv.yaml.d]# kubectl get pv,pvc,deploy,svc,pod
NAME                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM               STORAGECLASS   REASON   AGE
persistentvolume/mysql-pv   10Gi       RWO            Retain           Bound    default/mysql-pvc   nfs                     73s

NAME                              STATUS   VOLUME     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/mysql-pvc   Bound    mysql-pv   10Gi       RWO            nfs            73s

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/mysql   1/1     1            1           73s

NAME                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
service/kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP    17d
service/mysql        ClusterIP   10.102.65.24   <none>        3306/TCP   73s

NAME                         READY   STATUS    RESTARTS   AGE
pod/mysql-5b5d554c48-4b4vl   1/1     Running   0          73s

进入pod内操作(此处也可以使用集群内主机通过svc登录mysql)

[root@k8s-master1 pv.yaml.d]# kubectl exec -it mysql-5b5d554c48-4b4vl /bin/bash
bash-4.2# mysql -uroot -p"Liumuquan@123"
mysql> create database my_id;
Query OK, 1 row affected (0.00 sec)

mysql> use my_id;
Database changed
mysql> create table t1(id int,name varchar(30));
Query OK, 0 rows affected (0.02 sec)

mysql> insert into t1 values(1,"maguocheng");
Query OK, 1 row affected (0.01 sec)

mysql> insert into t1 values(2,"longkeduo");
Query OK, 1 row affected (0.00 sec)

mysql> select * from t1;
+------+------------+
| id   | name       |
+------+------------+
|    1 | maguocheng |
|    2 | longkeduo  |
+------+------------+
2 rows in set (0.00 sec)

退出pod,删除svc,deploy,pvc,pv

[root@k8s-master1 pv.yaml.d]# kubectl delete -f mysql-pv-test.yaml 
persistentvolume "mysql-pv" deleted
persistentvolumeclaim "mysql-pvc" deleted
service "mysql" deleted
deployment.apps "mysql" deleted

重新创建

[root@k8s-master1 pv.yaml.d]# kubectl apply -f mysql-pv-test.yaml 
persistentvolume/mysql-pv created
persistentvolumeclaim/mysql-pvc created
service/mysql created
deployment.apps/mysql created

进入容器查看发现数据并未丢失

[root@k8s-master1 pv.yaml.d]# kubectl get pod
NAME                     READY   STATUS    RESTARTS   AGE
mysql-5b5d554c48-zlx7m   1/1     Running   0          43s
[root@k8s-master1 pv.yaml.d]# kubectl exec -it mysql-5b5d554c48-zlx7m /bin/bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
bash-4.2# mysql -uroot -p"Liumuquan@123"

mysql> use my_id;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> select * from t1;
+------+------------+
| id   | name       |
+------+------------+
|    1 | maguocheng |
|    2 | longkeduo  |
+------+------------+
2 rows in set (0.00 sec)

2、PV/PVC的动态供应

动态存储流程示意图

当k8s业务上来的时候,需要大量的pvc,此时我们人工创建匹配的话,工作量就会非常大了,需要动态的自动挂载相应的存储。

nfs为提供存储的节点

绿色的pod用途为自动创建pv/pvc,使用deploy创建。

黄色的StorageClass,来对接存储,靠他来自动关联pvc,并创建pv。

橙色的StatefulSet,pod控制器,这里用来创建nginx的pod,本章结尾会详细说明。

2.1、PV/PVC动态供应项目实战

1)在nfs节点创建共享文件夹

[root@localhost ~]# mkdir /root/nfs/container_data
[root@localhost ~]# chmod 777 /root/nfs/container_data

2)部署storageclass

[root@k8s-master1 dynamic]# vim storageclass.yaml
[root@k8s-master1 dynamic]# cat storageclass.yaml
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: managed-nfs-storage #指定了存储类的名称
provisioner: fuseim.pri/ifs #指定了用于动态存储卷创建的插件或供应者

3)配置授权

因为storage自动创建pv需要经过kube-apiserver,所以要进行授权

创建1个sa(serviceaccount)

创建1个clusterrole,并赋予应该具有的权限,比如对于一些基本api资源的增删改查;这里也可以使用自带k8s角色。

创建1个clusterrolebinding,将sa和clusterrole绑定到一起;这样sa就有权限了;

然后pod中再使用这个sa,那么pod再创建的时候,会用到sa,sa具有创建pv的权限,便可以自动创建pv;

[root@k8s-master1 dynamic]# vim sa.yaml
[root@k8s-master1 dynamic]# cat sa.yaml
---
apiVersion: v1                        # 定义 ServiceAccount 的 API 版本
kind: ServiceAccount                  # 资源类型为 ServiceAccount
metadata:                             # 元数据部分
  name: nfs-client-provisioner        # ServiceAccount 的名称
  namespace: default                  # ServiceAccount 所在的命名空间
---
kind: ClusterRole                     # 资源类型为 ClusterRole
apiVersion: rbac.authorization.k8s.io/v1 # 定义 ClusterRole 的 API 版本
metadata:                             # 元数据部分
  name: nfs-client-provisioner-runner # ClusterRole 的名称
rules:                                # 权限规则
  - apiGroups: [""]                   # 适用于 core API 组
    resources: ["nodes"]              # 节点资源
    verbs: ["get", "list", "watch"]   # 权限操作
  - apiGroups: [""]                   # 适用于 core API 组
    resources: ["persistentvolumes"]  # 持久卷资源
    verbs: ["get", "list", "watch", "create", "delete"] # 权限操作
  - apiGroups: [""]                   # 适用于 core API 组
    resources: ["persistentvolumeclaims"] # 持久卷声明资源
    verbs: ["get", "list", "watch", "update"] # 权限操作
  - apiGroups: ["storage.k8s.io"]     # 适用于 storage.k8s.io API 组
    resources: ["storageclasses"]     # 存储类资源
    verbs: ["get", "list", "watch"]   # 权限操作
  - apiGroups: [""]                   # 适用于 core API 组
    resources: ["events"]             # 事件资源
    verbs: ["create", "update", "patch"] # 权限操作
---
kind: ClusterRoleBinding              # 资源类型为 ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1 # 定义 ClusterRoleBinding 的 API 版本
metadata:                             # 元数据部分
  name: run-nfs-client-provisioner    # ClusterRoleBinding 的名称
subjects:                             # 关联的主体
  - kind: ServiceAccount              # 主体类型为 ServiceAccount
    name: nfs-client-provisioner      # 关联的 ServiceAccount 名称
    namespace: default                # ServiceAccount 所在的命名空间
roleRef:                              # 角色引用部分
  kind: ClusterRole                   # 角色类型为 ClusterRole
  name: nfs-client-provisioner-runner # 关联的 ClusterRole 名称
  apiGroup: rbac.authorization.k8s.io # 角色的 API 组
---
kind: Role                           # 资源类型为 Role
apiVersion: rbac.authorization.k8s.io/v1 # 定义 Role 的 API 版本
metadata:                             # 元数据部分
  name: leader-locking-nfs-client-provisioner # Role 的名称
  namespace: default                  # Role 所在的命名空间
rules:                                # 权限规则
  - apiGroups: [""]                   # 适用于 core API 组
    resources: ["endpoints"]          # 端点资源
    verbs: ["get", "list", "watch", "create", "update", "patch"] # 权限操作
---
kind: RoleBinding                    # 资源类型为 RoleBinding
apiVersion: rbac.authorization.k8s.io/v1 # 定义 RoleBinding 的 API 版本
metadata:                             # 元数据部分
  name: leader-locking-nfs-client-provisioner # RoleBinding 的名称
  namespace: default                  # RoleBinding 所在的命名空间
subjects:                             # 关联的主体
  - kind: ServiceAccount              # 主体类型为 ServiceAccount
    name: nfs-client-provisioner      # 关联的 ServiceAccount 名称
    namespace: default                # ServiceAccount 所在的命名空间
roleRef:                              # 角色引用部分
  kind: Role                         # 角色类型为 Role
  name: leader-locking-nfs-client-provisioner # 关联的 Role 名称
  apiGroup: rbac.authorization.k8s.io # 角色的 API 组

4)配置deploy

[root@k8s-master1 dynamic]# vim deploy.yaml
[root@k8s-master1 dynamic]# cat deploy.yaml
---
kind: Deployment                    # 部署资源类型
apiVersion: apps/v1                  # API 版本
metadata:                            # 元数据部分
  name: nfs-client-provisioner       # 部署的名称
spec:                                # 规格部分
  selector:                          # 选择器部分,用于确定哪些 Pods 属于这个 Deployment
    matchLabels:                     # 标签匹配规则
      app: nfs-client-provisioner    # 匹配标签 "app" 的值为 "nfs-client-provisioner"
  replicas: 1                        # 副本数,即创建一个 Pod 实例
  strategy:                          # 部署策略部分
    type: Recreate                   # 策略类型为 Recreate,即先删除旧的 Pod 再创建新的 Pod
  template:                          # Pod 模板
    metadata:                        # 模板的元数据部分
      labels:                       # Pod 的标签
        app: nfs-client-provisioner # 标签 "app" 的值为 "nfs-client-provisioner"
    spec:                            # Pod 的规格部分
      serviceAccount: nfs-client-provisioner # 指定使用的 ServiceAccount
      containers:                    # 容器列表
        - name: nfs-client-provisioner # 容器的名称
          image: registry.cn-chengdu.aliyuncs.com/k8s_module_images/lizhenliang_nfs-client-provisioner:v2.0.0 # 容器镜像地址
          volumeMounts:              # 卷挂载配置
            - name: nfs-client-root # 卷的名称
              mountPath: /persistentvolumes # 挂载路径
          env:                       # 环境变量配置
            - name: PROVISIONER_NAME  # 环境变量名称
              value: fuseim.pri/ifs  # 环境变量值,应与 storageclass 中的 provisioner 一致
            - name: NFS_SERVER       # 环境变量名称
              value: 192.168.188.200 # NFS 服务器地址
            - name: NFS_PATH         # 环境变量名称
              value: /root/nfs/container_data # NFS 共享路径
      volumes:                        # 卷列表
        - name: nfs-client-root      # 卷的名称
          nfs:                       # 使用 NFS 卷类型
            server: 192.168.188.200 # NFS 服务器地址
            path: /root/nfs/container_data # NFS 共享路径

5)部署上方配置文件并检查

[root@k8s-master1 dynamic]# kubectl apply -f storageclass.yaml 
storageclass.storage.k8s.io/managed-nfs-storage created
[root@k8s-master1 dynamic]# kubectl apply -f sa.yaml 
serviceaccount/nfs-client-provisioner created
clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-runner created
clusterrolebinding.rbac.authorization.k8s.io/run-nfs-client-provisioner created
role.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
rolebinding.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
[root@k8s-master1 dynamic]# kubectl apply -f deploy.yaml 
deployment.apps/nfs-client-provisioner created
[root@k8s-master1 dynamic]# kubectl get sc,sa,deploy,pod
NAME                                              PROVISIONER      RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
storageclass.storage.k8s.io/managed-nfs-storage   fuseim.pri/ifs   Delete          Immediate           false                  64s

NAME                                    SECRETS   AGE
serviceaccount/default                  1         18d
serviceaccount/nfs-client-provisioner   1         58s

NAME                                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nfs-client-provisioner   1/1     1            1           50s

NAME                                          READY   STATUS    RESTARTS   AGE
pod/nfs-client-provisioner-65fcd7b4c8-bmcc4   1/1     Running   0          50s

6)配置StatefulSet

这里需要引入无头svc

[root@k8s-master1 dynamic]# vim nginx-StatefulSet.yaml
[root@k8s-master1 dynamic]# cat nginx-StatefulSet.yaml
---
apiVersion: v1                        # API 版本
kind: Service                         # 资源类型为 Service
metadata:                             # 元数据部分
  name: nginx                         # Service 的名称
  labels:                             # 标签
    app: nginx                        # 标签 "app" 的值为 "nginx"
spec:                                 # 规格部分
  ports:                               # 端口配置
  - port: 80                           # Service 公开的端口
    name: web                         # 端口名称
  clusterIP: None                     # 集群内部 IP 地址设为 None,表示这是一个 Headless Service
  selector:                           # 选择器部分
    app: nginx                        # 选择标签为 "app: nginx" 的 Pods
---
apiVersion: apps/v1                   # API 版本
kind: StatefulSet                     # 资源类型为 StatefulSet
metadata:                             # 元数据部分
  name: web                           # StatefulSet 的名称
spec:                                 # 规格部分
  serviceName: "nginx"                # 关联的 Service 名称
  replicas: 2                         # 副本数,即创建两个 Pod 实例
  selector:                           # 选择器部分
   matchLabels:                       # 标签匹配规则
      app: nginx                     # 匹配标签 "app" 的值为 "nginx"
  template:                           # Pod 模板
    metadata:                         # 模板的元数据部分
      labels:                         # Pod 的标签
        app: nginx                    # 标签 "app" 的值为 "nginx"
    spec:                             # Pod 的规格部分
      containers:                     # 容器列表
      - name: nginx                   # 容器的名称
        image: registry.cn-chengdu.aliyuncs.com/liumuquan_app/nginx:1.12.0-alpine # 容器镜像地址
        ports:                        # 端口配置
        - containerPort: 80           # 容器内部端口
          name: web                   # 端口名称
        volumeMounts:                 # 卷挂载配置
        - name: www                   # 卷的名称
          mountPath: /usr/share/nginx/html # 挂载路径
  volumeClaimTemplates:               # 卷声明模板
  - metadata:                         # 模板的元数据部分
      name: www                       # 卷声明的名称
    spec:                             # 卷声明的规格部分
      accessModes: [ "ReadWriteOnce" ] # 存储访问模式
      storageClassName: "managed-nfs-storage" # 存储类名称
      resources:                      # 资源请求配置
        requests:                     # 请求的资源
          storage: 1Gi               # 存储请求量

7)创建nginx

[root@k8s-master1 dynamic]# kubectl apply -f nginx-StatefulSet.yaml 
service/nginx created
statefulset.apps/web created

8)查看pod状态

[root@k8s-master1 dynamic]# kubectl get pod
NAME                                      READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-65fcd7b4c8-bmcc4   1/1     Running   0          18m
web-0                                     1/1     Running   0          75s
web-1                                     1/1     Running   0          70s

 这里可以看出StatefulSet是有序命名,逐个创建的(注意运行时间的不同)

 9)查看pv

命名规则:命名空间-模板设置的卷名-pod名字-pvc-随机序列号

[root@k8s-master1 dynamic]# kubectl get pv
NAME                                                         CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM               STORAGECLASS          REASON   AGE
default-www-web-0-pvc-88f9b153-9c9f-4e8b-9f7a-6f35d0622582   1Gi        RWO            Delete           Bound    default/www-web-0   managed-nfs-storage            25m
default-www-web-1-pvc-2d1de5c7-1ff0-4765-8760-241be3f2bcd6   1Gi        RWO            Delete           Bound    default/www-web-1   managed-nfs-storage            25m

这里有两个pv分别对应nfs节点目录的两个文件夹

[root@localhost ~]# ls /root/nfs/container_data
default-www-web-0-pvc-88f9b153-9c9f-4e8b-9f7a-6f35d0622582  default-www-web-1-pvc-2d1de5c7-1ff0-4765-8760-241be3f2bcd6

 只在web-0目录创建文件

[root@localhost ~]# echo "statefulset" > /root/nfs/container_data/default-www-web-0-pvc-88f9b153-9c9f-4e8b-9f7a-6f35d0622582/index.html
[root@localhost ~]# chmod 777 /root/nfs/container_data/default-www-web-0-pvc-88f9b153-9c9f-4e8b-9f7a-6f35d0622582/index.html

回到master节点访问

[root@k8s-master1 dynamic]# kubectl get pod -o wide
NAME                                      READY   STATUS    RESTARTS   AGE   IP            NODE        NOMINATED NODE   READINESS GATES
nfs-client-provisioner-65fcd7b4c8-bmcc4   1/1     Running   0          50m   10.244.2.31   k8s-node2   <none>           <none>
web-0                                     1/1     Running   0          32m   10.244.2.32   k8s-node2   <none>           <none>
web-1                                     1/1     Running   0          32m   10.244.1.46   k8s-node1   <none>           <none>
[root@k8s-master1 dynamic]# curl 10.244.2.32
statefulset
[root@k8s-master1 dynamic]# curl 10.244.1.46
<html>
<head><title>403 Forbidden</title></head>
<body bgcolor="white">
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.12.0</center>
</body>
</html>

备注:

  1. 此时nfs上的/root/nfs/container_data目录,已经被取用nfs的pod(绿色)挂到/persistentvolumes(deploy.yaml内配置)
  2. StatefulSet通过自身的卷模板触发storageclass从绿pod的/persistentvolumes取用空间

10)资源对象回收

回收顺序:StatefulSet-pv/pvc(这里是deloyment控制器)-授权-stc

[root@k8s-master1 dynamic]# ls
deploy.yaml  nginx-StatefulSet.yaml  sa.yaml  storageclass.yaml
[root@k8s-master1 dynamic]# kubectl delete -f nginx-StatefulSet.yaml
service "nginx" deleted
statefulset.apps "web" deleted
[root@k8s-master1 dynamic]# kubectl delete -f deploy.yaml 
deployment.apps "nfs-client-provisioner" deleted
[root@k8s-master1 dynamic]# kubectl delete -f sa.yaml 
serviceaccount "nfs-client-provisioner" deleted
clusterrole.rbac.authorization.k8s.io "nfs-client-provisioner-runner" deleted
clusterrolebinding.rbac.authorization.k8s.io "run-nfs-client-provisioner" deleted
role.rbac.authorization.k8s.io "leader-locking-nfs-client-provisioner" deleted
rolebinding.rbac.authorization.k8s.io "leader-locking-nfs-client-provisioner" deleted
[root@k8s-master1 dynamic]# kubectl delete -f storageclass.yaml 
storageclass.storage.k8s.io "managed-nfs-storage" deleted

此时查看数据仍正常保存

[root@localhost ~]# cat /root/nfs/container_data/default-www-web-0-pvc-88f9b153-9c9f-4e8b-9f7a-6f35d0622582/index.html 
statefulset

3、statefulset控制器

StatefulSet 是用来管理有状态应用的工作负载 API 对象。下面是和deploy的对比。

DeploymentStatefulSet

适合场景

无状态的应用有状态的应用

特点

1.pod之间没有顺序

2.所有pod共享存储

3.pod名字包含随机数字

4.service都有ClusterIP,可以负载均衡

1.部署、扩展、更新、删除都要有顺序


2.每个pod都有自己存储,所以都用volumeClaimTemplates,为每个pod都生成一个自己的存储,保存自己的状态


3.pod名字始终是固定的


4.service没有ClusterIP,是headlessservice,所以无法负载均衡,返回的都是pod名,所以pod名字都必须固定,StatefulSet在Headless Service的基础上又为StatefulSet控制的每个Pod副本创建了一个DNS域名:$(podname).(headless server name).namespace.svc.cluster.local

StatefulSet 中的 Pod 具有一个独特且持久的身份标识(域名),这个标识基于 StatefulSet 控制器分配给每个 Pod 的唯一顺序索引。Pod 的名称的形式为 <StatefulSetName>-<index>。例如,如果一个 StatefulSet 名为 web 且拥有两个副本,它会创建两个 Pod,分别为 web-0web-1

标识符(域名)解析演示
[root@k8s-master1 dynamic]# kubectl get pod -o wide
NAME                                      READY   STATUS    RESTARTS   AGE     IP            NODE        NOMINATED NODE   READINESS GATES
nfs-client-provisioner-65fcd7b4c8-8qqc5   1/1     Running   0          10m     10.244.2.33   k8s-node2   <none>           <none>
web-0                                     1/1     Running   0          9m56s   10.244.2.34   k8s-node2   <none>           <none>
web-1                                     1/1     Running   0          9m54s   10.244.1.49   k8s-node1   <none>           <none>


[root@k8s-master1 dynamic]# kubectl exec -it web-1 /bin/sh
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
/ # nslookup web-0.nginx.default.svc.cluster.local
Name:      web-0.nginx.default.svc.cluster.local
Address 1: 10.244.2.34 web-0.nginx.default.svc.cluster.local
/ # 

与 Deployment 相似,StatefulSet 也管理一组基于相同容器定义的 Pod。然而,StatefulSet 与 Deployment 的不同之处在于,StatefulSet 为每个 Pod 维护一个固定的 ID。这些 Pod 是基于相同的声明创建的,但它们不可互换,每个 Pod 都有一个永久不变的 ID。

使用场景:StatefulSet 对于以下需求的应用程序尤为重要:

  1. 稳定的、唯一的网络标识符:即使 Pod 重新调度,其 PodName 和 HostName 仍保持不变(虽然 IP 地址可能会变)。命名方式为
    PodName.serviceName.namespaceName.svc.cluster.local
  2. 稳定的、持久的存储:即使 Pod 重新调度,仍能访问相同的持久化数据,通过 PVC 实现。
  3. 有序的部署和缩放
  4. 有序的、自动的滚动更新

总之,StatefulSet 提供了稳定性,确保 Pod 调度或重调度的过程是持久的。

如果应用程序不需要稳定的标识符或有序的部署、删除或缩放,可以使用无状态的副本控制器,如 Deployment 或 ReplicaSet,这些更适用于无状态应用的部署。

使用规则:

  1. 存储要求:Pod 的存储必须由 PersistentVolume 驱动,依据所请求的 storage class 提供,或由管理员预先提供。

  2. 存储保护:删除或缩减 StatefulSet 不会删除其关联的存储卷,以确保数据安全,这通常比自动清除所有相关资源更为重要。

  3. 网络标识:StatefulSet 需要一个 headless 服务来处理 Pod 的网络标识。你需要负责创建该服务。

  4. 终止保证:StatefulSet 不保证 Pod 的终止。为了正常终止,可以在删除前将 StatefulSet 缩减到 0。

  5. 滚动更新:在默认的 Pod 管理策略 (OrderedReady) 下,滚动更新可能导致需要人工干预才能修复的损坏状态。

  6. 有序索引:StatefulSet 中的每个 Pod 将被分配一个从 0 到 N-1 的唯一整数序号。

  7. 主机名格式:StatefulSet 中的每个 Pod 的主机名由 StatefulSet 名称和 Pod 的序号组成,格式为 $(StatefulSet 名称)-$(序号)

部署、删除、扩容,缩容规则:

  1. Pod 创建顺序:在 StatefulSet 中,包含 N 个副本的 Pod 按照顺序从 0 到 (N-1) 依次创建。

  2. Pod 删除顺序:Pod 被删除时,按照逆序从 (N-1) 到 0 终止。

  3. 缩放前提:在应用缩放操作前,前面的所有 Pod 必须处于 Running 和 Ready 状态。

  4. 缩容保护:如果 web-2 被终止和删除后,但 web-1 尚未被终止,且此时 web-0 发生运行失败,那么系统会等待 web-0 恢复到 Running 和 Ready 状态后才会终止 web-1。这样做是为了确保系统的稳定性和数据一致性,防止在 Pod 失败的情况下过早地终止其他 Pod

  5. 继任者关闭:在终止 Pod 之前,所有后续序号的 Pod必须完全关闭,也就是说,如果 StatefulSet 有 3 个副本,终止序号为 1 的 Pod 前,Pod 2 和 Pod 3 必须完全停止,这样可以确保数据的完整性和正确性。

  6. 终止宽限期pod.Spec.TerminationGracePeriodSeconds 指定 Pod 在终止前的宽限时间。如果将此值设置为 0,Pod 会立即终止,可能导致未完成的请求丢失或数据不一致。为了保证 Pod 有足够时间完成当前操作和清理资源,必须设置一个合理的宽限期。这样可以提高系统的可靠性和安全性。

标签:StatefulSet,pv,kubernetes,--,yaml,nfs,mysql,k8s,root
From: https://blog.csdn.net/qq_43387908/article/details/141784552

相关文章

  • 【漏洞复现】通达OA v11.7 moare 反序列化漏洞
    免责声明:        本文内容旨在提供有关特定漏洞或安全漏洞的信息,以帮助用户更好地了解可能存在的风险。公布此类信息的目的在于促进网络安全意识和技术进步,并非出于任何恶意目的。阅读者应该明白,在利用本文提到的漏洞信息或进行相关测试时,可能会违反某些法律法规......
  • pbootcms去除ueditor编辑器图片自动添加的title和alt属性
    为了去掉UEditor上传图片时自动添加的 title 和 alt 属性,并且将 alt 属性设置为空,可以按照以下步骤进行修改:步骤1:修改 ueditor.all.min.js 文件打开文件:打开文件 \core\extend\ueditor\ueditor.all.min.js。搜索并修改代码:搜索 "imageUrlPrefix",找到以......
  • 视频监控管理平台LntonAIServer视频质量诊断功能:画面静止检测与遮挡检测
    随着视频监控技术的不断发展,视频质量的重要性日益凸显。LntonAIServer通过引入一系列视频质量诊断功能,致力于提高视频监控系统的可靠性和有效性。其中,画面静止检测与遮挡检测是两个非常实用的功能,它们可以帮助监控系统及时发现并解决问题,确保视频流的质量符合预期。一、画面静止检......
  • [英语单词]hairpin
    这个第一眼看了,以为是头发丝这么细的pin/大头针。但是hairpin,是用的pin的第二个意思:固定。意思是:发卡,固定头发的发卡。pinn.大头针,针,别针,栓,销子,图钉,插头,管脚,品(液量单位)vt.将…用针别住,钉住,压住,牵制,使不能动,归罪于a.针的,销子的,闩的......
  • 【漏洞复现】致远OA fileUpload.do 任意文件上传漏洞
    免责声明:        本文内容旨在提供有关特定漏洞或安全漏洞的信息,以帮助用户更好地了解可能存在的风险。公布此类信息的目的在于促进网络安全意识和技术进步,并非出于任何恶意目的。阅读者应该明白,在利用本文提到的漏洞信息或进行相关测试时,可能会违反某些法律法规......
  • 教育问答工具V1.0—使用手册
    背景信息阿里云微服务SpringCloudAlibabaSpringCloudAlibaba是阿里巴巴提供的微服务开发一站式解决方案,是阿里巴巴开源中间件与SpringCloud体系的融合。以下是对SpringCloudAlibaba的详细介绍:定义:SpringCloudAlibaba是阿里巴巴结合自身丰富的微服务实践而推出的微服务开发......
  • 配置CentOS 7网卡的教程
    1、打开终端,并以root身份登录。2、使用以下命令查看当前系统中的网卡设备:ipaddrshow3、找到要配置的网卡设备名称,通常以ens或eth开头。4、打开要配置的网卡文件,例如ens33:vi/etc/sysconfig/network-scripts/ifcfg-ens335、在文件中,添加以下内容,根据实际情况进行修改......
  • React 18 系统精讲:‌前端教程与最新特性源码级剖析
    React18系统精讲:‌前端教程与最新特性源码级剖析引言React18带来了许多激动人心的新特性和改进,‌旨在提高应用的性能和用户体验。‌本教程将深入探讨React18的核心特性,‌包括并发特性、‌新的API、‌以及源码层面的解析,‌帮助前端开发者更好地理解和应用这些新技术。‌......
  • 【gtokentool】元宇宙nft区块链是什么
    元宇宙元宇宙的定义元宇宙(Metaverse)这个词起源于NealStephenson在1992年出版的小说《雪崩》,Metaverse由Meta(意即“超越”、“元”)和verse(意即“宇宙universe”)两个词构成。元宇宙是整合多种新技术而产生的新型虚实相融的互联网应用和社会形态,它是一个和现实世界有关联的虚......
  • 如何优化浏览器缓存
    每当用户访问您的网站,他他们的浏览器需要从服务器上下载页面显示所需的资源(图片、CSS、JavaScript和字体等),这些资源的下载会占用带宽,并需要一定的传输时间。但通过正确配置,您可以告知用户的浏览器保存部分文件,这样下一次访问时可以直接从缓存中读取,从而加快页面加载速度。什么是浏......