您现在的位置是:首页 > 文章详情

Kubernetes 持久卷

日期:2021-05-08点击:265

Volume 卷

Container 中的文件在磁盘上是临时存放的,这给 Container 中运行的较重要的应用程序带来一些问题:

  • 1.当容器崩溃时,kubelet 会重新启动容器,但容器会以干净的状态重启,造成文件的丢失。
  • 2.Pod 中运行多个容器时,希望能在多个容器中共享文件。

因此 Kubernetes 使用了卷(Volume) 这一抽象概念能够来解决这两个问题。Kubernetes 支持下列类型的卷:

  • hostpath:将主机节点文件系统上的文件或目录挂载到你的 Pod 中。
  • emptyDir: 当 Pod 分派到某个 Node 上时,emptyDir 卷会被创建,并且在 Pod 在该节点上运行期间,卷一直存在。 就像其名称表示的那样,卷最初是空的。 Pod 中的多个容器可以共享 emptyDir 卷中的文件。 当 Pod 因为某些原因被从节点上删除时,emptyDir 卷中的数据也会被永久删除。 容器崩溃并不会导致 Pod 被从节点上移除,因此容器崩溃期间 emptyDir 卷中的数据是安全的。
  • Persistent Volume:persistentVolumeClaim 卷用来将持久卷(PersistentVolume) 挂载到 Pod 中。 持久卷申领(PersistentVolumeClaim)是用户在不知道特定云环境细节的情况下"申领"持久存储 (例如 NFS,iSCSI)的一种方法。

以上只是列举了其中一小部分支持的卷,具体可以查看: https://kubernetes.io/zh/docs/concepts/storage/volumes/#persistentvolumeclaim

Persistent Volume 持久卷

