K8S存储值之PV和PVC

1. 概念:

1.1. PersistentVolume (PV):

  • 是由管理员设置的存储,它是群集的一部分。就像节点是集群中的资源一样,PV也是集群中的资源。PV是Volume之类的卷插件,但具有独立于使用PV的Pod的生命周期。此API对象包含存储实现的细节,即NFS、iSCSI或特定于云供应商的存储系统。

1.2. PersistentVolumeclaim (PVC)

  • 是用户存储的请求。它与Pod相似。Pod消耗节点资源,PVC消耗PV资源。Pod可以请求特定级别的资源(CPU和内存)。PVC可以请求特定的大小和访问模式(例如,可以以读/写一次或只读多次模式挂载)

1.3. PV和PVC如何绑定

  • master中的控制环路监视新的PVC,寻找匹配的PV(如果可能),并将它们绑定在一起。如果为新的PVC动态调配PV,则该环路将始终将该PV绑定到PVC。否则,用户总会得到他们所请求的存储,但是容量可能超出要求的数量。一旦PVPVC绑定后,PersistentVolumeClaim绑定是排他性的,不管它们是如何绑定的。PVCPV绑定是一对一的映射。

1.4. 持久化卷声明的保护

  • PVC保护的目的是确保由pod正在使用的PVC不会从系统中移除,因为如果被移除的话可能会导致数据丢失。
  • 注意:当pod状态为Pending并且pod已经分配给节点或pod为Running状态时,PVC处于活动状态。
  • 当启用PVC保护alpha功能时,如果用户删除了一个pod正在使用的PVC,则该PVC不会被立即删除。PVC的删除将被推迟,直到PVC不再被任何pod使用。

1.5. 持久化卷类型:

  • PersistentVolume类型以插件形式实现。Kubernetes目前支持以下插件类型:

    • GCEPersistentDiskAWSElasticBlockStoreAzureFileAzureDiskFC(Fibre Channel)
    • FlexVolumeFlockerNFSiSCSIRBD(Ceph Block Device)CephFS
    • Cinder(OpenStack block storage)GlusterfsVsphereVolumeQuobyte Volumes
    • HostPathVMware PhotonPortworx VolumesScalelo VolumesStorageos

1.6. PV的访问模式:

  • PersistentVolume可以以资源提供者支持的任何方式挂载到主机上。如下表所示,供应商具有不同的功能,每个PV的访问模式都将被设置为该卷支持的特定模式。例如,NFS可以支持多个读/写客户端,但特定的NFS PV可能以只读方式导出到服务器上。每个PV都有一套自己的用来描述特定功能的访问模式:

    • ReadWriteOnce一一允许一个Pod以读写模式访问PV。这是最常见的访问策略,适用于大多数应用程序
    • ReadOnlyMany一一允许多个Pod以只读模式访问同一个PV。这也是通过NFS实现的,但Pod只能读取共享目录,不能写入
    • ReadWriteMany一一允许多个Pod同时以读写模式访问同一个PV。这通常是通过网络文件系统(NFS)实现的,允许多个Pod在同一个共享目录上进行读写操作
  • 在命令行中,访问模式缩写为:

    • RWO--ReadWriteOnce
    • ROX--ReadOnlyMany
    • RWX--ReadWriteMany
  • 一个卷一次只能使用一种访问模式挂载,即使它支持很多访问模式。例如,GCEPersistentDisk可以由单个节点作为ReadWriteonce模式挂载,或由多个节点以ReadonlyMany模式挂载,但不能同时挂载
Volume插件ReadWriteOnceReadOnlyManyReadWriteMany
AWSElasticBlockStore--
AzureFile
AzureDisk--
CephFS
Cinder--
FC-
FlexVolume-
Flocker--
GCEPersistentDisk-
Glusterfs
HostPathVsphereVolume
iSCSI-
PhotonPersistentDisk--
Quobyte
NFS
RBD-
VsphereVolume--(当pod并列时有效)
Portworx Volumes-
ScalelO-
StorageOS--

