• kubernetes--数据存储


    目录

    一、数据存储引言:

    二、基础存储卷:

     1. emptyDir存储卷:

     2. hostPath存储卷:

     3. nfs共享存储卷:

      3.1 配置nfs:

      3.2 master节点编写yaml文件:

     4. 总结:

    三、PVC和PV:

     1. PV 的状态有以下 4 种:

     2. PV从创建到销毁的具体流程如下:

     3. pv定义的规格:

     4. PVC定义的规格:

     5. NFS使用静态PV和PVC:

      5.1. 配置nfs存储:

      5.2 定义PV:

      5.3 定义PVC:

    ​编辑

      5.4 测试访问:

     6. 动态 PV 创建:

     1. 动态pv的请求过程:

     2. 创建动态PV的过程:

     7. 实现 NFS 的动态 PV 创建:

      1. 在nfs节点上安装nfs,并配置nfs服务:

     2. 创建 Service Account:

     3. 使用 Deployment 来创建 NFS Provisioner:

     4. 创建 StorageClass:

     5. 创建PVC和Pod:

     6. 测试:


    一、数据存储引言:

    容器磁盘上的文件的生命周期是短暂的,这就使得在容器中运行重要应用时会出现一些问题。首先,当容器崩溃时,kubelet 会重启它,但是容器中的文件将丢失——容器以干净的状态(镜像最初的状态)重新启动。其次,在Pod中同时运行多个容器时,这些容器之间通常需要共享文件。Kubernetes 中的Volume抽象就很好的解决了这些问题。Pod中的容器通过Pause容器共享Volume。

    二、基础存储卷:

     1. emptyDir存储卷:

    当Pod被分配给节点时,首先创建emptyDir卷,并且只要该Pod在该节点上运行,该卷就会存在。正如卷的名字所述,它最初是空的。Pod 中的容器可以读取和写入emptyDir卷中的相同文件,尽管该卷可以挂载到每个容器中的相同或不同路径上。当出于任何原因从节点中删除 Pod 时,emptyDir中的数据将被永久删除。

    1. mkdir /opt/volumes
    2. cd /opt/volumes
    3. vim pod-emptydir.yaml
    4. apiVersion: v1
    5. kind: Pod
    6. metadata:
    7. name: pod-emptydir
    8. namespace: default
    9. labels:
    10. app: myapp
    11. tier: frontend
    12. spec:
    13. containers:
    14. - name: myapp
    15. image: ikubernetes/myapp:v1
    16. imagePullPolicy: IfNotPresent
    17. ports:
    18. - name: http
    19. containerPort: 80
    20. #定义容器挂载内容
    21. volumeMounts:
    22. #使用的存储卷名称,如果跟下面volume字段name值相同,则表示使用volume的这个存储卷
    23. - name: html
    24. #挂载至容器中哪个目录
    25. mountPath: /usr/share/nginx/html/
    26. - name: busybox
    27. image: busybox:latest
    28. imagePullPolicy: IfNotPresent
    29. volumeMounts:
    30. - name: html
    31. #在容器内定义挂载存储名称和挂载路径
    32. mountPath: /data/
    33. command: ['/bin/sh','-c','while true;do echo $(date) >> /data/index.html;sleep 2;done']
    34. #定义存储卷
    35. volumes:
    36. #定义存储卷名称
    37. - name: html
    38. #定义存储卷类型
    39. emptyDir: {}
    40. ##定义存储卷名为html,两个容器同时挂载存储卷,共享存储空间
    41. kubectl apply -f pod-emptydir.yaml
    42. kubectl get pods -o wide

     2. hostPath存储卷:

    hostPath卷将 node 节点的文件系统中的文件或目录挂载到集群中。
    hostPath可以实现持久存储,但是在node节点故障时,也会导致数据的丢失。

    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4. name: pod-hostpath
    5. namespace: default
    6. spec:
    7. containers:
    8. - name: nginx
    9. image: nginx
    10. volumeMounts:
    11. - name: html
    12. mountPath: /usr/share/nginx/html
    13. readOnly: false
    14. volumes:
    15. - name: html
    16. hostPath:
    17. path: /data/pod/volume1
    18. type: Directory

     3. nfs共享存储卷:

      3.1 配置nfs:

    1. //在新机器节点上安装nfs,并配置nfs服务
    2. mkdir /data/volumes -p
    3. chmod 777 /data/volumes
    4. vim /etc/exports
    5. /data/volumes 192.168.88.0/24(rw,no_root_squash)
    6. systemctl start rpcbind
    7. systemctl start nfs
    8. showmount -e

      3.2 master节点编写yaml文件:

    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4. name: pod-vol-nfs
    5. namespace: default
    6. spec:
    7. containers:
    8. - name: nginx01
    9. image: soscscs/myapp:v1
    10. volumeMounts:
    11. - name: html
    12. mountPath: /usr/share/nginx/html
    13. volumes:
    14. - name: html
    15. nfs:
    16. path: /data/volumes
    17. server: 192.168.88.105

     4. 总结:

    • emptydir:可实现Pod中的容器之间共享目录数据,但没有持久化数据的能力,存储卷会随着Pod生命周期结束而一起删除
    • hostPath:将node节点上的目录/文件挂载到Pod容器的指定目录/文件上,有持久化数据的能力,但只能在单个node节点上持久化数据,不能实现跨node节点的Pod共享数据
    • nfs:使用nfs服务将存储卷挂载到Pod容器的指定目录上,有持久化数据的能力,且也能实现跨node节点的Pod共享数据

    三、PVC和PV:

    • 上面介绍的PV和PVC模式是需要运维人员先创建好PV,然后开发人员定义好PVC进行一对一的Bond,但是如果PVC请求成千上万,那么就需要创建成千上万的PV,对于运维人员来说维护成本很高,Kubernetes提供一种自动创建PV的机制,叫StorageClass,它的作用就是创建PV的模板。
    • 创建 StorageClass 需要定义 PV 的属性,比如存储类型、大小等;另外创建这种 PV 需要用到的存储插件,比如 Ceph 等。 有了这两部分信息,Kubernetes 就能够根据用户提交的 PVC,找到对应的 StorageClass,然后 Kubernetes 就会调用 StorageClass 声明的存储插件,自动创建需要的 PV 并进行绑定。

     1. PV 的状态有以下 4 种:

    • Available(可用):表示可用状态,还未被任何 PVC 绑定
    • Bound(已绑定):表示 PV 已经绑定到 PVC
    • Released(已释放):表示 PVC 被删掉,但是资源尚未被集群回收
    • Failed(失败):表示该 PV 的自动回收失败

     2. PV从创建到销毁的具体流程如下:

    1. 一个PV创建完后状态会变成Available,等待被PVC绑定。
    2. 一旦被PVC邦定,PV的状态会变成Bound,就可以被定义了相应PVC的Pod使用。
    3. Pod使用完后会释放PV,PV的状态变成Released。
    4. 变成Released的PV会根据定义的回收策略做相应的回收工作。有三种回收策略,Retain、Delete和Recycle。Retain就是保留现场,K8S集群什么也不做,等待用户手动去处理PV里的数据,处理完后,再手动删除PV。Delete策略,K8S会自动删除该PV及里面的数据。Recycle方式,K8S会将PV里的数据删除,然后把PV的状态变成Available,又可以被新的PVC绑定使用。

     3. pv定义的规格:

    1. spec:
    2. nfs:(定义存储类型)
    3. path:(定义挂载卷路径)
    4. server:(定义服务器名称)
    5. accessModes:(定义访问模型,有以下三种访问模型,以列表的方式存在,也就是说可以定义多个访问模式)
    6. - ReadWriteOnce #(RWO)卷可以被一个节点以读写方式挂载。 ReadWriteOnce 访问模式也允许运行在同一节点上的多个 Pod 访问卷。
    7. - ReadOnlyMany #(ROX)卷可以被多个节点以只读方式挂载。
    8. - ReadWriteMany #(RWX)卷可以被多个节点以读写方式挂载。
    9. #nfs 支持全部三种;iSCSI 不支持 ReadWriteMany(iSCSI 就是在 IP 网络上运行 SCSI 协议的一种网络存储技术);HostPath 不支持 ReadOnlyMany 和 ReadWriteMany。
    10. capacity:(定义存储能力,一般用于设置存储空间)
    11. storage: 2Gi (指定大小)
    12. storageClassName: (自定义存储类名称,此配置用于绑定具有相同类别的PVC和PV)
    13. persistentVolumeReclaimPolicy: Retain #回收策略(Retain/Delete/Recycle)

    Retain(保留):当用户删除与之绑定的PVC时候,这个PV被标记为released(PVC与PV解绑但还没有执行回收策略)且之前的数据依然保存在该PV上,但是该PV不可用,需要手动来处理这些数据并删除该PV。
    Delete(删除):删除与PV相连的后端存储资源。对于动态配置的PV来说,默认回收策略为Delete。表示当用户删除对应的PVC时,动态配置的volume将被自动删除。(只有 AWS EBS, GCE PD, Azure Disk 和 Cinder 支持)
    Recycle(回收):如果用户删除PVC,则删除卷上的数据,卷不会删除。(只有 NFS 和 HostPath 支持)

     4. PVC定义的规格:

    PV和PVC中的spec关键字段要匹配,比如存储(storage)大小、访问模式(accessModes)、存储类名称(storageClassName)

    1. kubectl explain pvc.spec
    2. spec:
    3. accessModes: (定义访问模式,必须是PV的访问模式的子集)
    4. resources:
    5. requests:
    6. storage: (定义申请资源的大小)
    7. storageClassName: (定义存储类名称,此配置用于绑定具有相同类别的PVC和PV)

     5. NFS使用静态PV和PVC:

    1. 准备好存储设备和共享目录

    2. 准备yaml配置文件创建PV资源,设置 存储类型 访问模式(RWO RWX ROX RWOP) 空间大小 回收策略(Retain Delete Recycle) storageClassName等

    3. 准备yaml配置文件创建PVC资源,设置 访问模式(必要条件,必须是PV能支持的访问模式) 空间大小(默认就近选择大于等于指定大小的PV) storageClassName等来绑定PV

    4. 创建Pod资源挂载PVC存储卷,设置存储卷类型为 persistentVolumeClaim ,并在容器配置中定义存储卷挂载点目录

      5.1. 配置nfs存储:

    1. mkdir v{1,2,3,4,5}
    2. vim /etc/exports
    3. /data/volumes/v1 192.168.88.0/24(rw,no_root_squash)
    4. /data/volumes/v2 192.168.88.0/24(rw,no_root_squash)
    5. /data/volumes/v3 192.168.88.0/24(rw,no_root_squash)
    6. /data/volumes/v4 192.168.88.0/24(rw,no_root_squash)
    7. /data/volumes/v5 192.168.88.0/24(rw,no_root_squash)
    8. showmount -e

      5.2 定义PV:

    1. //这里定义5个PV,并且定义挂载的路径以及访问模式,还有PV划分的大小。
    2. vim pv-demo.yaml
    3. apiVersion: v1
    4. kind: PersistentVolume
    5. metadata:
    6. name: pv001
    7. labels:
    8. name: pv001
    9. spec:
    10. nfs:
    11. path: /data/volumes/v1
    12. server: 192.168.88.105
    13. accessModes: ["ReadWriteMany","ReadWriteOnce"]
    14. capacity:
    15. storage: 1Gi
    16. ---
    17. apiVersion: v1
    18. kind: PersistentVolume
    19. metadata:
    20. name: pv002
    21. labels:
    22. name: pv002
    23. spec:
    24. nfs:
    25. path: /data/volumes/v2
    26. server: 192.168.88.105
    27. accessModes: ["ReadWriteOnce"]
    28. capacity:
    29. storage: 2Gi
    30. ---
    31. apiVersion: v1
    32. kind: PersistentVolume
    33. metadata:
    34. name: pv003
    35. labels:
    36. name: pv003
    37. spec:
    38. nfs:
    39. path: /data/volumes/v3
    40. server: 192.168.88.105
    41. accessModes: ["ReadWriteMany","ReadWriteOnce"]
    42. capacity:
    43. storage: 2Gi
    44. ---
    45. apiVersion: v1
    46. kind: PersistentVolume
    47. metadata:
    48. name: pv004
    49. labels:
    50. name: pv004
    51. spec:
    52. nfs:
    53. path: /data/volumes/v4
    54. server: 192.168.88.105
    55. accessModes: ["ReadWriteMany","ReadWriteOnce"]
    56. capacity:
    57. storage: 4Gi
    58. ---
    59. apiVersion: v1
    60. kind: PersistentVolume
    61. metadata:
    62. name: pv005
    63. labels:
    64. name: pv005
    65. spec:
    66. nfs:
    67. path: /data/volumes/v5
    68. server: 192.168.88.105
    69. accessModes: ["ReadWriteMany","ReadWriteOnce"]
    70. capacity:
    71. storage: 5Gi
    1. kubectl apply -f pv-demo.yaml
    2. kubectl get pv

      5.3 定义PVC:

    这里定义了pvc的访问模式为多路读写,该访问模式必须在前面pv定义的访问模式之中。定义PVC申请的大小为2Gi,此时PVC会自动去匹配多路读写且大小为2Gi的PV,匹配成功获取PVC的状态即为Bound

    1. vim pod-vol-pvc.yaml
    2. apiVersion: v1
    3. kind: PersistentVolumeClaim
    4. metadata:
    5. name: mypvc
    6. namespace: default
    7. spec:
    8. accessModes: ["ReadWriteMany"]
    9. resources:
    10. requests:
    11. storage: 2Gi
    12. ---
    13. apiVersion: v1
    14. kind: Pod
    15. metadata:
    16. name: pod-vol-pvc
    17. namespace: default
    18. spec:
    19. containers:
    20. - name: myapp
    21. image: ikubernetes/myapp:v1
    22. volumeMounts:
    23. - name: html
    24. mountPath: /usr/share/nginx/html
    25. volumes:
    26. - name: html
    27. persistentVolumeClaim:
    28. claimName: mypvc
    1. kubectl apply -f pod-vol-pvc.yaml
    2. kubectl get pv,pvc

      5.4 测试访问:

    在存储服务器上创建index.html,并写入数据,通过访问Pod进行查看,可以获取到相应的页面。

    1. cd /data/volumes/v5/
    2. echo "welcome to use pv5" > index.html
    3. kubectl get pods -o wide
    4. curl ip

     6. 动态 PV 创建:

    Kubernetes 本身支持的动态 PV 创建不包括 NFS,所以需要使用外部存储卷插件分配PV。详见:

    https://kubernetes.io/zh/docs/concepts/storage/storage-classes/

    卷 插件称为 Provisioner(存储分配器),NFS 使用的是 nfs-client,这个外部卷插件会使用已经配置好的 NFS 服务器自动创建 PV。
    Provisioner:用于指定 Volume 插件的类型,包括内置插件(如 kubernetes.io/aws-ebs)和外部插件(如 external-storage 提供的 ceph.com/cephfs)。

     1. 动态pv的请求过程:

    Pod挂载pvc请求模板,pvc引用StorageClass资源,StorageClass通过不同的存储卷插件(Provisioner)动态分配不同存储类型的 pv 资源

     2. 创建动态PV的过程:

    1. 准备好存储设备和共享目录
    2. 如果是外置存储卷插件,需要先创建serviceaccount账户(Pod使用的账户)和做RBAC授权(创建角色授予相关资源对象的操作权限,再将账户与角色进行绑定),是的sa账户具有对PV PVC StorageClass等资源的操作权限
    3. 准备yaml配置文件创建外置存储卷插件的Pod,设置sa账户作为Pod的用户,并设置相关的环境变量(比如存储卷插件名称)
    4. 创建StorageClass(简称SC)资源,provisioner手动设置为存储卷插件名称 


     以上操作是一劳永逸的,之后只需要创建PVC资源时引用StorageClass就可以自动调用存储卷插件动态创建PV资源了 

    1. 准备yaml配置文件创建PVC资源,设置 访问模式 空间大小 storageClassName指定SC资源名称等来动态创建PV资源并绑定PV
    2. 创建Pod资源挂载PVC存储卷,设置存储卷类型为 persistentVolumeClaim ,并在容器配置中定义存储卷挂载点目录

     7. 实现 NFS 的动态 PV 创建:

      1. 在nfs节点上安装nfs,并配置nfs服务:

    1. mkdir /opt/k8s
    2. chmod 777 /opt/k8s/
    3. vim /etc/exports
    4. /opt/k8s 192.168.88.0/24(rw,no_root_squash,sync)
    5. systemctl restart nfs

     2. 创建 Service Account:

    创建 Service Account,用来管理 NFS Provisioner 在 k8s 集群中运行的权限,设置 nfs-client 对 PV,PVC,StorageClass 等的规则

    1. #创建 Service Account 账户,用来管理 NFS Provisioner 在 k8s 集群中运行的权限
    2. apiVersion: v1
    3. kind: ServiceAccount
    4. metadata:
    5. name: nfs-client-provisioner
    6. ---
    7. apiVersion: rbac.authorization.k8s.io/v1
    8. kind: ClusterRole
    9. metadata:
    10. name: nfs-client-provisioner-clusterrole
    11. rules:
    12. - apiGroups: [""]
    13. resources: ["persistentvolumes"]
    14. verbs: ["get", "list", "watch", "create", "delete"]
    15. - apiGroups: [""]
    16. resources: ["persistentvolumeclaims"]
    17. verbs: ["get", "list", "watch", "update"]
    18. - apiGroups: ["storage.k8s.io"]
    19. resources: ["storageclasses"]
    20. verbs: ["get", "list", "watch"]
    21. - apiGroups: [""]
    22. resources: ["events"]
    23. verbs: ["list", "watch", "create", "update", "patch"]
    24. - apiGroups: [""]
    25. resources: ["endpoints"]
    26. verbs: ["create", "delete", "get", "list", "watch", "patch", "update"]
    27. ---
    28. apiVersion: rbac.authorization.k8s.io/v1
    29. kind: ClusterRoleBinding
    30. metadata:
    31. name: nfs-client-provisioner-clusterrolebinding
    32. subjects:
    33. - kind: ServiceAccount
    34. name: nfs-client-provisioner
    35. namespace: default
    36. roleRef:
    37. kind: ClusterRole
    38. name: nfs-client-provisioner-clusterrole
    39. apiGroup: rbac.authorization.k8s.io

     3. 使用 Deployment 来创建 NFS Provisioner:

    NFS Provisioner(即 nfs-client),有两个功能:一个是在 NFS 共享目录下创建挂载点(volume),另一个则是将 PV 与 NFS 的挂载点建立关联。

     存储卷插件是以pod的方式部署在k8s集群中的,使用 Deployment 来创建 NFS Provisioner

    • 由于 1.20 版本启用了 selfLink,所以 k8s 1.20+ 版本通过 nfs provisioner 动态生成pv会报错,解决方法如下:

      如果是多master需要在每个节点配置,否则 provisioner Pod 会报错

    I1116 15:51:04.572876 1 controller.go:987] provision "default/mypvc-nfs" class "nfs-client-storageclass": started E1116 15:51:04.579547 1 controller.go:1004] provision "default/mypvc-nfs" class "nfs-client-storageclass": unexpected error getting claim reference: selfLink was empty, can't make reference

    1. vim /etc/kubernetes/manifests/kube-apiserver.yaml
    2. spec:
    3. containers:
    4. - command:
    5. - kube-apiserver
    6. - --feature-gates=RemoveSelfLink=false #添加这一行
    7. - --advertise-address=192.168.80.20
    8. ......
    9. kubectl apply -f /etc/kubernetes/manifests/kube-apiserver.yaml
    10. kubectl delete pods kube-apiserver -n kube-system
    11. kubectl get pods -n kube-system | grep apiserver
    12. 或者直接移动kube-apiserver.yaml到上层目录,过一段时间在移动回来
    •    创建 NFS Provisioner
    1. vim nfs-client-provisioner.yaml
    2. kind: Deployment
    3. apiVersion: apps/v1
    4. metadata:
    5. name: nfs-client-provisioner
    6. spec:
    7. replicas: 1
    8. selector:
    9. matchLabels:
    10. app: nfs-client-provisioner
    11. strategy:
    12. type: Recreate
    13. template:
    14. metadata:
    15. labels:
    16. app: nfs-client-provisioner
    17. spec:
    18. serviceAccountName: nfs-client-provisioner #指定Service Account账户
    19. containers:
    20. - name: nfs-client-provisioner
    21. image: quay.io/external_storage/nfs-client-provisioner:latest
    22. imagePullPolicy: IfNotPresent
    23. volumeMounts:
    24. - name: nfs-client-root
    25. mountPath: /persistentvolumes
    26. env:
    27. - name: PROVISIONER_NAME
    28. value: nfs-storage #配置provisioner的Name,确保该名称与StorageClass资源中的provisioner名称保持一致
    29. - name: NFS_SERVER
    30. value: stor01 #配置绑定的nfs服务器
    31. - name: NFS_PATH
    32. value: /opt/k8s #配置绑定的nfs服务器目录
    33. volumes: #申明nfs数据卷
    34. - name: nfs-client-root
    35. nfs:
    36. server: stor01
    37. path: /opt/k8s

     4. 创建 StorageClass:

    负责建立 PVC 并调用 NFS provisioner 进行预定的工作,并让 PV 与 PVC 建立关联

    1. vim nfs-client-storageclass.yaml
    2. apiVersion: storage.k8s.io/v1
    3. kind: StorageClass
    4. metadata:
    5. name: nfs-client-storageclass
    6. provisioner: nfs-storage #这里的名称要和provisioner配置文件中的环境变量PROVISIONER_NAME保持一致
    7. parameters:
    8. archiveOnDelete: "false" #false表示在删除PVC时不会对数据目录进行打包存档,即删除数据;为ture时就会自动对数据目录进行打包存档,存档文件以archived开头
    9. kubectl apply -f nfs-client-storageclass.yaml

     5. 创建PVC和Pod:

    1. vim test-pvc-pod.yaml
    2. apiVersion: v1
    3. kind: PersistentVolumeClaim
    4. metadata:
    5. name: test-nfs-pvc
    6. #annotations: volume.beta.kubernetes.io/storage-class: "nfs-client-storageclass" #另一种SC配置方式
    7. spec:
    8. accessModes:
    9. - ReadWriteMany
    10. storageClassName: nfs-client-storageclass #关联StorageClass对象
    11. resources:
    12. requests:
    13. storage: 1Gi
    14. ---
    15. apiVersion: v1
    16. kind: Pod
    17. metadata:
    18. name: test-storageclass-pod
    19. spec:
    20. containers:
    21. - name: busybox
    22. image: busybox:latest
    23. imagePullPolicy: IfNotPresent
    24. command:
    25. - "/bin/sh"
    26. - "-c"
    27. args:
    28. - "sleep 3600"
    29. volumeMounts:
    30. - name: nfs-pvc
    31. mountPath: /mnt
    32. restartPolicy: Never
    33. volumes:
    34. - name: nfs-pvc
    35. persistentVolumeClaim:
    36. claimName: test-nfs-pvc #与PVC名称保持一致
    37. kubectl apply -f test-pvc-pod.yaml

     6. 测试:

    1. PVC 通过 StorageClass 自动申请到空间
    2. kubectl get pvc
    3. //进入 Pod 在挂载目录 /mnt 下写一个文件,然后查看 NFS 服务器上是否存在该文件
    4. kubectl exec -it test-storageclass-pod sh
    5. / # cd /mnt/
    6. /mnt # echo 'this is test file' > test.txt
    7. //发现 NFS 服务器上存在,说明验证成功
    8. cat /opt/k8s/test.txt

  • 相关阅读:
    FPGA——用VGA时序显示图像(3)(代码)
    “熊猫视图”.Net图形控件功能介绍 [三]:前景层与背景层
    大二学生基于Html+Css+javascript的网页制作——动漫设计公司响应式网站模板 (10个页面)
    sqli-labs注入方法总结
    计算方法/数值分析 期末复习整理
    SpringCloud Alibaba学习
    linux安装CUDA、cuDNN以及ytorch-gpu
    GEE教程——利用Global 4-class PALSAR-2/PALSAR Forest数据提取指定区域的森林和影像下载
    Flutter高仿微信-第57篇-添加好友
    nn.LayerNorm详解+代码演示
  • 原文地址:https://blog.csdn.net/2301_78106979/article/details/134430437