前面的课程中我们学习了 PV
和 PVC
的使用方法,但是前面的 PV 都是静态的,什么意思?就是我要使用的一个 PVC 的话就必须手动去创建一个 PV,我们也说过这种方式在很大程度上并不能满足我们的需求,比如我们有一个应用需要对存储的并发度要求比较高,而另外一个应用对读写速度又要求比较高,特别是对于 StatefulSet
类型的应用简单的来使用静态的 PV 就很不合适了,这种情况下我们就需要用到动态 PV,也就是我们今天要讲解的 StorageClass
。
创建 Provisioner
要使用 StorageClass,我们就得安装对应的自动配置程序,比如我们这里存储后端使用的是 nfs,那么我们就需要使用到一个 nfs-client 的自动配置程序,我们也叫它 Provisioner,这个程序使用我们已经配置好的 nfs 服务器,来自动创建持久卷,也就是自动帮我们创建 PV。
- 自动创建的 PV 以
${namespace}-${pvcName}-${pvName}
这样的命名格式创建在 NFS 服务器上的共享数据目录中 - 而当这个 PV 被回收后会以
archieved-${namespace}-${pvcName}-${pvName}
这样的命名格式存在 NFS 服务器上。
当然在部署nfs-client
之前,我们需要先成功安装上 nfs 服务器,前面的课程中我们已经过了,服务地址是1192.168.3.131,共享数据目录是/data/k8s/,然后接下来我们部署 nfs-client 即可,我们也可以直接参考nfs-client 的文档,进行安装即可。
第一步:配置 Deployment,将里面的对应的参数替换成我们自己的 nfs 配置(nfs-client.yaml)
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: nfs-client-provisioner
spec:
replicas:
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: fuseim.pri/ifs
- name: NFS_SERVER
value: 192.168.3.131
- name: NFS_PATH
value: /data/k8s
volumes:
- name: nfs-client-root
nfs:
server: 192.168.3.131
path: /data/k8s
第二步:将环境变量 NFS_SERVER 和 NFS_PATH 替换,当然也包括下面的 nfs 配置,我们可以看到我们这里使用了一个名为 nfs-client-provisioner 的serviceAccount
,所以我们也需要创建一个 sa,然后绑定上对应的权限:(nfs-client-sa.yaml)
我们这里新建的一个名为 nfs-client-provisioner 的ServiceAccount
,然后绑定了一个名为 nfs-client-provisioner-runner 的ClusterRole
,而该ClusterRole
声明了一些权限,其中就包括对persistentvolumes
的增、删、改、查等权限,所以我们可以利用该ServiceAccount
来自动创建 PV。
第三步:nfs-client 的 Deployment 声明完成后,我们就可以来创建一个StorageClass
对象了:(nfs-client-class.yaml)
我们声明了一个名为 course-nfs-storage 的StorageClass
对象,注意下面的provisioner
对应的值一定要和上面的Deployment
下面的 PROVISIONER_NAME 这个环境变量的值一样。
现在我们来创建这些资源对象吧:
kubectl create -f nfs-client.yaml
kubectl create -f nfs-client-sa.yaml
kubectl create -f nfs-client-class.yaml
创建完成后查看下资源状态:
[root@localhost nfs]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nfs-client-provisioner-5db79cb75f-nk952 / ContainerCreating 12s
[root@localhost nfs]# kubectl get storageclass
NAME PROVISIONER AGE
course-nfs-storage fuseim.pri/ifs 31s
harbor-data fuseim.pri/ifs 90d
新建 StorageClass
上面把StorageClass
资源对象创建成功了,接下来我们来通过一个示例测试下动态 PV,首先创建一个 PVC 对象:(test-pvc.yaml)
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Mi
我们这里声明了一个PVC
对象,采用 ReadWriteMany
的访问模式,请求 1Mi 的空间,但是我们可以看到上面的 PVC 文件我们没有标识出任何和 StorageClass 相关联的信息,那么如果我们现在直接创建这个 PVC 对象能够自动绑定上合适的 PV 对象吗?显然是不能的(前提是没有合适的 PV),我们这里有两种方法可以来利用上面我们创建的 StorageClass 对象来自动帮我们创建一个合适的 PV:
- 第一种方法:在这个
PVC
对象中添加一个声明StorageClass
对象的标识,这里我们可以利用一个annotations
属性来标识,如下 kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-pvc
annotations:
volume.beta.kubernetes.io/storage-class: "course-nfs-storage"
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Mi- 第二种方法:我们可以设置这个 course-nfs-storage 的 StorageClass 为 Kubernetes 的默认存储后端,我们可以用
kubectl patch
命令来更新:yaml $ kubectl patch storageclass course-nfs-storage -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
上面这两种方法都是可以的,当然为了不影响系统的默认行为,我们这里还是采用第一种方法,直接创建即可:
上面这两种方法都是可以的,当然为了不影响系统的默认行为,我们这里还是采用第一种方法,直接创建即可:
(注意网络问题 这里需要拉取外网镜像)
kubectl create -f test-pvc.yaml
persistentvolumeclaim "test-pvc" created
[root@localhost nfs]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc-nfs Bound pv1 1Gi RWO 12h
test-pvc Bound pvc-a7293619-bb8c-11e9-93e7-000c29ecf8a8 1Mi RWX course-nfs-storage 11h
我们可以看到一个名为 test-pvc 的 PVC 对象创建成功了,状态已经是Bound
了,是不是也产生了一个对应的VOLUME
对象,最重要的一栏是STORAGECLASS
,现在是不是也有值了,就是我们刚刚创建的StorageClass
对象 course-nfs-storage。
然后查看下 PV 对象呢:
[root@localhost nfs]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-a7293619-bb8c-11e9-93e7-000c29ecf8a8 1Mi RWX Delete Bound default/test-pvc course-nfs-storage 3m48s
可以看到是不是自动生成了一个关联的 PV 对象,访问模式是RWX
,回收策略是 Delete
,这个 PV 对象并不是我们手动创建的吧,这是通过我们上面的 StorageClass
对象自动创建的。这就是 StorageClass 的创建方法。
OK,到这里我们大体明白了StorageClass的作用,下一篇我们会实际把它利用起来。