编辑
2023-06-12
K8S
00
请注意,本文编写于 590 天前,最后修改于 590 天前,其中某些信息可能已经过时。

目录

1.PV & PVC
2.基本使用
2.1创建 PV
2.2创建 PVC
2.3使用 PVC
3.动态供给
3.1 定义 NFS Provider
3.2 定义 StorageClass
3.3 使用 StorageClass 动态创建

Volume 提供了非常好的数据持久化方案,不过在可管理性上还有不足。前面 nfs 例子来说,要使用 Volume, Pod 必须事先知道以下信息:

  • 当前的 Volume 类型并明确 Volume 已经创建好。
  • 必须知道 Volume 的具体地址信息。

但是 Pod 通常是由应用的开发人员维护,而 Volume 则通常是由存储系统的管理员维护。开发人员要获得上面的信息,要么询问管理员,要么自己就是管理员。这样就带来一个管理上的问题:应用开发人员和系统管理员的职责耦合在一起了。如果系统规模较小或者对于开发环境,这样的情况还可以接受,当集群规模变大,特别是对于生产环境,考虑到效率和安全性,这就成了必须要解决的问题。

1.PV & PVC

Kubernetes 给出的解决方案是 Persistent Volume 和 Persistent Volume Claim

PersistentVolume(PV)是外部存储系统中的一块存储空间,由管理员创建和维护。与 Volume 一样,PV 具有持久性,生命周期独立于 Pod。

Persistent Volume Claim (PVC)是对 PV 的申请 (Claim)。PVC 通常由普通用户创建和维护。需要为 Pod 分配存储资源时,用户可以创建一个PVC,指明存储资源的容量大小和访问模式 (比如只读)等信息,Kubernetes 会查找并提供满足条件的 PV。有了 PersistentVolumeClaim,用户只需要告诉 Kubernetes 需要什么样的存储资源,而不必关心真正的空间从哪里分配、如何访问等底层细节信息。这些 Storage Provider 的底层信息交给管理员来处理,只有管理员才应该关心创建 PersistentVolume 的细节信息。

2.基本使用

2.1创建 PV

yml
apiVersion: v1 kind: PersistentVolume metadata: name: nfs-pv spec: capacity: storage: 1Gi #指定容量大小 accessModes: # 访问模式 - ReadWriteMany #这个PV能被多个节点以读写方式挂载,意味着这个PV可以被多个Pod挂载到多个节点上。 persistentVolumeReclaimPolicy: Retain #Retain:在 PVC 被删除后,保留 PV 和其数据,手动清理 PV 中的数据。 storageClassName: nfs nfs: path: /{nfs-server目录名称} server: {nfs-server IP 地址}
  • accessModes: 支持的访问模式有3种:

    • ReadWriteOnce 表示 PV 能以 readwrite 模式 mount 到单个节点
      • 这个PV只能被某个节点以读写方式挂载,意味着这个PV只能被一个Pod挂载到某个节点上,并且这个Pod可以对这个PV进行读写操作。如果尝试在其他节点上挂载这个PV,就会失败。
    • ReadOnlyMany 表示 PV 能以 read-only 模式 mount 到多个节点,
      • 这个PV能被多个节点以只读方式挂载,意味着这个PV可以被多个Pod挂载到多个节点上。
    • ReadWriteMany 表示 PV 能以 read-write 模式 mount 到多个节点。
      • 这个PV能被多个节点以读写方式挂载,意味着这个PV可以被多个Pod挂载到多个节点上。
  • persistentVolumeReclaimPolicy: 指定当 PV 的回收策略支持的策略有3种:

    • Retain:在 PVC 被删除后,保留 PV 和其数据,手动清理 PV 中的数据。

    • Delete:在 PVC 被删除后,自动删除 PV 和其数据。

    • Recycle:在 PVC 被删除后,通过删除 PV 中的数据来准备 PV 以供重新使用。

      值得注意的是,persistentVolumeReclaimPolicy 只适用于一些类型的 PV,如 NFS、HostPath、iSCSI 等。对于一些云平台提供的存储,如 AWS EBS 和 Azure Disk,由于底层提供商会自动处理 PV 的回收问题,因此该属性不适用。

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

2.2创建 PVC

yml
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: nfs-pvc spec: accessModes: - ReadWriteMany resources: requests: storage: 1Gi storageClassName: nfs # 通过名字进行选择 #selector: 通过标签形式 # matchLabels: # pv-name: nfs-pv

2.3使用 PVC

