Kubernetes(k8s)存储管理之数据卷volumes(四):持久卷Persistent Volume

一.系统环境

服务器版本 docker软件版本 Kubernetes(k8s)集群版本 CPU架构
CentOS Linux release 7.4.1708 (Core) Docker version 20.10.12 v1.21.9 x86_64

Kubernetes集群架构:k8scloude1作为master节点,k8scloude2,k8scloude3作为worker节点

服务器 操作系统版本 CPU架构 进程 功能描述
k8scloude1/192.168.110.130 CentOS Linux release 7.4.1708 (Core) x86_64 docker,kube-apiserver,etcd,kube-scheduler,kube-controller-manager,kubelet,kube-proxy,coredns,calico k8s master节点
k8scloude2/192.168.110.129 CentOS Linux release 7.4.1708 (Core) x86_64 docker,kubelet,kube-proxy,calico k8s worker节点
k8scloude3/192.168.110.128 CentOS Linux release 7.4.1708 (Core) x86_64 docker,kubelet,kube-proxy,calico k8s worker节点

二.前言

Kubernetes(k8s)数据卷volumes类型众多,本文介绍数据卷volumes之一持久卷Persistent Volume

使用数据卷volumes的前提是已经有一套可以正常运行的Kubernetes集群,关于Kubernetes(k8s)集群的安装部署,可以查看博客《Centos7 安装部署Kubernetes(k8s)集群》https://www.cnblogs.com/renshengdezheli/p/16686769.html

三.持久卷(Persistent Volume)

3.1 持久卷(Persistent Volume)概览

存储的管理是一个与计算实例的管理完全不同的问题。 PersistentVolume 子系统为用户和管理员提供了一组 API, 将存储如何制备的细节从其如何被使用中抽象出来。 为了实现这点,我们引入了两个新的 API 资源:PersistentVolume 和 PersistentVolumeClaim。

持久卷(PersistentVolume,PV) 是集群中的一块存储,可以由管理员事先制备, 或者使用存储类(Storage Class)来动态制备。 持久卷是集群资源,就像节点也是集群资源一样。PV 持久卷和普通的 Volume 一样, 也是使用卷插件来实现的,只是它们拥有独立于任何使用 PV 的 Pod 的生命周期。 此 API 对象中记述了存储的实现细节,无论其背后是 NFS、iSCSI 还是特定于云平台的存储系统。

持久卷申领(PersistentVolumeClaim,PVC) 表达的是用户对存储的请求。概念上与 Pod 类似。 Pod 会耗用节点资源,而 PVC 申领会耗用 PV 资源。Pod 可以请求特定数量的资源(CPU 和内存);同样 PVC 申领也可以请求特定的大小和访问模式 (例如,可以要求 PV 卷能够以 ReadWriteOnce、ReadOnlyMany 或 ReadWriteMany 模式之一来挂载)。

尽管 PersistentVolumeClaim 允许用户消耗抽象的存储资源, 常见的情况是针对不同的问题用户需要的是具有不同属性(如,性能)的 PersistentVolume 卷。 集群管理员需要能够提供不同性质的 PersistentVolume, 并且这些 PV 卷之间的差别不仅限于卷大小和访问模式,同时又不能将卷是如何实现的这些细节暴露给用户。 为了满足这类需求,就有了存储类(StorageClass) 资源。

3.2 持久卷和持久卷申领的生命周期

PV 卷是集群中的资源。PVC 申领是对这些资源的请求,也被用来执行对资源的申领检查。 PV 卷和 PVC 申领之间的互动遵循如下生命周期:
PV 卷的创建有两种方式:

  • 静态制备:集群管理员创建若干 PV 卷。这些卷对象带有真实存储的细节信息, 并且对集群用户可用。PV 卷对象存在于 Kubernetes API 中,可供用户消费(使用)。
  • 动态制备:如果管理员所创建的所有静态 PV 卷都无法与用户的 PersistentVolumeClaim 匹配, 集群可以尝试为该 PVC 申领动态制备一个存储卷。 这一制备操作是基于 StorageClass 来实现的:PVC 申领必须请求某个 存储类, 同时集群管理员必须已经创建并配置了该类,这样动态制备卷的动作才会发生。 如果 PVC 申领指定存储类为 "",则相当于为自身禁止使用动态制备的卷。

