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

news2024/11/25 18:42:24

前言:本章是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 是管理员创建和维护的外部存储空间,具有持久性,生命周期独立于 PodPVC 是对 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 有足够时间完成当前操作和清理资源,必须设置一个合理的宽限期。这样可以提高系统的可靠性和安全性。

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

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

相关文章

骨传导耳机哪个牌子最好?今天安利五款好口碑骨传导耳机!

基于对运动耳机多年的使用和深入研究&#xff0c;我想传达几个朴素却重要的观点&#xff1a;购买前请三思&#xff0c;避免盲目追求潮流。虽然网络上的热门款式引人瞩目&#xff0c;但它们的热度可能转瞬即逝&#xff1b;而高价位的知名品牌耳机&#xff0c;虽然品质有保证&…

SpringBoot整合Thymleaf实现页面静态化

1. 问题需求分析 在做乐优商城时&#xff0c;页面是通过Thymeleaf模板引擎渲染后返回到客户端。当商品详情页数据渲染时&#xff0c;在后台需要大量的数据查询&#xff0c;而后渲染得到HTML页面。在用户访问量大的情况下会对数据库造成压力&#xff0c;并且请求的响应时间过长…

开放式耳机与入耳式耳机相比,有哪些优劣势?权威推荐5个实用好用品牌

​开放式耳机其实相对于入耳式耳机来说区别还是比较大的。开放式耳机现在超火&#xff0c;它们不塞进耳朵&#xff0c;这样长时间戴着耳朵也不会难受&#xff0c;还能保护耳朵卫生&#xff0c;特别受爱运动和喜欢研究耳机的朋友们欢迎。不过市面上的开放式耳机太多了&#xff0…

glsl着色器学习(三)

前面两篇文章已经创建好了顶点着色器和片段着色器并编译成功&#xff0c;下面将创建program(程序)&#xff0c;将着色器链接起来 创建Program const prg gl.createProgram(); gl.attachShader(prg, vertexShader); gl.attachShader(prg, fragmentShader); gl.linkProgram(pr…

【无标题】docker-compose一键部署项目,haproxy容器代理多个web或java容器

# 创建脚本&#xff0c;可以在java环境中运行任何的jar包或者war包#!/bin/bash/usr/local/jdk/bin/java -jar /java/src/*.?ar 一、思路分析&#xff1a; &#xff08;1&#xff09;nginx 1、下载镜像&#xff0c;将本地的dist项目的目录挂载在容器的/usr/share/nginx/html/ …

LLM大模型教程:大模型技术名词和概念太多了,一手学习笔记

、、 构建AI化需要的知识体系 Semantic Kernel Semantic Kernel是Microsoft推出的一个开源框架&#xff0c;旨在帮助开发者构建和部署AI应用&#xff0c;特别是那些需要理解和生成自然语言的应用。它提供了一种结构化的方式来定义和管理技能&#xff08;Skills&#xff09;&…

【Canvas技法】五种函数化回文边纹纹饰荟萃

【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>五种函数化回文边纹纹饰荟萃</title><style type"text…

一文速学ChatBi“与数据库对话“大模型技术原理及框架一览

前言 上期写了NL2SQL&#xff0c;相信看过的朋友应该都对现在大模型在数据交互办公层面的探索和发展都十分感兴趣&#xff0c;在此商业化的产品市场上也有很多&#xff0c;比如阿里云的析言GBI&#xff1a; 腾讯云的ChatBI&#xff1a; 像此类的产品可以说是最贴切业务的。 在…

C++笔记16•数据结构:关联式容器map和set•

map和set 1.关联式容器 前面介绍的的是序列式容器&#xff1a;vector、list、deque等容器。这次博客介绍STL新的容器成员&#xff0c;那就是关联式容器&#xff1b;顾名思义关联式容器就是容器存在中的数据之间存在联系&#xff08;关联&#xff09;。与序列式容器不同的是&am…

linux入门系列【1】常用命令

一、简介 linux 基本操作命令,便于我们去使用命令帮助我们去检索和排查问题 二、常用命令 1.磁盘空间排查 1.1 查看磁盘空间分布情况 du -ah .|sort -hr 在对应目录下执行则是查看对应目录的文件分布以及大小情况,一般用于查看某个文件夹目录数据情况 1.2 查看深度层级为…