yml
apiVersion: v1 kind: Pod metadata: name: busybox-nfs spec: containers: - name: busybox image: busybox command: ["/bin/sh"] args: ["-c", "while true; do echo 'Hello NFS!' >> /data/index.html; sleep 1; done"] volumeMounts: - name: nfs-volume mountPath: /data volumes: - name: nfs-volume persistentVolumeClaim: claimName: nfs-pvc

image.png

3.动态供给

在前面的例子中,我们提前创建了PV,然后通过 PVC 申请 PV 并在Pod 中使用,这种方式叫作静态供给 ( Static Provision)与之对应的是动态供给 (Dynamical Provision),即如果没有满足PVC 条件的PV,会动态创建 PV。相比静态供给,动态供给有明显的优势:不需要提前创建 PV,减少了管理员 的工作量,效率高。动态供给是通过 StorageClass 实现的,StorageClass 定义了如何创建 PV,但需要注意的是每个 StorageClass 都有一个制备器(Provisioner),用来决定使用哪个卷插件制备 PV。 该字段必须指定。(https://kubernetes.io/zh-cn/docs/concepts/storage/storage-classes/) 才能实现动态创建,下面我们以 NFS 为例:

3.1 定义 NFS Provider

yml
apiVersion: apps/v1 kind: Deployment metadata: name: nfs-client-provisioner labels: app: nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: kube-system spec: replicas: 1 strategy: type: Recreate selector: matchLabels: app: nfs-client-provisioner template: metadata: labels: app: nfs-client-provisioner spec: serviceAccountName: nfs-client-provisioner containers: - name: nfs-client-provisioner image: chronolaw/nfs-subdir-external-provisioner:v4.0.2 volumeMounts: - name: nfs-client-root mountPath: /persistentvolumes env: - name: PROVISIONER_NAME value: k8s-sigs.io/nfs-subdir-external-provisioner - name: NFS_SERVER value: 192.168.24.131 - name: NFS_PATH value: /root/nfs/data volumes: - name: nfs-client-root nfs: server: 192.168.24.131 path: /root/nfs/data
yml
apiVersion: v1 kind: ServiceAccount metadata: name: nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: kube-system --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: nfs-client-provisioner-runner rules: - apiGroups: [""] resources: ["nodes"] verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["persistentvolumes"] verbs: ["get", "list", "watch", "create", "delete"] - apiGroups: [""] resources: ["persistentvolumeclaims"] verbs: ["get", "list", "watch", "update"] - apiGroups: ["storage.k8s.io"] resources: ["storageclasses"] verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["events"] verbs: ["create", "update", "patch"] --- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: run-nfs-client-provisioner subjects: - kind: ServiceAccount name: nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: kube-system roleRef: kind: ClusterRole name: nfs-client-provisioner-runner apiGroup: rbac.authorization.k8s.io --- kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: leader-locking-nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: kube-system rules: - apiGroups: [""] resources: ["endpoints"] verbs: ["get", "list", "watch", "create", "update", "patch"] --- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: leader-locking-nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: kube-system subjects: - kind: ServiceAccount name: nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: kube-system roleRef: kind: Role name: leader-locking-nfs-client-provisioner apiGroup: rbac.authorization.k8s.io

3.2 定义 StorageClass

yml
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: mysql-nfs-sc provisioner: k8s-sigs.io/nfs-subdir-external-provisioner parameters: onDelete: "remain"

名称要一致 image.png

3.3 使用 StorageClass 动态创建

yml
apiVersion: apps/v1 kind: StatefulSet metadata: name: mysql labels: app: mysql spec: serviceName: mysql #headless 无头服务 保证网络标识符唯一 必须存在 replicas: 1 template: metadata: name: mysql labels: app: mysql spec: containers: - name: mysql image: mysql/mysql-server:8.0 imagePullPolicy: IfNotPresent env: - name: MYSQL_ROOT_PASSWORD value: root volumeMounts: - mountPath: /var/lib/mysql #自己容器写入数据目录 name: data #保存到指定一个变量中 变量名字就是 data ports: - containerPort: 3306 restartPolicy: Always volumeClaimTemplates: #声明动态创建数据卷模板 - metadata: name: data # 数据卷变量名称 spec: accessModes: # 访问模式 - ReadWriteMany storageClassName: mysql-nfs-sc # 使用哪个 storage class 模板存储数据 resources: requests: storage: 2G selector: matchLabels: app: mysql

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

本文链接:

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

Document