为了基于存储类完成动态的存储制备,集群管理员需要在 API 服务器上启用 DefaultStorageClass 准入控制器。 举例而言,可以通过保证 DefaultStorageClass 出现在 API 服务器组件的 --enable-admission-plugins 标志值中实现这点;该标志的值可以是逗号分隔的有序列表。
用户创建一个带有特定存储容量和特定访问模式需求的 PersistentVolumeClaim 对象; 在动态制备场景下,这个 PVC 对象可能已经创建完毕。 主控节点中的控制回路监测新的 PVC 对象,寻找与之匹配的 PV 卷(如果可能的话), 并将二者绑定到一起。 如果为了新的 PVC 申领动态制备了 PV 卷,则控制回路总是将该 PV 卷绑定到这一 PVC 申领。 否则,用户总是能够获得他们所请求的资源,只是所获得的 PV 卷可能会超出所请求的配置。 一旦绑定关系建立,则 PersistentVolumeClaim 绑定就是排他性的, 无论该 PVC 申领是如何与 PV 卷建立的绑定关系。 PVC 申领与 PV 卷之间的绑定是一种一对一的映射,实现上使用 ClaimRef 来记述 PV 卷与 PVC 申领间的双向绑定关系。

如果找不到匹配的 PV 卷,PVC 申领会无限期地处于未绑定状态。 当与之匹配的 PV 卷可用时,PVC 申领会被绑定。 例如,即使某集群上制备了很多 50 Gi 大小的 PV 卷,也无法与请求 100 Gi 大小的存储的 PVC 匹配。当新的 100 Gi PV 卷被加入到集群时, 该 PVC 才有可能被绑定。
Pod 将 PVC 申领当做存储卷来使用。集群会检视 PVC 申领,找到所绑定的卷, 并为 Pod 挂载该卷。对于支持多种访问模式的卷, 用户要在 Pod 中以卷的形式使用申领时指定期望的访问模式。

一旦用户有了申领对象并且该申领已经被绑定, 则所绑定的 PV 卷在用户仍然需要它期间一直属于该用户。 用户通过在 Pod 的 volumes 块中包含 persistentVolumeClaim 节区来调度 Pod,访问所申领的 PV 卷。
保护使用中的存储对象(Storage Object in Use Protection) 这一功能特性的目的是确保仍被 Pod 使用的 PersistentVolumeClaim(PVC) 对象及其所绑定的 PersistentVolume(PV)对象在系统中不会被删除,因为这样做可能会引起数据丢失。

说明: 当使用某 PVC 的 Pod 对象仍然存在时,认为该 PVC 仍被此 Pod 使用。
如果用户删除被某 Pod 使用的 PVC 对象,该 PVC 申领不会被立即移除。 PVC 对象的移除会被推迟,直至其不再被任何 Pod 使用。 此外,如果管理员删除已绑定到某 PVC 申领的 PV 卷,该 PV 卷也不会被立即移除。 PV 对象的移除也要推迟到该 PV 不再绑定到 PVC。

你可以看到当 PVC 的状态为 Terminating 且其 Finalizers 列表中包含 kubernetes.io/pvc-protection 时,PVC 对象是处于被保护状态的。

3.3 持久卷的类型

PV 持久卷是用插件的形式来实现的。Kubernetes 目前支持以下插件:

cephfs - CephFS volume
csi - 容器存储接口 (CSI)
fc - Fibre Channel (FC) 存储
hostPath - HostPath 卷 (仅供单节点测试使用;不适用于多节点集群;请尝试使用 local 卷作为替代)
iscsi - iSCSI (SCSI over IP) 存储
local - 节点上挂载的本地存储设备
nfs - 网络文件系统 (NFS) 存储
rbd - Rados 块设备 (RBD) 卷

3.4 持久卷的回收策略persistentVolumeReclaimPolicy

当用户不再使用其存储卷时,他们可以从 API 中将 PVC 对象删除, 从而允许该资源被回收再利用。PersistentVolume 对象的回收策略告诉集群, 当其被从申领中释放时如何处理该数据卷。 目前,数据卷可以被 Retained(保留)、Recycled(回收)或 Deleted(删除)。

保留(Retain):回收策略 Retain 使得用户可以手动回收资源。当 PersistentVolumeClaim 对象被删除时,PersistentVolume 卷仍然存在,对应的数据卷被视为"已释放(released)"。 由于卷上仍然存在这前一申领人的数据,该卷还不能用于其他申领。 管理员可以通过下面的步骤来手动回收该卷:

删除 PersistentVolume 对象。与之相关的、位于外部基础设施中的存储资产 (例如 AWS EBS、GCE PD、Azure Disk 或 Cinder 卷)在 PV 删除之后仍然存在。根据情况,手动清除所关联的存储资产上的数据。手动删除所关联的存储资产。如果你希望重用该存储资产,可以基于存储资产的定义创建新的 PersistentVolume 卷对象。