本文主要介绍持久卷的使用。Kubernetes 为了使开发人员能够在请求存储资源时,避免处理存储设施细节,引入了持久卷(PersistentVolume,PV) 和 持久卷申领(PersistentVolumeClaim,PVC):

  • 持久卷(PersistentVolume,PV 是集群中的一块存储,可以由管理员事先供应,或者 使用存储类(Storage Class)来动态供应。 持久卷是集群资源,就像节点也是集群资源一样。PV 持久卷和普通的 Volume 一样,也是使用 卷插件来实现的,只是它们拥有独立于任何使用 PV 的 Pod 的生命周期。 此 API 对象中记述了存储的实现细节,无论其背后是 NFS、iSCSI 还是特定于云平台的存储系统。
  • 持久卷申领(PersistentVolumeClaim,PVC 表达的是用户对存储的请求。概念上与 Pod 类似。 Pod 会耗用节点资源,而 PVC 申领会耗用 PV 资源。Pod 可以请求特定数量的资源(CPU 和内存);同样 PVC 申领也可以请求特定的大小和访问模式 (例如,可以要求 PV 卷能够以 ReadWriteOnce、ReadOnlyMany 或 ReadWriteMany 模式之一来挂载)。

创建 PV 有两种方式:

  • 静态供应:一种是集群管理员通过手动方式静态创建应用所需要的 PV。
  • 动态供应:
    • 方式一:用户手动创建 PVC 并由 Provisioner 组件动态创建对应的 PV。
    • 方式二:在创建 Pod 的时候使用 volumeClaimTemplates 声明。

PV 回收策略

  • 保留(Retain) 保留策略允许手动回收资源,当删除PVC的时候,PV仍然存在,变为Realease状态,需要用户手动通过以下步骤回收卷(只有hostPath和nfs支持Retain回收策略):
    • 1.删除PV。
    • 2.手动清理存储的数据资源。
  • 回收(Resycle) 该策略已废弃,推荐使用dynamic provisioning,回收策略会在 volume上执行基本擦除(rm -rf /thevolume/*),可被再次声明使用。
  • 删除(Delete)
    • 当发生删除操作的时候,会从 Kubernetes 集群中删除 PV 对象,并执行外部存储资源的删除操作(根据不同的provisioner 定义的删除逻辑不同,有的是重命名而不是删除)。
    • 动态配置的卷继承其 StorageClass 的回收策略,默认为Delete,即当用户删除 PVC 的时候,会自动执行 PV 的删除策略。

访问模式

访问模式有:

  • ReadWriteOnce -- 卷可以被一个节点以读写方式挂载;
  • ReadOnlyMany -- 卷可以被多个节点以只读方式挂载;
  • ReadWriteMany -- 卷可以被多个节点以读写方式挂载。

在命令行接口(CLI)中,访问模式也使用以下缩写形式:

  • RWO -- ReadWriteOnce
  • ROX -- ReadOnlyMany
  • RWX -- ReadWriteMany

每个卷只能同一时刻只能以一种访问模式挂载,即使该卷能够支持 多种访问模式。例如,一个 GCEPersistentDisk 卷可以被某节点以 ReadWriteOnce 模式挂载,或者被多个节点以 ReadOnlyMany 模式挂载,但不可以同时以两种模式挂载。

卷绑定模式

volumeBindingMode 字段控制了 PVC 和 PV 在什么时候进行绑定。

  • Immediate:表示一旦创建了 PVC 也就完成了卷绑定和动态制备。 对于由于拓扑限制而非集群所有节点可达的存储后端,PV 会在不知道 Pod 调度要求的情况下绑定或者制备。
  • WaitForFirstConsumer:该模式将延迟 PV 的绑定和制备,直到使用该 PVC 的 Pod 被创建。PV 会根据 Pod 调度约束指定的拓扑来选择或制备,包括但不限于 资源需求、 节点筛选器、 pod 亲和性和互斥性、 以及污点和容忍度。

静态供应

静态供应需要管理员手动创建 PV,然后创建 PVC 绑定 PV,最后创建 Pod 声明使用 PVC。

创建 PV

apiVersion: v1 kind: PersistentVolume metadata: name: task-pv-volume labels: type: local spec: storageClassName: manual #静态供应,名字可以任意取 capacity: storage: 10Gi accessModes: - ReadWriteOnce hostPath: path: "/mnt/data" #在创建pod的节点上会新建该目录 

创建 PVC

fapiVersion: v1 kind: PersistentVolumeClaim metadata: name: task-pv-claim spec: storageClassName: manual #storageClassName要和PV中的一致 accessModes: - ReadWriteOnce #accessMode要和PV中的一致 resources: requests: storage: 3Gi #申请3G容量,申请就近原则,如果有一个10G的和一个20G的PV满足要求,那么使用10G的PV 

创建 Pod 挂载 PV

apiVersion: v1 kind: Pod metadata: name: task-pv-pod spec: volumes: - name: task-pv-storage persistentVolumeClaim: claimName: task-pv-claim #使用的PVC的名字 containers: - name: task-pv-container image: nginx ports: - containerPort: 80 name: "http-server" volumeMounts: - mountPath: "/usr/share/nginx/html" #容器中挂载的目录 name: task-pv-storage 

在宿主机上的目录创建一个文件:

root@worker01:~# cd /mnt/data/ root@worker01:/mnt/data# echo "volume nginx" > index.html 

尝试访问 Pod 的服务,可以看到 nginx 的 index.html 文件已经被修改:

root@master01:~/yaml/volume# kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES task-pv-pod 1/1 Running 0 11m 192.168.5.17 worker01 <none> <none> root@master01:~/yaml/volume# curl 192.168.5.17 volume nginx 

删除要按照 Pod-->PVC-->PV 的顺序删除,如果先删除了 PVC 会等 Pod 删除掉,才会删除 PVC ,如果先删除了 PV,会等 pod 和 PVC 删除了才会删除 PV。

动态供应

动态卷供应允许按需创建存储卷。 如果没有动态供应,集群管理员必须手动地联系他们的云或存储提供商来创建新的存储卷, 然后在 Kubernetes 集群创建 PersistentVolume 对象来表示这些卷。 动态供应功能消除了集群管理员预先配置存储的需要。 相反,它在用户请求时自动供应存储。

安装 NFS

安装NFS服务端

root@master01:/# apt-get -y install nfs-kernel-server root@master01:/# systemctl enable nfs-kernel-server.service && systemctl restart nfs-kernel-server.service 

安装NFS客户端

在 worker 节点安装NFS客户端:

root@worker01:~# apt-get -y install nfs-common 

配置存储插件

配置RBAC

apiVersion: v1 kind: ServiceAccount metadata: name: nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: default --- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: nfs-client-provisioner-runner rules: - 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: default 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: default 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: default subjects: - kind: ServiceAccount name: nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: default roleRef: kind: Role name: leader-locking-nfs-client-provisioner apiGroup: rbac.authorization.k8s.io 

部署存储插件

动态卷供应的实现基于 storage.k8s.io API 组中的 StorageClass API 对象。 集群管理员可以根据需要定义多个 StorageClass 对象,每个对象指定一个存储插件(又名 provisioner),存储插件以 Pod 的形式存在于 Kubernetes 集群中:

apiVersion: apps/v1 kind: Deployment metadata: name: nfs-client-provisioner labels: app: nfs-client-provisioner # replace with namespace where provisioner is deployed namespace: default 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: quay.io/external_storage/nfs-client-provisioner:latest volumeMounts: - name: nfs-client-root mountPath: /persistentvolumes env: # 指定标识插件的值 - name: PROVISIONER_NAME value: fuseim.pri/ifs #匹配StorageClass的provisioner - name: NFS_SERVER value: 10.0.1.31 #NFS服务器的ip地址 - name: NFS_PATH value: /storage #NFS服务器的路径 volumes: - name: nfs-client-root nfs: server: 10.0.1.31 #NFS服务器的ip地址 path: /storage #NFS服务器的路径 

方式一:创建 PVC 自动申请 PV

配置 StorageClass

StorageClass 声明存储插件,用于自动创建 PV,provisioner 参数和存储插件的标识对应上才能动态供应卷 :

apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: managed-nfs-storage provisioner: fuseim.pri/ifs #要匹配nfs deployment env PROVISIONER_NAME的值,默认不支持nfs存储需要添加插件标识 parameters: archiveOnDelete: "false" 

创建 PVC

apiVersion: v1 kind: PersistentVolumeClaim metadata: name: nginx-pv-storage spec: accessModes: - ReadWriteMany storageClassName: managed-nfs-storage resources: requests: storage: 1Gi 

查看创建的 PVC 和 PV,可以看到我们只创建了 PVC,PV 是存储插件自动配置的

root@master01:~/yaml/storageClass# kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE nginx-pv-storage Bound pvc-e52ac960-182a-4065-a6e8-6957f5c93b8a 1Gi RWX managed-nfs-storage 3s root@master01:~/yaml/storageClass# kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pvc-e52ac960-182a-4065-a6e8-6957f5c93b8a 1Gi RWX Delete Bound default/nginx-test managed-nfs-storage 11s 

Pod 使用 PVC 申请 Volume:

apiVersion: v1 kind: Pod metadata: name: nginx-pv-pod spec: volumes: - name: nginx-pv-storage persistentVolumeClaim: claimName: nginx-test containers: - name: nginx-pv-container image: nginx ports: - containerPort: 80 name: "nginx-server" volumeMounts: - mountPath: "/usr/share/nginx/html" name: nginx-pv-storage 

方式二:volumeClaimTemplates

除了上面创建 PVC 自动创建 PV,然后 Pod 再声明使用 PVC 的方式以外,还有一个更简便的方法,就是使用 volumeClaimTemplates 直接指定 StorageClass 和 申请存储的大小,动态创建 PVC 和 PV:

apiVersion: apps/v1 kind: StatefulSet metadata: name: web spec: selector: matchLabels: app: nginx serviceName: "nginx" replicas: 2 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 name: web volumeMounts: - name: nginx-disk-ssd mountPath: /data volumeClaimTemplates: - metadata: name: nginx-disk-ssd spec: accessModes: [ "ReadWriteOnce" ] storageClassName: "managed-nfs-storage" #storageClass的名字 resources: requests: storage: 10Gi 

欢迎关注

原文链接:https://my.oschina.net/u/4923278/blog/5044278
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章