


k8s之StorageClass存储动态供给
前面我们创建的pv和pvc都是静态的,简单来说静态的pv和pvc就是需要我们手动创建的,但这种情况很大程度上并不能满足我们的需求。假如我们有一个应用需要对存储的并发度要求比较高,而另外一个应用对读写速度又要求比较高,特别是对于StatefulSet类型的应用。这时候使用静态PV就很不合时了,于是就需要使用StorageClass了。
动态PV:StorageClass
StorageClass的定义主要包括名称、 后端存储的提供者(provisioner) 和后端存储的相关参数配置。StorageClass一旦被创建出来, 则将无法修改。如需更改, 则只能删除原StorageClass的定义重建
StorageClass是为了满足用于对存储设备的不同需求,比如快速存储,慢速存储等,通过对StorageClass的定义,管理员就可以将存储设备定义为某种资源类型,用户根据StorageClass的描述可以非常直观的知道各种存储资源的具体特性,这样就可以根据应用特性去申请合适的资源了。
通过StorageClass的定义,管理员可以将存储资源定义为某种类别(Class),正如存储设备对于自身的配置描述(Profile),例如 “快速存储” “慢速存储” “有数据冗余” “无数据冗余”
等。用户根据StorageClass的描述就能够直观得知各种存储资源的特性,就可以根据应用对存储资源的需求去申请存储资源了。

