上面介绍的PV和PVC模式是需要运维人员先创建好PV,然后开发人员定义好PVC进行一对一的Bond,但是如果PVC请求成千上万,那么就需要创建成千上万的PV,对于运维人员来说维护成本很高,Kubernetes提供一种自动创建PV的机制,叫StorageClass,它的作用就是创建PV的模板。
具体来说,StorageClass会定义一下两部分:
- PV的属性 ,比如存储的大小、类型等;
- 创建这种PV需要使用到的存储插件,比如Ceph等;
有了这两部分信息,Kubernetes就能够根据用户提交的PVC,找到对应的StorageClass,然后Kubernetes就会调用 StorageClass声明的存储插件,创建出需要的PV。
这里我们以NFS为例,要使用NFS,我们就需要一个nfs-client的自动装载程序,我们称之为Provisioner,这个程序会使用我们已经配置好的NFS服务器自动创建持久卷,也就是自动帮我们创建PV。
说明:
- 自动创建的PV会以${namespace}-${pvcName}-${pvName}的目录格式放到NFS服务器上;
- 如果这个PV被回收,则会以archieved-${namespace}-${pvcName}-${pvName}这样的格式存放到NFS服务器上;
详细可以参考:https://github.com/kubernetes-incubator/external-storage/tree/master/nfs-client
在部署之前,首先得确保有可用得NFS服务器,这里默认已经有可用得NFS服务器了。
1、创建ServiceAccount,为nfs-client授权。
nfs-client-sa.yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-client-provisioner
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: nfs-client-provisioner-clusterrole
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"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: nfs-client-provisioner-clusterrolebinding
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
namespace: default
roleRef:
kind: ClusterRole
name: nfs-client-provisioner-clusterrole
apiGroup: rbac.authorization.k8s.io
通过上面得配置,设置nfs-client对PV,PVC,StorageClass等得规则。接下来我们创建这个YAML文件:
[root@master storageclass]# kubectl apply -f nfs-client-sa.yaml
serviceaccount/nfs-client-provisioner created
clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-clusterrole created
clusterrolebinding.rbac.authorization.k8s.io/nfs-client-provisioner-clusterrolebinding created
2、创建nfs-client
使用Deployment来创建nfs-client,配置如下:
nfs-client.yaml
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-client-prosioner
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: nfs-client-prosioner
template:
metadata:
labels:
app: nfs-client-prosioner
spec:
serviceAccountName: nfs-client-provisioner
containers:
- name: nfs-client-prosioner
image: registry.cn-hangzhou.aliyuncs.com/rookieops/nfs-client-provisioner:v0.1
imagePullPolicy: IfNotPresent
volumeMounts:
- name: nfs-client-root
mountPath: /data/pv
env:
- name: PROVISIONER_NAME
value: rookieops/nfs
- name: NFS_SERVER
value: 192.168.0.177
- name: NFS_PATH
value: /data/k8s
volumes:
- name: nfs-client-root
nfs:
server: 192.168.0.177
path: /data/k8s
然后创建这个YAML文件。
[root@master storageclass]# kubectl apply -f nfs-client.yaml
deployment.extensions/nfs-client-prosioner created
查看其状态:
[root@master storageclass]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nfs-client-prosioner-66c9bb7f88-q2qm4 1/1 Running 0 52m
3、上面得创建完成后就可以创建StorageClass了。
nfs-client-storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-client-storageclass
provisioner: rookieops/nfs
注意provisioner必须和上面得Deployment的YAML文件中PROVISIONER_NAME的值保持一致。
创建这个YAML文件:
[root@master storageclass]# kubectl apply -f nfs-client-storageclass.yaml
storageclass.storage.k8s.io/nfs-client-storageclass created
[root@master storageclass]# kubectl get storageclass
NAME PROVISIONER AGE
nfs-client-storageclass fuseim.pri/ifs 15s
4、创建PVC
test-nfs-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: test-nfs-pvc2
annotations:
volume.beta.kubernetes.io/storage-class: "nfs-client-storageclass"
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Mi
annotations的作用是在PVC里声明一个StorageClass对象的标识。
创建这个YAML文件,观察其状态:
[root@master storageclass]# kubectl apply -f test-pvc.yaml
persistentvolumeclaim/test-nfs-pvc created
[root@master storageclass]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
test-nfs-pvc Bound pvc-e5b8765b-1d7b-4529-860f-bbe34e0b4109 1Mi RWX nfs-client-storageclass 2m16s
我们看到该PVC自动申请到空间,其STORAGECLASS就是我们创建的nfs-client-storageclass。
5、创建一个Pod,进行测试
test-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: test-storageclass-pod
spec:
containers:
- name: busybox
image: busybox:latest
imagePullPolicy: IfNotPresent
command:
- "/bin/sh"
- "-c"
args:
- "sleep 3600"
volumeMounts:
- name: nfs-pvc
mountPath: /mnt
restartPolicy: Never
volumes:
- name: nfs-pvc
persistentVolumeClaim:
claimName: test-nfs-pvc2
然后查看NFS服务器上是否生成对应的目录:
[root@master k8s]# ll
total 0
drwxrwxrwx 2 root root 6 Oct 29 17:21 default-test-nfs-pvc2-pvc-91671ba7-8da8-4611-8bd5-3673f63d15cb
我们可以看到生成了对应的目录,格式和我们上面说的一致。现在进Pod向该目录下写一个文件,然后查看NFS服务器上是否存在该文件:
[root@master storageclass]# kubectl exec -it test-storageclass-pod -- /bin/sh
/ # cd /mnt/
/mnt # echo "hello,I am NFS Server!" > test
/mnt # ls
test
[root@master default-test-nfs-pvc2-pvc-91671ba7-8da8-4611-8bd5-3673f63d15cb]# ls
test
[root@master default-test-nfs-pvc2-pvc-91671ba7-8da8-4611-8bd5-3673f63d15cb]# cat test
hello,I am NFS Server!
我们发现NFS服务器上存在,说明我们验证成功。
另外我们可以看到我们这里是手动创建的一个 PVC 对象,在实际工作中,使用 StorageClass 更多的是 StatefulSet 类型的服务,StatefulSet 类型的服务我们也可以通过一个 volumeClaimTemplates 属性来直接使用 StorageClass,如下:(test-statefulset-nfs.yaml)
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: nfs-web
spec:
serviceName: "nginx"
replicas: 2
template:
metadata:
labels:
app: nfs-web
spec:
terminationGracePeriodSeconds: 10
containers:
- name: nginx
image: nginx:1.7.9
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: nfs-client-storageclass
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
可以看到volumeClaimTemplates就是我们上面的PVC模板。然后我们创建这个文件:
[root@master storageclass]# kubectl apply -f test-statefulset.yaml
statefulset.apps/nfs-web created
[root@master storageclass]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
www-nfs-web-0 Bound pvc-5df69dbe-8b54-45dd-acd0-769c0c9ee1b8 1Gi RWO nfs-client-storageclass 7s
www-nfs-web-1 Bound pvc-0e83fef9-ec16-4e02-8482-7e04b7c81c92 1Gi RWO nfs-client-storageclass 3s
可以看到会自动生成两个PVC。
在NFS服务器上也可以看到正常创建了目录:
[root@master k8s]# ll
total 0
drwxrwxrwx 2 root root 18 Oct 29 17:29 default-test-nfs-pvc2-pvc-91671ba7-8da8-4611-8bd5-3673f63d15cb
drwxrwxrwx 2 root root 6 Oct 29 17:34 default-www-nfs-web-0-pvc-5df69dbe-8b54-45dd-acd0-769c0c9ee1b8
drwxrwxrwx 2 root root 6 Oct 29 17:34 default-www-nfs-web-1-pvc-0e83fef9-ec16-4e02-8482-7e04b7c81c92
补充
(1)标记默认 StorageClass 非默认
kubectl patch storageclass standard -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'
(2)标记一个 StorageClass 为默认
kubectl patch storageclass <your-class-name> -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'