1、简介
现在集群管理员不预分配 PV,他写了一个模板文件,这个模板文件是用来表示创建某一类型存储(块存储,文件存储等)所需的一些参数,这些参数是用户不关心的,给存储本身实现有关的参数。用户只需要提交自身的存储需求,也就是PVC文件,并在 PVC 中指定使用的存储模板(StorageClass)。K8s 集群中的管控组件,会结合 PVC 和 StorageClass 的信息动态,生成用户所需要的存储(PV),将 PVC 和 PV 进行绑定后,pod 就可以使用 PV 了。通过 StorageClass 配置生成存储所需要的存储模板,再结合用户的需求动态创建 PV 对象,做到按需分配,在没有增加用户使用难度的同时也解放了集群管理员的运维工作。
2、Provisioning(供应) - 为PVC提供PV
为pvc供应( Provisioning )pv有两种方式,静态和动态:
静态供应 (Static)
集群管理员实现创建好一系列 PersistentVolume,它们包含了可供集群中应用程序使用的关于实际存储的具体信息。

动态供应 (Dynamic)
在配置有合适的 StorageClass(存储类)且 PersistentVolumeClaim 关联了该 StorageClass 的情况下,kubernetes 集群可以为应用程序动态创建 PersistentVolume。

3、绑定 (Binding)
用户创建了一个 PersistentVolumeClaim 存储卷声明,并指定了需求的存储空间大小以及访问模式。
Kubernets master 将立刻为其匹配一个 PersistentVolume 存储卷,并将存储卷声明和存储卷绑定到一起。
除动态提供,应用程序将被绑定一个不小于(可能大于)其 PersistentVolumeClaim 中请求的存储空间大小的 PersistentVolume。一旦绑定,PersistentVolumeClaim 将拒绝其他 PersistentVolume 的绑定关系。PVC 与 PV 之间的绑定关系是一对一的映射。
PersistentVolumeClaim 将始终停留在 未绑定 unbound 状态,直到有合适的 PersistentVolume 可用。举个例子:集群中已经存在一个 50Gi 的 PersistentVolume,同时有一个 100Gi 的 PersistentVolumeClaim,在这种情况下,该 PVC 将一直处于 未绑定 unbound 状态,直到管理员向集群中添加了一个 100Gi 的 PersistentVolume。
4、使用中保护 (Storage Object in Use Protection)
使用中保护(Storage Object in Use Protection)的目的是确保正在被容器组使用的 PersistentVolumeClaim 以及其绑定的 PersistentVolume 不能被系统删除,以避免可能的数据丢失。
如果用户删除一个正在使用中的 PersistentVolumeClaim,则该 PVC 不会立即被移除掉,而是推迟到该 PVC 不在被任何容器组使用时才移除;同样的如果管理员删除了一个已经绑定到 PVC 的 PersistentVolume,则该 PV 也不会立刻被移除掉,而是推迟到其绑定的 PVC 被删除后才移除掉。
5、回收 (Reclaiming)
当用户不在需要其数据卷时,可以删除掉其 PersistentVolumeClaim,此时其对应的 PersistentVolume 将被集群回收并再利用。Kubernetes 集群根据 PersistentVolume 中的 reclaim policy(回收策略)决定在其被回收时做对应的处理。当前支持的回收策略有:Retained(保留)、Recycled(重复利用)、Deleted(删除):
保留 (Retain)
保留策略需要集群管理员手工回收该资源。当绑定的 PersistentVolumeClaim 被删除后,PersistentVolume 仍然存在,并被认为是”已释放“。但是此时该存储卷仍然不能被其他 PersistentVolumeClaim 绑定,因为前一个绑定的 PersistentVolumeClaim 对应容器组的数据还在其中。集群管理员可以通过如下步骤回收该 PersistentVolume:
删除该 PersistentVolume。PV 删除后,其数据仍然存在于对应的外部存储介质中(nfs、cefpfs、glusterfs 等)
手工删除对应存储介质上的数据
手工删除对应的存储介质,您也可以创建一个新的 PersistentVolume 并再次使用该存储介质
删除 (Delete)
删除策略将从 kubernete 集群移除 PersistentVolume 以及其关联的外部存储介质(云环境中的 AWA EBS、GCE PD、Azure Disk 或 Cinder volume)。
再利用 (Recycle)
再利用策略将在 PersistentVolume 回收时,执行一个基本的清除操作(rm -rf thevolume/*),并使其可以再次被新的 PersistentVolumeClaim 绑定。
Warning: The
Recycle
reclaim policy is deprecated. Instead, the recommended approach is to use dynamic provisioning.(动态供应)
6、PV字段
PersistentVolume 字段描述如下表所示:
| 字段名称 | 可选项/备注 |
|---|---|
| 容量 Capacity | 通常,一个 PersistentVolume 具有一个固定的存储容量(capacity) |
| Volume Mode | FEATURE STATE: Kubernetes v1.13 beta Kubernetes 1.9 之前的版本,所有的存储卷都被初始化一个文件系统。当前可选项有:block:使用一个 块设备(raw block device)filesystem(默认值):使用一个文件系统 |
| Access Modes | 可被单节点读写-ReadWriteOnce【RWO】可被多节点只读-ReadOnlyMany【ROX】可被多节点读写-ReadWriteMany【RWX】注意:不同的存储支持的不同,见下表 |
| 存储类 StorageClassName | 带有存储类 StorageClassName 属性的 PersistentVolume 只能绑定到请求该 StorageClass 存储类的 PersistentVolumeClaim。 没有 StorageClassName 属性的 PersistentVolume 只能绑定到无特定 StorageClass 存储类要求的 PVC。 |
| 回收策略 Reclaim Policy | 保留 Retain – 手工回收再利用Recycle – 清除后重新可用 (rm -rf thevolume/*)删除 Delete – 删除 PV 及存储介质 |
| Mount Options | 挂载选项用来在挂载时作为 mount 命令的参数 |
| 状态 Phase | Available – 可用的 PV,尚未绑定到 PVCBound – 已经绑定到 PVCReleased – PVC 已经被删除,但是资源还未被集群回收Failed – 自动回收失败 |
7、PVC相关字段
| 字段名称 | 可选项/备注 |
|---|---|
| 存储类 | 只有该 StorageClass 存储类的 PV 才可以绑定到此 PVC |
| 读写模式 Access Modes | 可被单节点读写-ReadWriteOnce可被多节点只读-ReadOnlyMany可被多节点读写-ReadWriteMany |
| Volume Modes | blockfilesystem - default |
| 总量 | 请求存储空间的大小 |
8、K8s动态资源的用途
数据库实例管理: 您可以创建一个自定义资源来定义数据库实例的规格、访问凭证和备份策略,然后使用控制器来动态创建和管理这些数据库实例。
应用程序配置: 通过自定义资源,您可以定义应用程序的配置,例如环境变量、配置文件和秘密。然后,您可以使用控制器将这些配置应用到相关的Pod中。
监控和警报: 自定义资源可以用于定义监控指标和警报规则。这使您可以在Kubernetes集群中集中管理监控和警报设置。
存储卷管理: 如果您有特定的存储需求,可以创建自定义资源来定义持久卷的规格和访问策略,然后使用控制器来创建和管理这些卷。
CI/CD管道: 自定义资源可以用于定义CI/CD管道的配置,包括构建规则、部署策略和自动化测试。
9、实战前准备-安装NFS环境
搭建NFS-Server环境
#配置NFS服务器
yum install -y nfs-utils
#执行命令 vi etc/exports,创建 exports 文件,文件内容如下:
echo "/data/volumes/ *(insecure,rw,sync,no_root_squash)" > etc/exports
#/data/volumes 172.26.248.0/20(rw,no_root_squash)
# 创建共享目录
mkdir -p data/volumes
systemctl enable rpcbind
systemctl enable nfs-server
#执行以下命令,启动 nfs 服务
systemctl restart rpcbind
systemctl restart nfs-server
exportfs -r
#检查配置是否生效
exportfs
# 输出结果如下所示
/data/volumes data/volumes
搭建NFS-Client环境(选测)
#服务器端防火墙开放111、662、875、892、2049的 tcp udp 允许,否则远端客户无法连接。
#安装客户端工具
yum install -y nfs-utils
#执行以下命令检查 nfs 服务器端是否有设置共享目录
# showmount -e $(nfs服务器的IP)
showmount -e 172.26.248.150
# 输出结果如下所示
Export list for 172.26.248.150
/data/volumes *
#执行以下命令挂载 nfs 服务器上的共享目录到本机路径 root/nfsmount
mkdir root/nfsmount
# mount -t nfs $(nfs服务器的IP):/root/nfs_root root/nfsmount
#高可用备份的方式
mount -t nfs 172.26.248.165:/nfs/data nfs/data
# 写入一个测试文件
echo "hello nfs server" > root/nfsmount/test.txt
#在 nfs 服务器上执行以下命令,验证文件写入成功
cat data/volumes/test.txt
10、创建存储类(NFS环境前面已经搭好)
| 字段名称 | 填入内容 | 备注 |
|---|---|---|
| 名称 | nfs-storage | 自定义存储类名称 |
| NFS Server | 172.20.60.23 | NFS服务的IP地址 |
| NFS Path | /data/volumes | NFS服务所共享的路径 |
11、Storage Classes
Storage Classes是K8s中定义动态存储的一种机制。它是一种资源对象,用于定义存储卷的属性和行为。
每个Storage Class都有一个唯一的名称,并定义了存储卷的类型、访问模式、存储提供者等属性。
当创建PVC(Persistent Volume Claim)时,可以指定所需的Storage Class,K8s将根据Storage Class的定义自动创建和绑定存储卷。
12、实战-动态提供 PV
基于Storage Class和nfs文件系统,实现存储的动态供给(NFS+PV+PVC)

创建sa
# 先创建授权
[root@node1 ~]# vi nfs-rbac.yaml
apiVersion: v1
kind: Namespace ##创建Namespace,并全部替换为新建的Namespace
metadata:
name: nfs-client-provisioner
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-client-provisioner
namespace: nfs-client-provisioner
---
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
namespace: nfs-client-provisioner
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
namespace: nfs-client-provisioner
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
namespace: nfs-client-provisioner
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
namespace: nfs-client-provisioner
roleRef:
kind: Role
name: leader-locking-nfs-client-provisioner
apiGroup: rbac.authorization.k8s.io
##这个镜像中volume的mountPath默认为/persistentvolumes,不能修改,否则运行时会报错
部署nfs-client-provisioner
nfs-client-provisioner 是一个 Kubernetes 的简易 NFS 的外部 provisioner,本身不提供 NFS,需要现有的 NFS 服务器提供存储。注意:地址和目录要改成实际的NFS服务对应配置。
[root@node1 ~]# cat deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-client-provisioner
labels:
app: nfs-client-provisioner
namespace: nfs-client-provisioner ##指向新建
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: registry.cn-hangzhou.aliyuncs.com/xzjs/nfs-subdir-external-provisioner:v4.0.0 ##更改镜像
volumeMounts:
- name: nfs-client-root
mountPath: persistentvolumes
env:
- name: PROVISIONER_NAME
value: k8s-sigs.io/nfs-subdir-external-provisioner
- name: NFS_SERVER
value: 172.20.60.23 ##nfs服务器地址
- name: NFS_PATH
value: data/volumes/ ##nfs路径
volumes:
- name: nfs-client-root
nfs:
server: 172.20.60.23 ##server
path: data/volumes/ ##路径
创建StorageClass
StorageClass是对存储资源的抽象定义,对用户设置的PVC申请屏蔽后端存储的细节,减轻管理员手工管理PV的工作,由系统自动完成PV的创建和绑定,实现动态资源供给。StorageClass的定义主要包括名称、后端存储的提供者(provisioner)和后端存储对应的参数。对于后端NFS存储来说,配置相对简单,只需要指定provisioner即可。
#创建storageclass
[root@node1 ~]# vi storageclass-nfs.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-client
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner ##和 deployment.yaml中定义的name一致
reclaimPolicy: Delete
#扩展"reclaim policy"有三种方式:Retain、Recycle、Deleted。
Retain
#保护被PVC释放的PV及其上数据,并将PV状态改成"released",不将被其它PVC绑定。集群管理员手动通过如下步骤释放存储资源:
手动删除PV,但与其相关的后端存储资源如(AWS EBS, GCE PD, Azure Disk, or Cinder volume)仍然存在。
手动清空后端存储volume上的数据。
手动删除后端存储volume,或者重复使用后端volume,为其创建新的PV。
Delete
删除被PVC释放的PV及其后端存储volume。对于动态PV其"reclaim policy"继承自其"storage class",
默认是Delete。集群管理员负责将"storage class"的"reclaim policy"设置成用户期望的形式,否则需要用
户手动为创建后的动态PV编辑"reclaim policy"
Recycle
保留PV,但清空其上数据,已废弃
改变默认sc
##改变系统默认sc
https://kubernetes.io/zh/docs/tasks/administer-cluster/change-default-storage-class/#%e4%b8%ba%e4%bb%80%e4%b9%88%e8%a6%81%e6%94%b9%e5%8f%98%e9%bb%98%e8%ae%a4-storage-class
[root@node1 ~]# kubectl patch storageclass storage-nfs-hdd -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
创建pvc
[root@node1 ~]# vi pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-claim
spec:
storageClassName: nfs-client ##存储类名字需保持一致
accessModes:
- ReadWriteMany ##多点读写
resources:
requests:
storage: 1Gi
实战部署deployment
[root@node1 ~]# cat test-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-deploy
labels:
app: test-deploy
namespace: default #与RBAC文件中的namespace保持一致
spec:
replicas: 2
selector:
matchLabels:
app: test-deploy
strategy:
type: Recreate
selector:
matchLabels:
app: test-deploy
template:
metadata:
labels:
app: test-deploy
spec:
containers:
- name: test-pod
image: busybox:1.24
command:
- "/bin/sh"
args:
- "-c"
# - "touch mnt/SUCCESS3 && exit 0 || exit 1" #创建一个SUCCESS文件后退出
- touch mnt/SUCCESS5; sleep 50000
volumeMounts:
- name: nfs-pvc
mountPath: "/mnt"
# subPath: test-pod-3 # 子路径 (这路基代表存储卷下面的test-pod子目录)
volumes:
- name: nfs-pvc
persistentVolumeClaim:
claimName: test-claim #与PVC名称保持一致
验证
# 去nfs服务器中验证
[root@node1 ~]# kubectl --kubeconfig=../sit get pod
NAME READY STATUS RESTARTS AGE
test-deploy-5d649d6566-bl7lx 1/1 Running 3 2d1h
test-deploy-5d649d6566-nkpqk 1/1 Running 3 2d1h
[root@node1 ~]# kubectl --kubeconfig=../sit exec -it test-deploy-5d649d6566-bl7lx -- /bin/sh
/ # cd /mnt/
/mnt # ls
SUCCESS5
/mnt # echo "111" > index.html
[root@node1 ~]# kubectl --kubeconfig=../sit exec -it test-deploy-5d649d6566-nkpqk -- /bin/sh
/ # cd /mnt/
/mnt # ls
SUCCESS5 index.html
/mnt # cat index.html
111
欢迎大家扫码关注:

本公众号只写原创,不接广告、不接广告、不接广告。下期小伙伴想学习什么技术,可以私信发我吆。