StorageClass作为对存储资源的抽象定义,对用户设置的PVC申请屏蔽后端的细节,一方面减轻用户对于存储资源细节的关注,另一方面也减轻了管理员手工管理PV的工作,由系统自动完成PV的创建和绑定,实现了动态的资源供应。使用基于StorageClass的动态资源供应模式将逐步成为云平台的标准存储配置模式。
StorageClass
的定义主要包括名称、后端存储的提供者(Provisioner)和后端存储的相关参数配置。StorageClass一旦被创建出来,将无法修改。如需修改,则只能删除原StorageClass的定义重建。
要使用 StorageClass,就得安装对应的自动配置程序,比如我们这里存储后端使用的是 nfs,那么我们就需要使用到一个 nfs-client 的自动配置程序,我们也叫它 Provisioner,这个程序使用我们已经配置好的 nfs 服务器,来自动创建持久卷,也就是自动帮我们创建 PV。
具体来说,StorageClass会定义一下两部分:
PV的属性 ,比如存储的大小、类型等; 创建这种PV需要使用到的存储插件,比如Ceph等;
有了这两部分信息,Kubernetes就能够根据用户提交的PVC,找到对应的StorageClass,然后Kubernetes就会调用 StorageClass声明的存储插件,创建出需要的PV。
要使用StorageClass,我们就需要安装对应的自动配置程序,这里我们采用nfs网络文件系统作为后端存储,因此就需要使用一个nfs-client的自动配置程序,我们也叫它Provisioner
,这个程序使用我们已经配置好的nfs服务器,来自动创建持久卷,即自动为我们创建PV。
温馨提示:自动创建的 PV 以
${namespace}-${pvcName}-${pvName}
这样的命名格式创建在 NFS 服务器上的共享数据目录中。当这个 PV 被回收后会以archieved-${namespace}-${pvcName}-${pvName}
这样的命名格式存在 NFS 服务器上。
NFS服务部署这里就不重复介绍了,有需要的小伙伴可参考我之前写的文章:NFS网络文件系统介绍及安装
一、创建nfs的nfs-client-provisioner的Deployment
出于某种网络原因,镜像拉取不下来的话可以去国外的服务器装上docker拉取 或者文章评论留言或者文末加我微信备注
公众号拿镜像
我看到就会给你提供镜像
注
:把下面变量NFS_SERVER
和NFS_PATH
的value值改成自己nfs配置的实际值
vim nfs-client-deployment.yaml
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: nfs-client-provisioner
spec:
selector:
matchLabels:
app: nfs-client-provisioner
replicas: 1
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 # 镜像由于网络原因可能拉不下来
imagePullPolicy: IfNotPresent
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: fuseim.pri/ifs
- name: NFS_SERVER
value: 192.168.2.220
- name: NFS_PATH
value: /data/k8s
volumes:
- name: nfs-client-root
nfs:
server: 192.168.2.220
path: /data/k8s
二、创建 nfs-client-provisioner 和serviceAccount
serviceAccount用于将nfs-client-provisioner中的ServiceAccount绑定到一个nfs-client-provisioner-runner的ClusterRole。而该ClusterRole声明了一些权限,其中就包括了对persistentvolumes的增删改查,所以我们就可以利用ServiceAccount来自动创建PV
cat >> nfs-client-sa.yaml <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-client-provisioner
---
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: ["list", "watch", "create", "update", "patch"]
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["create", "delete", "get", "list", "watch", "patch", "update"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-client-provisioner
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
namespace: default
roleRef:
kind: ClusterRole
name: nfs-client-provisioner-runner
apiGroup: rbac.authorization.k8s.io
EOF
三、创建一个StorageClass对象
注:
这里的 fuseim.pri/ifs
需要和deployment中写的保持一致course-nfs-storage
是我们这里定义的StorageClass名称。可以自己更改,但是后面引用StorageClass的时候要和这里保持一致。即:要用这里定义的这个名称。否则关联不上就无法通过该SC创建PV了
vim nfs-client-class.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: course-nfs-storage
provisioner: fuseim.pri/ifs
四、创建并查看这些资源对象
# -f后面的.代表应用当前目录下所有yaml资源清单文件
[root@k8s-master storageclass-nfs]# kubectl apply -f .
[root@k8s-master storageclass-nfs]# kubectl get po
NAME READY STATUS RESTARTS AGE
nfs-client-provisioner-6f59fd5dfc-62qzz 1/1 Running 0 2m22s
[root@k8s-master storageclass-nfs]# kubectl get sc
NAME PROVISIONER AGE
course-nfs-storage fuseim.pri/ifs 2m22s
StorageClass资源对象创建成功后,新建PVC来引用刚刚创建的storageclass,测试是否能自动创建合适的PV。
vim test-pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-pvc
annotations:
volume.beta.kubernetes.io/storage-class: "course-nfs-storage" # 指定storageclass名称
spec:
accessModes: # 访问模式
- ReadWriteMany
resources:
requests:
storage: 1Mi # 请求数据大小
应用pvc清单文件:
[root@k8s-master storageclass-nfs]# kubectl apply -f test-pvc.yaml
[root@k8s-master storageclass-nfs]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
test-pvc Bound pvc-df681715-ca3f-41ec-b42f-fba1fb0ac642 1Mi RWX course-nfs-storage 28m
可以看到 test-pvc 的 PVC对象创建成功,状态为BOUND。同时生成一个VOLUME对象,StorageClass是刚才前面创建的course-nfs-storage
查看一下pv对象:
[root@k8s-master storageclass-nfs]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
...
pvc-73b5ffd2-8b4b-11e8-b585-525400db4df7 1Mi RWX Delete Bound default/test-pvc course-nfs-storage 8s
看到自动生成了一个关联的 PV 对象,访问模式是 RWX,回收策略是 Delete,这个 PV 对象并不是我们手动创建的,这是通过我们上面的 StorageClass 对象自动创建的。这就是 StorageClass 的创建方法。
在默认情况下,我们创建一个pvc需要有一个状态为空闲的pv,然后才会绑定到pvc上。使用storageclass之后,我们不需要的手动创建pv,只需要创建一个pvc,storageclass
会自动将pv给创建并且关联
创建pod测试上面用StorageClass方式声明的PVC对象
这里的Pod类型和Deployment使用方式是一样的,官方默认使用的是Pod这里就不变,修改为Deployment也是一样的格式
kind: Pod
apiVersion: v1
metadata:
name: test-pod
spec:
containers:
- name: test-pod
image: busybox
imagePullPolicy: IfNotPresent
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-pvc
用一个 busybox 容器,在 /mnt 目录下面新建一个 SUCCESS 的文件,然后把 /mnt 目录挂载到上面我们新建的 test-pvc 这个资源对象上面了,要验证很简单,只需要去查看下我们 nfs 服务器上面的共享数据目录下面是否有 SUCCESS 这个文件即可。当成功创建SUCCESS文件以后,该POD的状态就会变成completed。这是标识pod已经成功启动并成功完成了我们定义的创建文件操作。
[root@k8s-master storageclass]# kubectl apply -f test-pod.yaml
# 下面在k8s-master直接查看
[root@k8s-master storageclass]# ll /data/k8sclient/default-test-pvc-pvc-df681715-ca3f-41ec-b42f-fba1fb0ac642/
total 0
-rw-r--r-- 1 root root 0 Sep 26 10:54 SUCCESS
# 下面在nfs的服务端查看
[root@k8s-master storageclass]# ll default-test-pvc-pvc-df681715-ca3f-41ec-b42f-fba1fb0ac642/
total 0
-rw-r--r-- 1 root root 0 Sep 26 10:54 SUCCESS
可以看到下面有名字很长的文件夹,这个文件夹的命名方式是不是和我们上面的规则:${namespace}-${pvcName}-${pvName}
是一样的,目录下也有SUCCESS
文件。证明以上创建pod是成功了。如果有问题报错,则执行kubectl describe pod_name
进行排查
测试删除掉刚才的test-pvc,先delete掉pod再删除pvc,会发现相关的动态创建的pv也会被删除。并且同样验证了PV创建和被回收掉以后的命名格式也是对应上了。
[root@k8s-master storageclass]# kubectl get po
NAME READY STATUS RESTARTS AGE
nfs-client-provisioner-b48bd9776-w885s 1/1 Running 0 4h50m
test-pod 0/1 Completed 0 4h13m
[root@k8s-master storageclass]# ll /data/k8sclient/
total 0
drwxrwxrwx 2 root root 21 Sep 26 10:54 default-test-pvc-pvc-df681715-ca3f-41ec-b42f-fba1fb0ac642
[root@k8s-master storageclass]# kubectl delete po test-pod
pod "test-pod" deleted
[root@k8s-master storageclass]# kubectl delete pvc test-pvc
persistentvolumeclaim "test-pvc" deleted
[root@k8s-master storageclass]# ll /data/k8sclient
total 0
drwxrwxrwx 2 root root 21 Sep 26 10:54 archived-default-test-pvc-pvc-df681715-ca3f-41ec-b42f-fba1fb0ac642
使用StatefulSet 引用Storageclass
在实际工作中,使用 StorageClass 更多的是 StatefulSet 类型的服务 测试创建StatefulSet 类型的服务。通过一个 volumeClaimTemplates 属性来直接使用 StorageClass
vim test-statefulset-nfs.yaml
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: nfs-web
spec:
serviceName: "nginx"
replicas: 3
template:
metadata:
labels:
app: nfs-web
spec:
terminationGracePeriodSeconds: 10
containers:
- name: nginx
image: nginx:1.12.2
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
annotations:
volume.beta.kubernetes.io/storage-class: course-nfs-storage
spec:
#storageClassName: "course-nfs-storage" 写了注解这里就不需要写了,注解是早期的写法
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
实际上 volumeClaimTemplates 下面就是一个 PVC 对象的模板,就类似于我们这里 StatefulSet 下面的 template,实际上就是一个 Pod 的模板,我们不单独创建成 PVC 对象,而用这种模板就可以动态的去创建对象了,这种方式在 StatefulSet 类型的服务下面使用得非常多
创建完statefulset对象后,查看po,pv,pvc以及nfs服务器上的共享数据目录中的数据
[root@k8s-master storageclass]# kubectl apply -f test-statefulset-nfs.yaml
[root@k8s-master storageclass]# kubectl get po
NAME READY STATUS RESTARTS AGE
nfs-web-0 1/1 Running 0 31m
nfs-web-1 1/1 Running 0 30m
nfs-web-2 1/1 Running 0 30m
查看pv,pvc
[root@k8s-master storageclass]# kubectl get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/pvc-21ce09ec-68b9-4802-a573-bb57062a90e3 1Gi RWO Delete Bound default/www-nfs-web-2 course-nfs-storage 32m
persistentvolume/pvc-7345363c-a755-42b4-9779-1ac3e0223c4b 1Gi RWO Delete Bound default/www-nfs-web-0 course-nfs-storage 32m
persistentvolume/pvc-910b8568-ae1f-49ad-ba94-7a0f5d39ab0d 1Gi RWO Delete Bound default/www-nfs-web-1 course-nfs-storage 32m
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/www-nfs-web-0 Bound pvc-7345363c-a755-42b4-9779-1ac3e0223c4b 1Gi RWO course-nfs-storage 32m
persistentvolumeclaim/www-nfs-web-1 Bound pvc-910b8568-ae1f-49ad-ba94-7a0f5d39ab0d 1Gi RWO course-nfs-storage 32m
persistentvolumeclaim/www-nfs-web-2 Bound pvc-21ce09ec-68b9-4802-a573-bb57062a90e3 1Gi RWO course-nfs-storage 32m
查看 nfs 服务器上面的共享数据目录
[root@k8s-node01 k8s]# ll /data/k8s/
total 0
drwxrwxrwx 2 root root 6 Sep 26 10:57 default-www-nfs-web-0-pvc-7345363c-a755-42b4-9779-1ac3e0223c4b
drwxrwxrwx 2 root root 6 Sep 26 10:57 default-www-nfs-web-1-pvc-910b8568-ae1f-49ad-ba94-7a0f5d39ab0d
drwxrwxrwx 2 root root 6 Sep 26 10:57 default-www-nfs-web-2-pvc-21ce09ec-68b9-4802-a573-bb57062a90e3
完
------------------------------------------------------
公众号:竹下侯小姜运维
个人博客:https://www.ayunw.cn
重要的事情认真做,普通的事情规范做!
------------------------------------------------------
不定期更新优质内容,技术干货!如果觉得对你有帮助,请扫描下方二维码关注!

温馨提示
如果你喜欢本文,请分享到朋友圈,想要获得更多信息,请关注我!