Java中的Set(如果想知道Java中有关Set的知识点,那么只看这一篇就足够了!)

前言&#xff1a;在Java编程中&#xff0c;集合框架&#xff08;Collections Framework&#xff09;是处理数据结构和算法的基础工具之一。它提供了一套强大且灵活的接口和类&#xff0c;用于存储和操作不同类型的数据集合。在这其中&#xff0c;Set接口扮演着一个重要角色。与…

vue-router基本流程及其案例分析

web发展历程 1.后端实现路由 在这个阶段&#xff0c;前端基本上只写界面&#xff0c;也就是html,css,js那些东西&#xff0c;然后在界面中挖槽用来接后端数据&#xff0c;包括路由也由后端负责&#xff0c;在这个阶段中&#xff0c;web开发非常依赖后端&#xff0c;常见的后端…

系列精选 |【梧桐数据库】产品架构层次解析-总述

梧桐数据库中秋特别活动免费领取大闸蟹 抽奖免费领取大闸蟹 以下是正文 在浩瀚的数据世界里&#xff0c;梧桐数据库犹如一颗璀璨的星辰&#xff0c;它的设计如同一首细腻的诗歌&#xff0c;每一个层次都是优美的韵律&#xff0c;为我们构建了一个强大而灵动的数据天地。 梧桐数…

西中区2024年度安全知识竞赛活动方案

为有效预防安全生产事故的发生&#xff0c;深化西中区全体员工对安全生产的认识&#xff0c;切实提升全体人员的安全意识和自我保护能力&#xff0c;夯实安全知识基础&#xff0c;丰富安全文化内涵&#xff0c;推动安全生产工作更加规范化、系统化&#xff0c;根据西中区安全生…

<数据集>遥感航拍飞机和船舶和识别数据集<目标检测>

数据集格式&#xff1a;VOCYOLO格式 图片数量&#xff1a;19973张 标注数量(xml文件个数)&#xff1a;19973 标注数量(txt文件个数)&#xff1a;19973 标注类别数&#xff1a;2 标注类别名称&#xff1a;[ship,plane] 序号类别名称图片数框数1ship17575416292plane239815…

简单好用的SD卡克隆软件:轻松克隆SD卡

想更换SD卡以提升性能&#xff0c;但不知道如何进行SD卡克隆&#xff1f;不用担心&#xff0c;本文推荐了一款好用SD卡克隆软件&#xff0c;轻松帮你解决问题&#xff01; 为什么要克隆SD卡&#xff1f; SD卡广泛应用于游戏机、手机及其他便携设备。用户常用SD卡存储个人数据…

2024/9/3黑马头条跟学笔记(一)

D1 视频链接 Day1-05-nacos环境搭建_哔哩哔哩_bilibili 内容介绍 搭建微服务开发环境&#xff0c;登录接口包含注册中心和nacos配置中心 服务端用户…微服务。网关负载均衡转发接口请求 实现微服务间互相通信 接口测试 前后端联调 前置知识 背景介绍 类似今日头条&#x…

权威解读:社交类APP都需要办理哪些资质?

今天小编给大家讲讲社交类APP都需要办理哪些资质&#xff1f; 我们先来看下微信小程序对社交类目是怎么分类以及需要哪些资质许可证&#xff1f; 微信小程序社交类目许可资质 微信小程序对社交类目做了一些细分&#xff0c;它把社交分为陌生人交友、熟人交友、社区/论坛、直播…

log4j 控制台和文件输出乱码问题解决

一个小问题&#xff0c;却让我感觉到&#xff0c;现在真正动脑的人很少。。我来说说吧。 今天遇到一个小问题&#xff0c; log4j输出到文件乱码&#xff0c;控制台正常。显然是编码问题导致。Google一搜&#xff0c;几乎一水的说&#xff1a; 项目中log4j在英文版linux下输出中…

气膜水产养殖:打造高效、可持续的水产养殖新模式—轻空间

随着全球对高质量水产品需求的不断增加&#xff0c;传统的水产养殖方式面临着诸多挑战&#xff0c;如环境污染、气候变化以及水源短缺等问题。在这种背景下&#xff0c;气膜水产养殖作为一种创新的养殖模式&#xff0c;逐渐引起了广泛关注。通过结合气膜结构建筑与现代化养殖技…