删除(Delete):对于支持 Delete 回收策略的卷插件,删除动作会将 PersistentVolume 对象从 Kubernetes 中移除,同时也会从外部基础设施(如 AWS EBS、GCE PD、Azure Disk 或 Cinder 卷)中移除所关联的存储资产。 动态制备的卷会继承其 StorageClass 中设置的回收策略, 该策略默认为 Delete。管理员需要根据用户的期望来配置 StorageClass; 否则 PV 卷被创建之后必须要被编辑或者修补。 参阅更改 PV 卷的回收策略。

回收(Recycle):警告: 回收策略 Recycle 已被废弃。取而代之的建议方案是使用动态制备。如果下层的卷插件支持,回收策略 Recycle 会在卷上执行一些基本的擦除 (rm -rf /thevolume/*)操作,之后允许该卷用于新的 PVC 申领。

简言之:

  • Retain -- 手动回收
  • Recycle -- 基本擦除 (rm -rf /thevolume/*)
  • Delete -- 诸如 AWS EBS、GCE PD、Azure Disk 或 OpenStack Cinder 卷这类关联存储资产也被删除,目前,仅 NFS 和 HostPath 支持回收(Recycle)。 AWS EBS、GCE PD、Azure Disk 和 Cinder 卷都支持删除(Delete)。

3.5 卷模式volumeMode

针对 PV 持久卷,Kubernetes 支持两种卷模式(volumeModes):Filesystem(文件系统) 和 Block(块)。 volumeMode 是一个可选的 API 参数。 如果该参数被省略,默认的卷模式是 Filesystem。

volumeMode 属性设置为 Filesystem 的卷会被 Pod 挂载(Mount) 到某个目录。 如果卷的存储来自某块设备而该设备目前为空,Kuberneretes 会在第一次挂载卷之前在设备上创建文件系统。

你可以将 volumeMode 设置为 Block,以便将卷作为原始块设备来使用。 这类卷以块设备的方式交给 Pod 使用,其上没有任何文件系统。 这种模式对于为 Pod 提供一种使用最快可能方式来访问卷而言很有帮助, Pod 和卷之间不存在文件系统层。另外,Pod 中运行的应用必须知道如何处理原始块设备。

3.6 访问模式 accessModes

PersistentVolume 卷可以用资源提供者所支持的任何方式挂载到宿主系统上。 如下表所示,提供者(驱动)的能力不同,每个 PV 卷的访问模式都会设置为对应卷所支持的模式值。 例如,NFS 可以支持多个读写客户,但是某个特定的 NFS PV 卷可能在服务器上以只读的方式导出。 每个 PV 卷都会获得自身的访问模式集合,描述的是特定 PV 卷的能力。

访问模式accessModes有:

  • ReadWriteOnce:卷可以被一个节点以读写方式挂载。 ReadWriteOnce 访问模式也允许运行在同一节点上的多个 Pod 访问卷。
  • ReadOnlyMany:卷可以被多个节点以只读方式挂载。
  • ReadWriteMany:卷可以被多个节点以读写方式挂载。
  • ReadWriteOncePod:卷可以被单个 Pod 以读写方式挂载。 如果你想确保整个集群中只有一个 Pod 可以读取或写入该 PVC, 请使用 ReadWriteOncePod 访问模式。这只支持 CSI 卷以及需要 Kubernetes 1.22 以上版本。

说明:Kubernetes 使用卷访问模式来匹配 PersistentVolumeClaim 和 PersistentVolume。 在某些场合下,卷访问模式也会限制 PersistentVolume 可以挂载的位置。 卷访问模式并不会在存储已经被挂载的情况下为其实施写保护。 即使访问模式设置为 ReadWriteOnce、ReadOnlyMany 或 ReadWriteMany,它们也不会对卷形成限制。 例如,即使某个卷创建时设置为 ReadOnlyMany,也无法保证该卷是只读的。 如果访问模式设置为 ReadWriteOncePod,则卷会被限制起来并且只能挂载到一个 Pod 上。

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

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

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

3.7 存储类storageClass

每个 PV 可以属于某个类(Class),通过将其 storageClassName 属性设置为某个 StorageClass 的名称来指定。 特定类的 PV 卷只能绑定到请求该类存储卷的 PVC 申领。 未设置 storageClassName 的 PV 卷没有类设定,只能绑定到那些没有指定特定存储类的 PVC 申领。

早前,Kubernetes 使用注解 volume.beta.kubernetes.io/storage-class 而不是 storageClassName 属性。这一注解目前仍然起作用,不过在将来的 Kubernetes 发布版本中该注解会被彻底废弃。

3.8 持久卷状态PersistentVolume status

持久卷状态PersistentVolume status如下:

[root@k8scloude1 volume]# kubectl get pv
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS     CLAIM          STORAGECLASS   REASON   AGE
pv007   5Gi        RWO            Recycle          Released   volume/mypvc   secret                  75m

每个pv卷会处于以下状态之一

  • Available(可用)-- 卷是一个空闲资源,尚未绑定到任何申领;
  • Bound(已绑定)-- 该卷已经绑定到某申领;
  • Released(已释放)-- 所绑定的申领已被删除,但是资源尚未被集群回收;
  • Failed(失败)-- 卷的自动回收操作失败。

命令行接口能够显示绑定到某 PV 卷的 PVC 对象(CLAIM字段)。

pv全局有效,不限于某个namespace

四.持久卷申领PersistentVolumeClaim(PVC)

每个 PVC 对象都有 spec 和 status 部分,分别对应申领的规约和状态。 PersistentVolumeClaim 对象的名称必须是合法的 DNS 子域名。

访问模式:申领在请求具有特定访问模式的存储时,使用与卷相同的访问模式约定。

卷模式:申领使用与卷相同的约定来表明是将卷作为文件系统还是块设备来使用。

资源:申领和 Pod 一样,也可以请求特定数量的资源。在这个上下文中,请求的资源是存储。 卷和申领都使用相同的 资源模型。

选择算符:申领可以设置标签选择算符 来进一步过滤卷集合。只有标签与选择算符相匹配的卷能够绑定到申领上。 选择算符包含两个字段:

  • matchLabels - 卷必须包含带有此值的标签
  • matchExpressions - 通过设定键(key)、值列表和操作符(operator) 来构造的需求。合法的操作符有 In、NotIn、Exists 和 DoesNotExist。

来自 matchLabels 和 matchExpressions 的所有需求都按逻辑与的方式组合在一起。 这些需求都必须被满足才被视为匹配。

存储类storageClass:申领可以通过为 storageClassName 属性设置 StorageClass 的名称来请求特定的存储类。 只有所请求的类的 PV 卷,即 storageClassName 值与 PVC 设置相同的 PV 卷, 才能绑定到 PVC 申领。

PVC 申领不必一定要请求某个类。如果 PVC 的 storageClassName 属性值设置为 "", 则被视为要请求的是没有设置存储类的 PV 卷,因此这一 PVC 申领只能绑定到未设置存储类的 PV 卷(未设置注解或者注解值为 "" 的 PersistentVolume(PV)对象在系统中不会被删除, 因为这样做可能会引起数据丢失。未设置 storageClassName 的 PVC 与此大不相同, 也会被集群作不同处理。具体筛查方式取决于 DefaultStorageClass 准入控制器插件 是否被启用。

如果准入控制器插件被启用,则管理员可以设置一个默认的 StorageClass。 所有未设置 storageClassName 的 PVC 都只能绑定到隶属于默认存储类的 PV 卷。 设置默认 StorageClass 的工作是通过将对应 StorageClass 对象的注解 storageclass.kubernetes.io/is-default-class 赋值为 true 来完成的。 如果管理员未设置默认存储类,集群对 PVC 创建的处理方式与未启用准入控制器插件时相同。 如果设定的默认存储类不止一个,准入控制插件会禁止所有创建 PVC 操作。
如果准入控制器插件被关闭,则不存在默认 StorageClass 的说法。 所有将 storageClassName 设为 "" 的 PVC 只能被绑定到也将 storageClassName 设为 "" 的 PV。 不过,只要默认的 StorageClass 可用,就可以稍后更新缺少 storageClassName 的 PVC。 如果这个 PVC 更新了,它将不再绑定到也将 storageClassName 设为 "" 的 PV。

取决于安装方法,默认的 StorageClass 可能在集群安装期间由插件管理器(Addon Manager)部署到集群中。

当某 PVC 除了请求 StorageClass 之外还设置了 selector,则这两种需求会按逻辑与关系处理: 只有隶属于所请求类且带有所请求标签的 PV 才能绑定到 PVC。

说明: 目前,设置了非空 selector 的 PVC 对象无法让集群为其动态制备 PV 卷。
早前,Kubernetes 使用注解 volume.beta.kubernetes.io/storage-class 而不是 storageClassName 属性。这一注解目前仍然起作用,不过在将来的 Kubernetes 发布版本中该注解会被彻底废弃。

PVC不是全局生效的,只在一个namespace里生效

五.创建NFS持久卷

5.1 配置NFS服务端以及共享目录

在一台机器上安装NFS服务端,k8s的两个worker安装NFS客户端。

etcd1机器作为NFS的服务端,安装NFS。

[root@etcd1 ~]# yum -y install nfs-utils

[root@etcd1 ~]# rpm -qa | grep nfs
libnfsidmap-0.25-19.el7.x86_64
nfs-utils-1.3.0-0.68.el7.2.x86_64

启动NFS

#使nfs开机自启动并现在就启动
[root@etcd1 ~]# systemctl enable nfs-server --now
Created symlink from /etc/systemd/system/multi-user.target.wants/nfs-server.service to /usr/lib/systemd/system/nfs-server.service.

#查看nfs状态
[root@etcd1 ~]# systemctl status nfs-server 
● nfs-server.service - NFS server and services
   Loaded: loaded (/usr/lib/systemd/system/nfs-server.service; enabled; vendor preset: disabled)
   Active: active (exited) since 二 2022-01-18 17:24:24 CST; 8s ago
  Process: 1469 ExecStartPost=/bin/sh -c if systemctl -q is-active gssproxy; then systemctl reload gssproxy ; fi (code=exited, status=0/SUCCESS)
  Process: 1453 ExecStart=/usr/sbin/rpc.nfsd $RPCNFSDARGS (code=exited, status=0/SUCCESS)
  Process: 1451 ExecStartPre=/usr/sbin/exportfs -r (code=exited, status=0/SUCCESS)
 Main PID: 1453 (code=exited, status=0/SUCCESS)
   CGroup: /system.slice/nfs-server.service

1月 18 17:24:24 etcd1 systemd[1]: Starting NFS server and services...
1月 18 17:24:24 etcd1 systemd[1]: Started NFS server and services.

先在NFS服务端创建/persitdir,并把目录/persitdir共享出去

#创建/persitdir作为共享目录
[root@etcd1 ~]# mkdir /persitdir

[root@etcd1 ~]# vim /etc/exports

#把/persitdir目录共享出去
[root@etcd1 ~]# cat /etc/exports
/persitdir *(rw,async,no_root_squash)

[root@etcd1 ~]# exportfs -arv
exporting *:/persitdir

创建文件

[root@etcd1 ~]# touch /persitdir/{xx,yy,zz,ww}.txt

[root@etcd1 ~]# ls /persitdir/
ww.txt  xx.txt  yy.txt  zz.txt

5.2 配置NFS客户端

在k8s集群的worker节点安装nfs的客户端

[root@k8scloude3 ~]# yum -y install nfs-utils

 #安装nfs的客户端
[root@k8scloude2 ~]# yum -y install nfs-utils

查看etcd1(192.168.110.133)机器共享出来的目录是哪个?

[root@k8scloude2 ~]# showmount -e 192.168.110.133
Export list for 192.168.110.133:
/persitdir *

5.3 创建持久卷

PersistentVolume 和 docker 中的 Volume 概念类似,都是代表机器上的一块存储,而PersistentVolume 也被称为集群共享资源,PersistentVolumeClaim 则是用户请对 pv 资源的请求。pv全局有效,不限于某个namespace

查看持久化存储数据卷PV

[root@k8scloude1 volume]# kubectl get pv
No resources found

配置nfs类型的持久卷Persistent Volume,关于nfs数据卷请查看博客《Kubernetes(k8s)存储管理之数据卷volumes(三):NFS数据卷》https://www.cnblogs.com/renshengdezheli/p/16971943.html

[root@k8scloude1 volume]# vim persistentv.yaml

[root@k8scloude1 volume]# cat persistentv.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv007
spec:
  #pv的大小
  capacity:
    storage: 5Gi
  #PV的卷模式
  volumeMode: Filesystem
  #PV的访问模式
  accessModes:
    - ReadWriteOnce
  #PV的回收策略
  persistentVolumeReclaimPolicy: Recycle
  #storageClassName: slow
  #PV的类型为nfs
  nfs:
    #nfs共享目录
    path: /persitdir
    #nfs服务器地址
    server: 192.168.110.133

创建持久卷Persistent Volume

[root@k8scloude1 volume]# kubectl apply -f persistentv.yaml 
persistentvolume/pv007 created

查看持久卷Persistent Volume

[root@k8scloude1 volume]# kubectl get pv
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pv007   5Gi        RWO            Recycle          Available                                   10s

pv全局有效,不限于某个namespace

[root@k8scloude1 volume]# kubectl get pv -n default
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pv007   5Gi        RWO            Recycle          Available      
                             95s
[root@k8scloude1 volume]# kubectl get pv -n ns1
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pv007   5Gi        RWO            Recycle          Available                                   101s

5.4 创建持久卷申领PersistentVolumeClaim

PersistentVolumeClaim(简称PVC)是用户存储的请求,PVC消耗PV的资源,可以请求特定的大小和访问模式,需要指定归属于某个Namespace,在同一个Namespace的Pod才可以指定对应的PVC。当需要不同性质的PV来满足存储需求时,可以使用StorageClass来实现。

PVC不是全局生效的,只在一个namespace里生效。

查看持久化存储卷声明pvc

[root@k8scloude1 volume]# kubectl get pvc
No resources found in volume namespace.

配置pvc

[root@k8scloude1 volume]# vim pvc1.yaml

[root@k8scloude1 volume]# cat pvc1.yaml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mypvc
spec:
  #访问模式
  accessModes:
    - ReadWriteOnce
  #卷模式
  volumeMode: Filesystem
  #请求的存储大小
  resources:
    requests:
      storage: 3Gi
  #storageClassName: slow

创建pvc

[root@k8scloude1 volume]# kubectl apply -f pvc1.yaml 
persistentvolumeclaim/mypvc created

注意:pvc和PV之间的关联主要靠参数:CAPACITY ,ACCESS MODES

[root@k8scloude1 volume]# kubectl get pvc
NAME    STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc   Bound    pv007    5Gi        RWO                           11s

PVC不是全局生效的,只在一个namespace里生效。

[root@k8scloude1 volume]# kubectl get pvc -n default
No resources found in default namespace.

在default命名空间创建pvc

[root@k8scloude1 volume]# kubectl apply -f pvc1.yaml -n default
persistentvolumeclaim/mypvc created

因为此时pvc已经被volume的命名空间里的pv关联在一起,现在不能在default命名空间关联pv

[root@k8scloude1 volume]# kubectl get pvc -n default
NAME    STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc   Pending                                                     3s

[root@k8scloude1 volume]# kubectl get pvc -n default
NAME    STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc   Pending                                                     2m1s

[root@k8scloude1 volume]# kubectl delete -f pvc1.yaml -n default
persistentvolumeclaim "mypvc" deleted

[root@k8scloude1 volume]# kubectl get pvc -n default
No resources found in default namespace.

5.5 添加存储类storageClass

注意:pvc和PV之间的关联主要靠参数:1.CAPACITY:pvc里的要求容量要小于等于pv里的容量 ,2.ACCESS MODES:必须相同, 3.STORAGECLASS不一样的话,pv和PVC也关联不起来。

CLAIM:volume/mypvc 可以看到mypvc已经和pv007关联在一起了。

[root@k8scloude1 volume]# kubectl get pvc 
NAME    STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc   Bound    pv007    5Gi        RWO                           5m31s

[root@k8scloude1 volume]# kubectl get pv
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM          STORAGECLASS   REASON   AGE
pv007   5Gi        RWO            Recycle          Bound    volume/mypvc                           16m

配置PersistentVolume

[root@k8scloude1 volume]# vim persistentv.yaml 

#设置storageClassName: secret
[root@k8scloude1 volume]# cat persistentv.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv007
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  storageClassName: secret
  nfs:
    path: /persitdir
    server: 192.168.110.133

配置PersistentVolumeClaim

[root@k8scloude1 volume]# vim pvc1.yaml 

#设置storageClassName: secret
[root@k8scloude1 volume]# cat pvc1.yaml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mypvc
spec:
  accessModes:
    - ReadWriteOnce
  volumeMode: Filesystem
  resources:
    requests:
      storage: 3Gi
  storageClassName: secret

创建PV和PVC,可以看到STORAGECLASS是一样的

[root@k8scloude1 volume]# kubectl apply -f persistentv.yaml 
persistentvolume/pv007 configured

[root@k8scloude1 volume]# kubectl apply -f pvc1.yaml 
persistentvolumeclaim/mypvc created

[root@k8scloude1 volume]# kubectl get pv
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS     CLAIM          STORAGECLASS   REASON   AGE
pv007   5Gi        RWO            Recycle          Released   volume/mypvc   secret                  75m

[root@k8scloude1 volume]# kubectl get pvc
NAME    STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc   Pending                                      secret         16s
[root@k8scloude1 volume]# kubectl get pvc
NAME    STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc   Bound    pv007    5Gi        RWO            secret         25s

可以查看PV的详细描述信息,比如NFS服务器地址和目录

[root@k8scloude1 volume]# kubectl describe pv pv007 
Name:            pv007
Labels:          <none>
Annotations:     pv.kubernetes.io/bound-by-controller: yes
Finalizers:      [kubernetes.io/pv-protection]
StorageClass:    secret
Status:          Bound
Claim:           volume/mypvc
Reclaim Policy:  Recycle
Access Modes:    RWO
VolumeMode:      Filesystem
Capacity:        5Gi
Node Affinity:   <none>
Message:         
Source:
    Type:      NFS (an NFS mount that lasts the lifetime of a pod)
    Server:    192.168.110.133
    Path:      /persitdir
    ReadOnly:  false
Events:
  Type    Reason          Age   From                         Message
  ----    ------          ----  ----                         -------
  Normal  RecyclerPod     91s   persistentvolume-controller  Recycler pod: Successfully assigned default/recycler-for-pv007 to k8scloude2
  Normal  RecyclerPod     89s   persistentvolume-controller  Recycler pod: Pulling image "busybox:1.27"
  Normal  RecyclerPod     71s   persistentvolume-controller  Recycler pod: Successfully pulled image "busybox:1.27" in 18.377762222s
  Normal  RecyclerPod     71s   persistentvolume-controller  Recycler pod: Created container pv-recycler
  Normal  RecyclerPod     71s   persistentvolume-controller  Recycler pod: Started container pv-recycler
  Normal  VolumeRecycled  70s   persistentvolume-controller  Volume recycled

删除pvc之后,pv的状态由Bound变为Available

[root@k8scloude1 volume]# kubectl delete -f pvc1.yaml 
persistentvolumeclaim "mypvc" deleted

[root@k8scloude1 volume]# kubectl get pv
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pv007   5Gi        RWO            Recycle          Available           secret                  80m

删除pvc之后,NFS服务端的 /persitdir/ 这个目录下文件没了 ,persistentVolumeReclaimPolicy: Recycle pv的回收策略:Recycle表示只要pvc被删除,对应的数据也会被删除

[root@etcd1 ~]# ls /persitdir/

5.6 修改persistentVolume的回收策略

在NFS服务端创建文件

[root@etcd1 ~]# touch /persitdir/{xx,yy,zz,ww}.txt

[root@etcd1 ~]# ls /persitdir/
ww.txt  xx.txt  yy.txt  zz.txt

配置PersistentVolume

[root@k8scloude1 volume]# vim persistentv.yaml 

#persistentVolumeReclaimPolicy: Retain  Retain表示pvc被删除之后,也要保留对应的数据 
[root@k8scloude1 volume]# cat persistentv.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv007
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: secret
  nfs:
    path: /persitdir
    server: 192.168.110.133

创建pv,PVC

[root@k8scloude1 volume]# kubectl apply -f persistentv.yaml 
persistentvolume/pv007 created

[root@k8scloude1 volume]# kubectl apply -f pvc1.yaml 
persistentvolumeclaim/mypvc created

[root@k8scloude1 volume]# kubectl get pv
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM          STORAGECLASS   REASON   AGE
pv007   5Gi        RWO            Retain           Bound    volume/mypvc   secret                  44s

[root@k8scloude1 volume]# kubectl get pvc
NAME    STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc   Bound    pv007    5Gi        RWO            secret         8s

[root@k8scloude1 volume]# kubectl delete -f pvc1.yaml 
persistentvolumeclaim "mypvc" deleted

[root@k8scloude1 volume]# kubectl get pvc
No resources found in volume namespace.

RECLAIM POLICY:Retain ,STATUS:Released,STATUS:Released 表示pv仍然保留为被关联状态,即使重新创建一个相同的pvc也只会处于Pending状态

[root@k8scloude1 volume]# kubectl get pv
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS     CLAIM          STORAGECLASS   REASON   AGE
pv007   5Gi        RWO            Retain           Released   volume/mypvc   secret                  112s

在NFS服务端 /persitdir/ 数据依然存在

[root@etcd1 ~]# ls /persitdir/
ww.txt  xx.txt  yy.txt  zz.txt

创建PVC

[root@k8scloude1 volume]# kubectl apply -f pvc1.yaml 
persistentvolumeclaim/mypvc created

#PV的STATUS:Released  表示pv仍然保留为被关联状态,即使重新创建一个相同的pvc也只会处于Pending状态
[root@k8scloude1 volume]# kubectl get pvc
NAME    STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc   Pending                                      secret         13s

[root@k8scloude1 volume]# kubectl delete -f pvc1.yaml 
persistentvolumeclaim "mypvc" deleted

[root@k8scloude1 volume]# kubectl get pvc
No resources found in volume namespace.

想正常使用PVC,只能删除pv,然后重新创建PVC

[root@k8scloude1 volume]# kubectl delete -f persistentv.yaml 
persistentvolume "pv007" deleted

[root@k8scloude1 volume]# kubectl get pv
No resources found

pv被删除了,NFS服务端/persitdir/ 数据依然存在没有影响

[root@etcd1 ~]# ls /persitdir/
ww.txt  xx.txt  yy.txt  zz.txt

现在重新创建PV和PVC即可

[root@k8scloude1 volume]# kubectl apply -f persistentv.yaml 
persistentvolume/pv007 created

[root@k8scloude1 volume]# kubectl apply -f pvc1.yaml 
persistentvolumeclaim/mypvc created

[root@k8scloude1 volume]# kubectl get pv
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM          STORAGECLASS   REASON   AGE
pv007   5Gi        RWO            Retain           Bound    volume/mypvc   secret                  10s

[root@k8scloude1 volume]# kubectl get pvc
NAME    STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc   Bound    pv007    5Gi        RWO            secret         7s

六.创建有NFS持久卷的pod

那我们的pod怎么使用pvc呢?配置pod把PVC挂载到容器的/xx目录

[root@k8scloude1 volume]# vim pvcpod.yaml 

[root@k8scloude1 volume]# cat pvcpod.yaml 
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: pvcshare
  name: pvcshare
spec:
  #nodeName指定pod运行在k8scloude3节点
  nodeName: k8scloude3
  terminationGracePeriodSeconds: 0
  volumes:
  - name: v1
    #卷类型为PVC
    persistentVolumeClaim:
      claimName: mypvc
  containers:
  - image: nginx
    imagePullPolicy: IfNotPresent
    name: h1
    resources: {}
    volumeMounts:
    - name: v1
      mountPath: /xx
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

创建pod

[root@k8scloude1 volume]# kubectl apply -f pvcpod.yaml 
pod/pvcshare created

[root@k8scloude1 volume]# kubectl get pod -o wide
NAME       READY   STATUS    RESTARTS   AGE   IP               NODE         NOMINATED NODE   READINESS GATES
pvcshare   1/1     Running   0          14s   10.244.251.255   k8scloude3   <none>           <none>

查看pod的详细描述信息

[root@k8scloude1 volume]# kubectl describe pod pvcshare | grep -A10 Volumes
Volumes:
  v1:
    Type:       PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
    ClaimName:  mypvc
    ReadOnly:   false
  kube-api-access-4kd64:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true

查看PV的详细描述信息

[root@k8scloude1 volume]# kubectl describe pv pv007 
Name:            pv007
Labels:          <none>
Annotations:     pv.kubernetes.io/bound-by-controller: yes
Finalizers:      [kubernetes.io/pv-protection]
StorageClass:    secret
Status:          Bound
Claim:           volume/mypvc
Reclaim Policy:  Retain
Access Modes:    RWO
VolumeMode:      Filesystem
Capacity:        5Gi
Node Affinity:   <none>
Message:         
Source:
    Type:      NFS (an NFS mount that lasts the lifetime of a pod)
    Server:    192.168.110.133
    Path:      /persitdir
    ReadOnly:  false
Events:        <none>

进入pod

[root@k8scloude1 volume]# kubectl exec -it pvcshare -- bash
#pod里也有对应的文件
root@pvcshare:/# ls /xx/
ww.txt	xx.txt	yy.txt	zz.txt
root@pvcshare:/# exit
exit

删除pod,pvc,pv

[root@k8scloude1 volume]# kubectl delete pod pvcshare --force
warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.
pod "pvcshare" force deleted

[root@k8scloude1 volume]# kubectl delete pvc mypvc 
persistentvolumeclaim "mypvc" deleted

[root@k8scloude1 volume]# kubectl delete pv pv007 
persistentvolume "pv007" deleted

[root@k8scloude1 volume]# kubectl get pod
No resources found in volume namespace.

[root@k8scloude1 volume]# kubectl get pvc
No resources found in volume namespace.

[root@k8scloude1 volume]# kubectl get pv
No resources found

目前创建持久卷Persistent Volume使用的是静态制备(集群管理员创建若干 PV 卷。这些卷对象带有真实存储的细节信息, 并且对集群用户可用。PV 卷对象存在于 Kubernetes API 中,可供用户消费使用),简言之就是需要先创建pv,然后才能创建PVC,我们可以使用存储类StorageClass实现动态制备,关于动态制备详细内容请查看博客《Kubernetes(k8s)存储管理之数据卷volumes(五):动态制备-存储类StorageClass》https://www.cnblogs.com/renshengdezheli/p/16972814.html。

posted @ 2022-12-10 20:41  人生的哲理  阅读(2033)  评论(1编辑  收藏  举报