1.7. PV的回收策略:

  • Retain(保留)一一手动回收
  • Recycle(回收)一一基本擦除(rm-rf/thevolume/*)
  • Delete(删除)一一关联的存储资产(例如AWS EBS、GCE PD、Azure Disk和OpenStack Cinder卷)将被刷除
  • 当前,只有NFS和HostPath支持回收策路。AWS EBS、GCE PD、Azure Disk和OpenStack Cinder卷支持删除策略

1.8. PV的状态

  • PV卷可以处于以下的某种状态:

    • Available(可用):PV 可以被 PersistentVolumeClaim(PVC)请求绑定
    • Bound(已绑定):PV 已经与 PVC 绑定,可以供 Pod 使用
    • Released(已释放):PVC 与 PV 的绑定关系已经解除,但是 PV 的底层存储资源尚未被清理。
    • Failed(失败):PV 创建或绑定过程中出现错误,无法使用。
  • 命令行会显示绑定到PV的PVC的名称

2. K8S+NFS静态存储模式

  • 静态存储:手动方式静态创建所需要的PV和PVC

2.1. 实例一:

2.1.1. 安装NFS服务

[root@localhost ~]# yum -y install nfs-common nfs-utils.x86_64 rpcbind.x86_64
//创建共享目录
[root@localhost ~]# mkdir /nfsdata
//修改权限
[root@localhost ~]# chmod 777 /nfsdata
[root@localhost ~]# chown nfsnobody /nfsdata/
//编辑/etc/exports文件
[root@localhost ~]# vim /etc/exports
/nfsdata *(rw,sync,no_root_squash,no_all_squash,sync)

//启动服务
[root@localhost ~]# systemctl start rpcbind.service && systemctl start nfs
//在挂载目录创建一个html文件
[root@localhost ~]# cd /nfsdata/
[root@localhost nfsdata]# echo "Hello World" >> index.html


//所有的K8S节点安装nfs客户端
yum -y install nfs-utils.x86_64 rpcbind.x86_64
//搜索网络中可用的共享文件
[root@master1 yaml]# showmount -e 192.168.2.50
Export list for 192.168.2.50:
/nfsdata *

2.1.2. 部署PV

vim  nfs-pv.yaml

apiVersion: v1  #指定 Kubernetes API 的版本
kind: PersistentVolume  #指定资源类型,这里是 PersistentVolume,表示持久卷
metadata:  #元数据部分,包含持久卷的名称等信息
  name: nfs-pv1  #指定pv的名称为nfs-pv1
spec:    #指定持久卷的详细规格
  capacity:  #指定持久卷的容量,这里是 10Gi
    storage: 10Gi
  accessModes:    #指定持久卷的访问模式,这里是 ReadWriteMany,表示多个 Pod 可以同时读写该持久卷
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain   #指定持久卷回收策略,这里是 Retain,表示在持久卷被释放后保留数据
  storageClassName: nfs  #指定持久卷的存储类名称,这里是 nfs
  nfs:     #指定 NFS 卷的相关配置
    path: /nfsdata  #指定 NFS 服务器上共享目录的路径,这里是 /nfsdata 
    server: 192.168.2.50  #指定 NFS 服务器的 IP 地址或主机名,这里是 192.168.2.50
    readOnly: false  #指定是否以只读模式挂载 NFS 卷,这里是 false,表示可读可写


//创建PV
[root@master1 yaml]# kubectl apply -f nfs-pv.yaml
persistentvolume/nfs-pv1 created
[root@master1 yaml]# kubectl get pv
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
nfs-pv1   1Gi        RWX            Retain           Available           nfs                     5s

2.1.3. 创建PVC

vim   pvc.yaml

apiVersion: v1    #指定使用的Kubernetes API版本
kind: PersistentVolumeClaim  #指定创建的资源类型为PVC
metadata:   #用于指定PVC的元数据,包括名称等
  name: nfs-pvc1  #指定PVC的名称为nfs-pvc1
spec:  #指定PVC的规格
  accessModes:   #指定PVC的访问模式。在这个示例中,设置为ReadWriteMany,表示可以同时被多个Pod以读写方式访问
    - ReadWriteMany  
  resources:  #用于指定PVC所需的资源
    requests:   #指定需要的存储容量
      storage: 1Gi  #设置PVC需要的存储容量为1GB
  storageClassName: nfs  #指定使用的存储类名称为nfs。存储类定义了存储的类型和配置


//创建pvc
[root@master1 pv]# kubectl apply -f pvc.yaml
persistentvolumeclaim/nfs-pvc1 created
//查看pvc的信息
[root@master1 pv]# kubectl get pvc
NAME       STATUS   VOLUME    CAPACITY   ACCESS MODES   STORAGECLASS   AGE
nfs-pvc1   Bound    nfs-pv1   10Gi       RWX            nfs            3s
//查看pv的信息
[root@master1 pv]# kubectl get pv
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM              STORAGECLASS   REASON   AGE
nfs-pv1   10Gi       RWX            Retain           Bound    default/nfs-pvc1   nfs                     2m24s

---可以看的出来pv和pvc已经绑定成功。

2.1.4. 使用deployment创建pod关联pvc

vim   nginx.deployment.yaml

apiVersion: apps/v1  #指定Deployment的API版本
kind: Deployment    #指定对象类型为Deployment
metadata:   #指定Deployment的元数据,包括名称等。
  name: nfs-nginx  #指定Deployment的名称
spec:   #指定 deployment 对象的配置信息
  replicas: 4   #指定需要运行的副本数,这里是 4
  selector:    #指定选择器,用于选择需要管理的 Pod
    matchLabels:  #匹配标签,这里是 app: my-nginx,表示选择具有 app=my-nginx 标签的Pod
      app: my-nginx
  template:   #指定 Pod 的模板,用于创建和管理 Pod
    metadata:  #指定Pod 元数据信息,包括标签等信息
      labels:   #Pod 标签,这里是 app: my-nginx
        app: my-nginx
    spec:       #指定Pod 配置信息
      containers:  #容器列表,这里只有一个 Nginx 容器
        - name: nfs-nginx  #指定容器名称
          image: nginx  #指定容器使用的镜像
          imagePullPolicy: IfNotPresent #镜像拉取策略:本地不存在镜像时才尝试拉取新镜像
          volumeMounts: #这是一个包含卷挂载配置的列表
            - name: nginx-html  #这是卷的名称需要和volume.name的内容一样
              mountPath: /usr/share/nginx/html/ #指定卷在容器内的挂载路径
      volumes:  #卷配置的列表
        - name: nginx-html #这是卷的名称,必须与 volumeMounts.name 中的内容相匹配
          persistentVolumeClaim:  #指定使用的持久卷声明
            claimName: nfs-pvc1  #指定pvc的名称
---
apiVersion: v1  #定义了Kubernetes API的版本,这里使用的是v1版本
kind: Service   #指定要创建的对象类型,这里是Service
metadata:    #指定Service的元数据,包括名称等
  name: nginx-service  #指定Service的名称
spec:   #指定 service对象的配置信息
  type: NodePort  #指定Service类型为NodePort
  selector:     #选择器,用于选择要关联的Pod
    app: my-nginx  #匹配具有指定标签的Pod
  ports:   #Service暴露的端口列表
    - name: http   #端口名称
      protocol: TCP  #端口协议
      port: 80  #Service的端口号
      targetPort: 80  #将流量转发到Pod的端口号
      nodePort: 30080  #节点端口,用于访问Service的端口


//创建
[root@master1 pv]# kubectl apply -f nginx.deployment.yaml
deployment.apps/nfs-nginx created
service/nginx-service created

//查看pod状态
[root@master1 pv]# kubectl get pod
NAME                         READY   STATUS    RESTARTS   AGE
nfs-nginx-78d5d6b9f5-m4zn2   1/1     Running   0          3s
nfs-nginx-78d5d6b9f5-m5kdb   1/1     Running   0          3s
nfs-nginx-78d5d6b9f5-wqjd4   1/1     Running   0          3s
nfs-nginx-78d5d6b9f5-z4nv4   1/1     Running   0          3s

//查看svc信息
[root@master1 pv]# kubectl get svc
NAME            TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
kubernetes      ClusterIP   10.10.0.1      <none>        443/TCP        6d4h
nginx-service   NodePort    10.10.76.216   <none>        80:30080/TCP   11s

//验证pod是否和pvc关联成功
[root@master1 pv]# curl 192.168.2.10:30080
Hello World      ---这个内容是在nfs服务器上创建的。

2.2. 实例二:

  • 清理实例一的操作,删除pvc、pv等。

2.2.1. 部署nfs服务:

[root@localhost ~]# yum -y install nfs-common nfs-utils.x86_64 rpcbind.x86_64
//创建共享目录
[root@localhost ~]# mkdir -p  /data/nfs{1..4}
[root@localhost ~]# ls /data/
nfs1  nfs2  nfs3  nfs4

//修改权限
[root@localhost ~]# chmod 777 /data/nfs1/  /data/nfs2/ /data/nfs3/ /data/nfs4/
[root@localhost ~]# chown nfsnobody /data/nfs1/  /data/nfs2/ /data/nfs3/ /data/nfs4/
[root@localhost ~]# ll /data/
total 0
drwxrwxrwx 2 nfsnobody root 6 Jun 23 21:33 nfs1
drwxrwxrwx 2 nfsnobody root 6 Jun 23 21:33 nfs2
drwxrwxrwx 2 nfsnobody root 6 Jun 23 21:33 nfs3
drwxrwxrwx 2 nfsnobody root 6 Jun 23 21:33 nfs4

//编辑/etc/exports文件
[root@localhost ~]# vim /etc/exports
/data/nfs1 *(rw,sync,no_root_squash,no_all_squash,sync)
/data/nfs2 *(rw,sync,no_root_squash,no_all_squash,sync)
/data/nfs3 *(rw,sync,no_root_squash,no_all_squash,sync)
/data/nfs4 *(rw,sync,no_root_squash,no_all_squash,sync)

//启动服务
[root@localhost ~]# systemctl restart rpcbind.service && systemctl restart nfs

//在挂载目录创建html文件
[root@localhost ~]# echo "aaaa" > /data/nfs1/index.html
[root@localhost ~]# echo "bbbb" > /data/nfs2/index.html
[root@localhost ~]# echo "cccc" > /data/nfs3/index.html
[root@localhost ~]# echo "dddd" > /data/nfs4/index.html


//所有的K8S节点安装nfs客户端
yum -y install nfs-utils.x86_64 rpcbind.x86_64

//搜索网络中可用的共享文件
[root@master1 ~]# showmount  -e 192.168.2.50
Export list for 192.168.2.50:
/data/nfs4 *
/data/nfs3 *
/data/nfs2 *
/data/nfs1 *

2.2.2. 部署PV

nfs-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv1
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  storageClassName: nfs
  nfs:
    path: /data/nfs1
    server: 192.168.2.50
    readOnly: false
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv2
spec:
  capacity:
    storage: 2Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  storageClassName: nfs
  nfs:
    path: /data/nfs2
    server: 192.168.2.50
    readOnly: false
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv3
spec:
  capacity:
    storage: 2Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  storageClassName: nfs
  nfs:
    path: /data/nfs3
    server: 192.168.2.50
    readOnly: false
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv4
spec:
  capacity:
    storage: 2Gi
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  storageClassName: nfs
  nfs:
    path: /data/nfs4
    server: 192.168.2.50
    readOnly: false

//创建pv
[root@master1 yaml]# kubectl apply -f nfs-pv.yaml
persistentvolume/nfs-pv1 created
persistentvolume/nfs-pv2 created
persistentvolume/nfs-pv3 created
persistentvolume/nfs-pv4 created

//查看pv状态
[root@master1 yaml]# kubectl get pv
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
nfs-pv1   5Gi        RWX            Retain           Available           nfs                     6s
nfs-pv2   2Gi        RWX            Retain           Available           nfs                     6s
nfs-pv3   2Gi        RWX            Retain           Available           nfs                     6s
nfs-pv4   2Gi        RWX            Retain           Available           nfs                     6s

2.2.3. 创建服务并使用PVC

vim  nginx-pvc-service.yaml

apiVersion: v1     #定义使用的Kubernetes API版本
kind: Service    #定义资源类型为Service
metadata:     #定义Service的元数据,包括名称
  name: nginx-service  #定义service的名称为nginx-service
spec:    #指定 service对象的配置信息
  selector:  #指定Pod的标签,用于将Service与Pod关联起来
    app: my-nginx    #匹配具有指定标签的Pod
  ports:    #Service暴露的端口列表
    - port: 80   #Service的端口号
      name: web  #端口名称
  clusterIP: None  #表示这是一个Headless Service,没有集群内部的虚拟IP(ClusterIP),只有DNS记录

---

apiVersion: apps/v1  #定义使用的Kubernetes API版本
kind: StatefulSet   #定义资源类型为StatefulSet
metadata:     #定义StatefulSet的元数据,包括名称
  name: my-nginx   #定义StatefulSet名称为my-nginx
spec:      #指定StatefulSet对象的配置信息
  selector:   #指定选择器,用于选择需要管理的 Pod
    matchLabels:  #匹配标签,这里是 app: my-nginx,表示选择具有 app=my-nginx 标签的Pod
      app: my-nginx
  serviceName: nginx-service   #指定关联的Service的名称
  replicas: 4   #定义StatefulSet中Pod的副本数量为4
  template:     #定义StatefulSet中Pod的模板,用于创建Pod 
    metadata:    #定义Pod的元数据,包括标签
      labels:    #Pod 标签,这里是 app: my-nginx
        app: my-nginx
    spec:    #定义Pod的规格
      containers:   #定义Pod中的容器,包括容器的名称、镜像、挂载的卷等
        - name: my-nginx  #定义容器名称
          image: nginx:latest  #定义容器使用的镜像
          imagePullPolicy: IfNotPresent #定义镜像拉取策略,IfNotPresent表示如果镜像已经存在就不再拉取
          volumeMounts:  #定义容器的挂载点
            - name: nginx-html  #挂载点的名称
              mountPath: /usr/share/nginx/html  #在容器内的挂载点路径
  volumeClaimTemplates:  #定义持久卷申请模板
    - metadata:    #持久卷申请模板的元数据,包括名称
        name: nginx-html  #持久卷申请模板的名称,与容器的挂载点名称匹配
      spec:  #持久卷申请模板的规范,包括访问模式、存储类和资源请求。
        accessModes:  #定义持久化卷的访问模式,ReadWriteMany表示可以被多个Pod同时读写,这个策略必须和PV的访问策略一样。
          - ReadWriteMany
        resources:   #定义持久化卷的资源请求,这里请求1Gi的存储空间,这里的请求空间不能比pv的空间大,可以相等。
          requests:
            storage: 1Gi
        storageClassName: nfs  #定义持久化卷的存储类名称,这里使用nfs存储类,这个需要和pv定义的存储类名称一样。


//创建:
[root@master1 yaml]# kubectl apply -f nginx-pvc-service.yaml

//查看pod创建情况
[root@master1 yaml]# kubectl get pod -o wide
NAME         READY   STATUS    RESTARTS   AGE   IP            NODE      NOMINATED NODE   READINESS GATES
my-nginx-0   1/1     Running   0          13m   10.244.1.54   node1     <none>           <none>
my-nginx-1   1/1     Running   0          13m   10.244.1.55   node1     <none>           <none>
my-nginx-2   1/1     Running   0          13m   10.244.3.15   master3   <none>           <none>
my-nginx-3   1/1     Running   0          13m   10.244.2.19   master2   <none>           <none>

//查看pvc创建情况:
[root@master1 yaml]# kubectl get pvc
NAME                    STATUS   VOLUME    CAPACITY   ACCESS MODES   STORAGECLASS   AGE
nginx-html-my-nginx-0   Bound    nfs-pv2   2Gi        RWX            nfs            25m
nginx-html-my-nginx-1   Bound    nfs-pv3   2Gi        RWX            nfs            25m
nginx-html-my-nginx-2   Bound    nfs-pv4   2Gi        RWX            nfs            25m
nginx-html-my-nginx-3   Bound    nfs-pv1   5Gi        RWX            nfs            25m


//验证:
[root@master1 yaml]# curl 10.244.1.54
bbbb
[root@master1 yaml]# curl 10.244.1.55
cccc

[root@master1 yaml]# curl 10.244.3.15
dddd

[root@master1 yaml]# curl 10.244.2.19
aaaa

2.2.4. 关于StatefulSet

  • 匹配Pod name(网络标识)的模式为:(StatefulSet名你)-(序号),比如上面的示例:my-nginx-0、my-nginx-1、my-nginx-2、my-nginx-3
[root@master1 yaml]# kubectl get pod -o wide
NAME         READY   STATUS    RESTARTS   AGE   IP            NODE      NOMINATED NODE   READINESS GATES
my-nginx-0   1/1     Running   0          13m   10.244.1.54   node1     <none>           <none>
my-nginx-1   1/1     Running   0          13m   10.244.1.55   node1     <none>           <none>
my-nginx-2   1/1     Running   0          13m   10.244.3.15   master3   <none>           <none>
my-nginx-3   1/1     Running   0          13m   10.244.2.19   master2   <none>           <none>
  • StatefulSet为每个Pod副本创建了一个DNS域名,这个域名的格式为:(podname).(headless server name),也就意味着服务间是通过Pod域名来通信而非Pod IP,因为当Pod所在Node发生故障时,Pod会飘逸到其它Nods上,Pod IP会发生变化,但是Pod域名不会有变化。

  • StatefulSet便用Headless服务来控制Pod的域名,这个域名的FQDN为:(servicename).(namespace).svc.cluster.local,其中,"cluster.local"指的是集群的域名。

[root@master1 pvc]# dig -t A nginx-service.default.svc.cluster.local. @10.244.0.14

; <<>> DiG 9.11.4-P2-RedHat-9.11.4-26.P2.el7_9.13 <<>> -t A nginx-service.default.svc.cluster.local. @10.244.0.14
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 56295
;; flags: qr aa rd; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;nginx-service.default.svc.cluster.local. IN A

;; ANSWER SECTION:
nginx-service.default.svc.cluster.local. 30 IN A 10.244.1.60
nginx-service.default.svc.cluster.local. 30 IN A 10.244.2.21
nginx-service.default.svc.cluster.local. 30 IN A 10.244.1.61
nginx-service.default.svc.cluster.local. 30 IN A 10.244.0.17

;; Query time: 35 msec
;; SERVER: 10.244.0.14#53(10.244.0.14)
;; WHEN: Sat Jun 24 03:15:44 CST 2023
;; MSG SIZE  rcvd: 288

  • 跟据volumeClaimTemplates,为每个Pod创建一个pvc,pvc的命名规则匹配模式:(volumeClaimTemplates.name)-(pod_name),比如上面的volumeMounts.name=nginx-html, Pod name=my-nginx-0-3,因此创建出来的PVC是nginx-html-my-nginx-0、nginx-html-my-nginx-1、nginx-html-my-nginx-2、nginx-html-my-nginx-3
[root@master1 pvc]# kubectl get  pvc
NAME                    STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
nginx-html-my-nginx-0   Bound    pvc-a27993f6-757b-4e8c-afe7-0ae4113b344c   1Gi        RWX            managed-nfs-storage   31m
nginx-html-my-nginx-1   Bound    pvc-bf387cc5-accd-4baf-8e6d-fc405f62f563   1Gi        RWX            managed-nfs-storage   31m
nginx-html-my-nginx-2   Bound    pvc-0fce0ac6-51b9-4ab7-940a-df853b39d4cd   1Gi        RWX            managed-nfs-storage   31m
nginx-html-my-nginx-3   Bound    pvc-e6312dfe-8803-4937-a10f-22cc37d998c1   1Gi        RWX            managed-nfs-storage   31m

  • 删除Pod不会脚除其PVC,手动删除pvc将自动释放PV

  • Statefulset的启停顺序:

    • 有序部署:部署StatefulSet时,如果有多个Pod副本,它们会被顺序地创建从(0到N-1)并且在下一个Pod运行之前所有之前的Pod须都是Runningl和Ready状态。
    • 有序删除:当Pod被删除时,它们被终止的顺序是从(N-1到0)。
    • 有序扩展:当对Pod执行扩展操作时,与部署一样,它前面的Pod必须都处于Running和Ready状态。

3. K8S+NFS动态存储模式

  • 动态存储: 通过创建PVC动态地创建对应PV,无需手动创建PV。

  • 动态创建持久卷(PV)的原理是通过使用动态存储类(StorageClass)和持久卷声明(PVC)来实现。

    • 动态存储类(StorageClass):动态存储类是定义存储插件和参数的对象。它指定了用于创建持久卷的存储插件、存储参数和其他选项。创建动态存储类时,Kubernetes将根据所定义的存储插件和参数创建持久卷。
    • 持久卷声明(PVC):持久卷声明是对所需存储资源的请求。它指定了所需的存储类、访问模式和存储大小。当创建一个持久卷声明后,Kubernetes将根据所指定的存储类和其他参数自动创建一个符合要求的持久卷。
  • 当创建一个持久卷声明时,Kubernetes将根据存储类的定义,与存储插件交互并动态创建一个持久卷。这样,无需手动创建和管理每个PV,而是根据需求自动创建符合要求的PV。这种动态创建的方式可以简化存储管理,并提高资源的利用率和灵活性。
    在这里插入图片描述

  • 使用StorageClass有什么好处呢?除了由存储系统动态创建,节省了管理员的时间,还有一个好处是可以封装不同类型的存储供PVC选用。

  • 在StorageClass出现以前,PVC绑定一个PV只能根据两个条件,一个是存储的大小,另一个是访问模式。在StorageClass出现后,等于增加了一个绑定维度。如下为动态PV存储操作方式:

3.1. 安装NFS服务:

[root@localhost ~]# yum -y install nfs-common nfs-utils.x86_64 rpcbind.x86_64

//创建共享目录
[root@localhost ~]# mkdir -p /data/nfs

//修改权限
[root@localhost ~]# chmod 777 /data/nfs
[root@localhost ~]# chown nfsnobody /data/nfs

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

//启动服务
[root@localhost ~]# systemctl start rpcbind.service && systemctl start nfs

//所有的K8S节点安装nfs客户端
yum -y install nfs-utils.x86_64 rpcbind.x86_64
//搜索网络中可用的共享文件
[root@master1 yaml]# showmount -e 192.168.2.50
Export list for 192.168.2.50:
/data/nfs *

3.2. 创建命名空间和动态存储类(StorageClass)

vim class.yaml

apiVersion: v1    #指定了所使用的Kubernetes API版本
kind: Namespace   #指定了对象的类型为Namespace
metadata:          #该部分包含了Namespace的元数据,如名称(name)等
  name: nfs   #指定了Namespace的名称为nfs
---
apiVersion: storage.k8s.io/v1    #指定了所使用的Kubernetes API版本
kind: StorageClass     #指定了对象的类型为StorageClass
metadata:     #该部分包含了存储类的元数据,如名称(name)等
  name: managed-nfs-storage    #指定存储类的名称,用于标识和引用该存储类
  namespace: nfs     #指定存储类所属的命名空间,这里是 nfs
  annotations:    #存储类的注解,用于添加附加信息
    storageclass.beta.kubernetes.io/is-default-class: 'true'  #表示这个存储类是否是默认的存储类,这里设置为 true
    storageclass.kubernetes.io/is-default-class: 'true'  #同上,这里同样设置为 true
provisioner: fuseim.pri/ifs  #指定了用于创建持久卷的存储插件。在这个示例中,使用的是fuseim.pri/ifs插件
reclaimPolicy: Retain    #指定持久卷的回收策略,这里设置为 Retain,表示在删除持久卷后保留数据
volumeBindingMode: Immediate  #定持久卷绑定模式,这里设置为 Immediate,表示立即绑定持久卷
parameters:  #这是存储插件的参数部分,用于配置插件的行为
  archiveOnDelete: "true"  #指定了当持久卷被删除时是否进行归档。"true"表示删除时进行归档


//创建动态存储类
[root@master1 pvc]# kubectl apply -f class.yaml
namespace/nfs created
storageclass.storage.k8s.io/managed-nfs-storage created

//查看命名空间是否创建成功
[root@master1 pvc]# kubectl get namespaces
NAME                   STATUS   AGE
default                Active   6d8h
kube-node-lease        Active   6d8h
kube-public            Active   6d8h
kube-system            Active   6d8h
kubernetes-dashboard   Active   6d4h
nfs                    Active   13s

//查看存储类是否创建成功
[root@master1 pvc]# kubectl get sc -n nfs
NAME                            PROVISIONER      RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
managed-nfs-storage (default)   fuseim.pri/ifs   Retain          Immediate           false                  28s

3.3. 创建RBAC权限:

vim rbac.yaml


apiVersion: v1   #指定了所使用的Kubernetes API版本
kind: ServiceAccount  #指定了对象的类型为ServiceAccount
metadata:     #该部分包含了ServiceAccount的元数据,如名称(name)等
  name: nfs-client-provisioner   #定义了ServiceAccount的名称
  namespace: nfs   # 指定服务账户所属的命名空间
---
kind: ClusterRole   #指定了对象的类型为ClusterRole
apiVersion: rbac.authorization.k8s.io/v1   #指定了所使用的Kubernetes API版本
metadata:   #该部分包含了集群角色的元数据,如名称(name)等
  name: nfs-client-provisioner-runner   #定义集群角色的名称
rules:    #定义了集群角色的权限规则
  - apiGroups: [""]    #资源所属的组,""表示核心API组
    resources: ["persistentvolumes"]   #定义了可以访问的资源为PV
    verbs: ["get", "list", "watch", "create", "delete"]  #定义了可以执行的操作,比如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     #指定了对象的类型ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1  #指定了所使用的Kubernetes API版本
metadata:   #该部分包含了集群角色绑定的元数据,如名称(name)等
  name: run-nfs-client-provisioner  #定义了集群角色绑定的名称
subjects:   #定义了角色绑定的主体,即与角色关联的服务账户
  - kind: ServiceAccount  #主体的类型,这里是ServiceAccount
    name: nfs-client-provisioner  #主体的名称,即之前定义的服务账户nfs-client-provisioner
    namespace: nfs  #主体所属的命名空间,与之前的服务账户相同
roleRef:   #定义了与角色绑定关联的角色
  kind: ClusterRole   #角色的类型,这里是ClusterRole
  name: nfs-client-provisioner-runner  #角色的名称,即之前定义的集群角色nfs-client-provisioner-runner
  apiGroup: rbac.authorization.k8s.io  #角色所属的API组,这里是rbac.authorization.k8s.io
---
kind: Role  #指定了对象的类型为Role
apiVersion: rbac.authorization.k8s.io/v1  #指定了所使用的Kubernetes API版本
metadata:    #该部分包含了Role的元数据,如名称(name)等
  name: leader-locking-nfs-client-provisioner  #定义了Role的名称
  namespace: nfs  #定义Role所属的命名空间
rules:   #定义了角色的权限规则,这里允许对endpoints资源进行操作
  - apiGroups: [""]     #资源所属的组,""表示核心API组
    resources: ["endpoints"]   #定义了可以访问的资源为endpoints
    verbs: ["get", "list", "watch", "create", "update", "patch"]   #定义了可以执行的操作,比如get、list、watch、create和patch
---
kind: RoleBinding   #指定了对象的类型为RoleBinding
apiVersion: rbac.authorization.k8s.io/v1  #指定了所使用的Kubernetes API版本
metadata:  #该部分包含了RoleBinding的元数据,如名称(name)等
  name: leader-locking-nfs-client-provisioner  #定义了RoleBinding的名称
  namespace: nfs  #角色绑定所属的命名空间,与之前的服务账户相同
subjects:   #定义了角色绑定的主体,即与角色关联的服务账户,与之前的角色绑定相同。
  - kind: ServiceAccount  
    name: nfs-client-provisioner
    namespace: nfs
roleRef:    #定义了与角色绑定关联的角色,与之前的角色相同
  kind: Role
  name: leader-locking-nfs-client-provisioner
  apiGroup: rbac.authorization.k8s.io


//创建:
[root@master1 pvc]# kubectl apply -f rbac.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

3.4. 部署NFS客户端供应程序

vim   nfs-deployment.yaml 

apiVersion: apps/v1   #这指定了使用的Kubernetes API版本。
kind: Deployment   #指定了对象的类型为deployment
metadata:   #指定了deployment的元数据,包含name,标签等。
  name: nfs-client-provisioner   #指定了deployment的名称
  labels:   #Deployment对象定义的标签为app: nfs-client-provisioner
    app: nfs-client-provisioner 
  namespace: nfs  #定义所属的命名空间为nfs
spec:   #指定deployment对象的配置信息
  replicas: 1   #指定需要运行的副本数,这里是1
  strategy:  #  这表示在更新Deployment时使用的策略是重新创建
    type: Recreate
  selector:   #指定选择器,用于选择需要管理的 Pod
    matchLabels:   #匹配标签,这里是nfs-client-provisioner,表示选择具有nfs-client-provisioner标签的Pod
      app: nfs-client-provisioner
  template:    #指定 Pod 的模板,用于创建和管理 Pod
    metadata:  #Pod 元数据信息,包括标签等信息
      labels:   #Pod 标签,这里是nfs-client-provisioner
        app: nfs-client-provisioner
    spec:   #Pod 配置信息
      serviceAccountName: nfs-client-provisioner  #这指定了Pod使用的服务账户
      containers:  #容器列表
        - name: nfs-client-provisioner  #指定容器名称
          image: quay.io/external_storage/nfs-client-provisioner:latest   #指定容器使用的镜像
          volumeMounts:  #这是一个包含卷挂载配置的列表
            - name: nfs-client-root  #卷的名称,必须和volumes.name一样
              mountPath: /persistentvolumes  #指定卷在容器内的挂载路径
          env:   #这是用于设置容器环境变量的名称和值。
            - name: PROVISIONER_NAME
              value: fuseim.pri/ifs
            - name: NFS_SERVER    #这是NFS服务器的IP地址
              value: 192.168.2.50
            - name: NFS_PATH   #这是NFS共享的路径
              value: /data/nfs
      volumes:  #卷配置的列表
        - name: nfs-client-root  #卷的名称,需和volumeMounts.name内容一样
          nfs:  #指定NFS服务器的IP地址和共享的路径
            server: 192.168.2.50
            path: /data/nfs

//创建:
[root@master1 pvc]# kubectl apply -f nfs-deployment.yaml
deployment.apps/nfs-client-provisioner created


[root@master1 pvc]# kubectl get pod -n nfs
NAME                                     READY   STATUS    RESTARTS   AGE
nfs-client-provisioner-65dbff946-xh6tj   1/1     Running   0          12m

3.5. 创建K8S POD案例,自动获取PV资源即可

vim  nfs-service-pod.yaml

apiVersion: v1  #指定使用的Kubernetes API版本
kind: Service  #指定对象类型为Service
metadata:   #指定service的元数据,包括名称和标签
  name: nginx-service  #指定service的名称
  labels:   #标签用于标识和选择相关的Pod
    app: my-nginx  
spec:  #Service的规范,包括端口和选择器
  ports:  #定义Service暴露的端口
  - port: 80  #服务将监听的端口号
    name: nginx  #端口的名称
  selector:   #选择器用于选择要与该Service关联的Pod
    app: my-nginx   #选择要与Service关联的Pod的标签
  clusterIP: None   #指定Service没有Cluster IP,这意味着该Service将不会被集群内部的其他服务访问
---
apiVersion: apps/v1   #指定使用的Kubernetes API版本
kind: StatefulSet    #指定对象类型为StatefulSet
metadata:     #对象的元数据,包括名称
  name: nginx-nfs  #指定对象的名称
spec:    #StatefulSet的规范,包括选择器、副本数和Pod模板
  selector:  #选择器用于选择要与该StatefulSet关联的Pod
    matchLabels:   #选择要与StatefulSet关联的Pod的标签
      app: my-nginx
  serviceName: "nginx-service"   #指定关联的Service的名称
  replicas: 4   #指定要创建的Pod副本数
  template:    #定义创建Pod的模板
    metadata:   #Pod模板的元数据,包括标签
      labels:   #Pod模板的标签,与StatefulSet的选择器匹配
        app: my-nginx   
    spec:    #Pod模板的规范,包括镜像、容器和持久卷
      containers:  #容器列表
      - name: nginx-nfs  #定义容器名称
        image: nginx  #定义容器使用的镜像
        ports:  #定义容器暴露的端口
        - containerPort: 80   #容器将监听的端口号
          name: web   #端口的名称
        volumeMounts:  #定义容器的挂载点
        - name: nginx-html  #挂载点的名称
          mountPath: /usr/share/nginx/html  #指定容器挂载点的路径
  volumeClaimTemplates:   #定义持久卷申请模板
  - metadata:   #持久卷申请模板的元数据,包括名称
      name: nginx-html   #持久卷申请模板的名称,与容器的挂载点名称匹配
    spec:   #持久卷申请模板的规范,包括访问模式、存储类和资源请求
      accessModes: [ "ReadWriteMany" ]   #指定持久卷的访问模式为多个读写
      storageClassName: "managed-nfs-storage"  #指定持久卷的存储类名称
      resources:   #指定持久卷的资源请求
        requests:  #指定存储资源的请求量
          storage: 1Gi   #指定存储资源的请求大小为1GB

//创建:
[root@master1 pvc]# kubectl apply -f nfs-service-pod.yaml
service/nginx-service created
statefulset.apps/nginx-nfs created

[root@master1 pvc]# kubectl get pod
NAME          READY   STATUS    RESTARTS   AGE
nginx-nfs-0   0/1     Pending   0          8m33s
  • 如果POD容器一直处于Pending状态,可以查看其LOG日志信息,报错信息假如为:Claim reference: selfLink was empty, can‘t make refere,解决方法:
    #在/etc/kubernetes/manifests/kube-apiserver.yaml配置文件中加入如下代码:
vim  /etc/kubernetes/manifests/kube-apiserver.yaml
...
- --feature-gates=RemoveSelfLink=false
...
//重新应用apiserver yaml文件
kubectl apply -f /etc/kubernetes/manifests/kube-apiserver.yaml
---假如是高可用集群需要每个master都修改apiserver的内容。

//查看pod创建是否成功:
[root@master1 manifests]# kubectl get pod
NAME          READY   STATUS    RESTARTS   AGE
nginx-nfs-0   1/1     Running   0          32m
nginx-nfs-1   1/1     Running   0          15m
nginx-nfs-2   1/1     Running   0          15m
nginx-nfs-3   1/1     Running   0          15m

//查看pvc信息:
[root@master1 manifests]# kubectl get pvc
NAME                     STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
nginx-html-nginx-nfs-0   Bound    pvc-378e7c94-a53d-4ad0-af36-29fb483b9ee3   1Gi        RWX            managed-nfs-storage   32m
nginx-html-nginx-nfs-1   Bound    pvc-6f39322d-3e7a-43a2-831b-aa07886ff132   1Gi        RWX            managed-nfs-storage   16m
nginx-html-nginx-nfs-2   Bound    pvc-1254fd7e-be8c-407f-8735-8ce2ba35562e   1Gi        RWX            managed-nfs-storage   16m
nginx-html-nginx-nfs-3   Bound    pvc-d5e3656f-26d3-4e5f-9696-60e6707e2e3f   1Gi        RWX            managed-nfs-storage   15m

//查看pv信息
[root@master1 manifests]# kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                            STORAGECLASS          REASON   AGE
pvc-1254fd7e-be8c-407f-8735-8ce2ba35562e   1Gi        RWX            Retain           Bound    default/nginx-html-nginx-nfs-2   managed-nfs-storage            16m
pvc-378e7c94-a53d-4ad0-af36-29fb483b9ee3   1Gi        RWX            Retain           Bound    default/nginx-html-nginx-nfs-0   managed-nfs-storage            16m
pvc-6f39322d-3e7a-43a2-831b-aa07886ff132   1Gi        RWX            Retain           Bound    default/nginx-html-nginx-nfs-1   managed-nfs-storage            16m
pvc-d5e3656f-26d3-4e5f-9696-60e6707e2e3f   1Gi        RWX            Retain           Bound    default/nginx-html-nginx-nfs-3   managed-nfs-storage            16m

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值