K8S 通过引入 PV 和 PVC 的概念,可以让集群的管理人员和开发人员各司其职。不过也增加了额外 PV 和 PVC 创建、绑定、删除、回收等资源管理的工作,也显现出了存储方面的流程复杂和繁琐。
K8S 又引入了 StorageClass 动态卷的概念,可以使得存储能够灵活分配,可以按需请求自动创建存储卷。如果没有动态卷,集群管理员必须通过 Kubernetes 集群创建 PersistentVolume 对象来表示这些卷。 动态供应功能避免了集群管理员预先配置存储的需要。
K8S 动态卷供应的实现基于 storage.k8s.io API 组中的 StorageClass API 对象。集群管理员可以根据需要定义多个 StorageClass 对象,每个对象指定一个卷插件(又名 provisioner), 卷插件向卷供应商提供在创建卷时需要的数据卷信息及相关参数。
StorageClass 作为对存储资源的抽象定义, 对用户设置的NFS申请屏蔽后端存储的细节, 一方面减少了用户对于存储资源细节的关注, 另一方面减轻了集群管理员手工管理 pv 的工作, 由系统自动完成pv的创建和绑定。StorageClass 是一种资源对象, 不提供pv的创建。
NFS 共享存储简单易部署,成本低,不知道怎么安装部署的可以查看这里:Linux 下使用 NFS 文件共享。这里以NFS共享存储为例, 使用nfs-client-provisioner 组件连接nfs服务器以及pv的创建。
声明部署
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//deployment.yaml
kind: Deployment
apiVersion: apps/v1
metadata:
name: nfs-client-provisioner
spec:
replicas: 1
selector:
matchLabels:
app: nfs-client-provisioner
strategy:
type: Recreate
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: nfs-storage
- name: NFS_SERVER # NFS服务地址
value: s1001.lab.org
- name: NFS_PATH # NFS服务目录
value: /data/nfs-data/k8s/dynamic/
volumes:
- name: nfs-client-root
nfs:
server: s1001.lab.org
path: /data/nfs-data/k8s/dynamic/
注意需将以上NFS服务地址和路径参数改成自己的。
StorageClass
StorageClass,此处修改provisioner名称,需要和部署文件中的PROVISIONER_NAME一致:
1
2
3
4
5
6
7
8
//class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: managed-nfs-storage
provisioner: nfs-storage # 这里名称需和上面 PROVISIONER_NAME 一致
parameters:
archiveOnDelete: "false"
storageclass 支持以下几个参数:
- onDelete:delete 删除目录。retain:归档。
- archiveOnDelete:false 删除目录。如果设置了onDelete参数,archiveOnDelete就会被忽略。
- pathPattern:用于设置创建目录的路径, 默认格式是
1
${.PVC.namespace}/${.PVC.annotations.nfs.io/storage-path}
当PVC删除时,默认会对创建的目录进行规定并重命名保存:
1
archived-+volume.Name
注意 storageclass 一旦创建, parameters 参数不允许再次更改,只能重新创建。
执行安装
依次执行:
1
2
3
kubectl apply -f https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner/raw/master/deploy/rbac.yaml
kubectl apply -f deployment.yaml
kubectl apply -f class.yaml
测试验证
现在就可以使用动态卷了, 创建一个用于测试的 Pod, 通过 PersistentVolumeClaim 申请使用nfs共享卷,执行后如果你在挂载的目录中看到一个SUCCESS文件就说明成功了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//test.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-claim
annotations:
volume.beta.kubernetes.io/storage-class: "managed-nfs-storage"
spec:
storageClassName: managed-nfs-storage
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Mi
---
kind: Pod
apiVersion: v1
metadata:
name: test-pod
spec:
containers:
- name: test-pod
image: busybox:1.28.4
command:
- "/bin/sh"
args:
- "-c"
- "touch /mnt/SUCCESS && exit 0 || exit 1"
volumeMounts:
- name: nfs-pvc
mountPath: "/mnt"
restartPolicy: "Never"
volumes:
- name: nfs-pvc
persistentVolumeClaim:
claimName: test-claim
验证一下,pv、pvc 已经自动创建好了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//查看pv
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-c95e877a-6418-417f-bfac-cb9853a2bfc7 1Mi RWX Delete Bound default/test-claim managed-nfs-storage 32m
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
test-claim Bound pvc-c95e877a-6418-417f-bfac-cb9853a2bfc7 1Mi RWX managed-nfs-storage 34m
$ ls /data/nfs-data/k8s/dynamic
default-test-claim-pvc-c95e877a-6418-417f-bfac-cb9853a2bfc7
$ ls -al /data/nfs-data/k8s/dynamic/default-test-claim-pvc-c95e877a-6418-417f-bfac-cb9853a2bfc7/
SUCCESS
如果执行删除 kubectl delete -f deployment.yaml 删除pvc后, 创建的目录和文件就会自动删除,因为我们上面设置到了 StorageClass 的参数 archiveOnDelete 为 false,也就不会自动归档。
参考文档
https://kubernetes.io/zh/docs/concepts/storage/dynamic-provisioning/
https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner