前言:K8S是一个成熟的容器业务集群管理方案,但是目前来讲,在存储方面显得过于复杂和繁琐,更不要说中间穿插着资源访问权限和认证的管理,尽管google在开源它之前有很多年的实战经验,但是从目前官方的发布文档来看,依然显得学习成本略高,我们来看看这个学习流程:

1,最初,学习k8s发现它罗列了一系列存储方案,无非就是对一系列本地和云存储的广泛支持:

以上全部成功后进一步测试NFS共享存储在PV,PVC中是否工作正常:

2,创建测试的静态PV和PVC

pv.yml

apiVersion:?v1
kind:?PersistentVolume
metadata:
??name:?mypv1
spec:
??capacity:
????storage:?4Gi
??accessModes:
????-?ReadWriteOnce
??persistentVolumeReclaimPolicy:?Recycle
??nfs:
????path:?/NAS-NFS
????server:?[NAS服务器IP或域名]

pvc.yml

kind:?PersistentVolumeClaim
apiVersion:?v1
metadata:
??name:?mypvc1
spec:
??accessModes:
????-?ReadWriteOnce
??resources:
????requests:
??????storage:?100Mi

开始创建资源对象(为了简化实验,所有资源对象都是默认的命名空间default展开):

以上实验充分证明nfs系统工作正常,删除以上测试的内容,进行下一步。

注意:

如果不删除PVC来解除资源的占用,是无法直接删除PV并释放资源,

具体操作表现在三个方面:

1,kubectl delete命令一直停留在执行状态不显示结果;

2,Dashboard资源对象一直正常显示存在,无视删除操作;

3,命令行强制退出删除命令,但是并不代表撤销删除操作,而是挂起,一直等待PVC手工清除,随即立即删除PV.


想要动态生成PV,需要运行一个NFS-Provisioner服务,将已配置好的NFS系统相关参数录入,向用户提供创建PV的服务。

官方推荐使用Deployment运行一个副本集来实现,当然也可以使用Daemonset等其他方式,这些都在官方文档中提供了。

创建持久卷的服务访问角色,角色绑定,权限分配供Provisioner角色后台调用:

编写serviceaccount.yaml文件如下:

apiVersion:?v1
kind:?ServiceAccount
metadata:
??name:?nfs-provisioner

编写rbac.yaml文件如下:

kind:?ClusterRole
apiVersion:?rbac.authorization.k8s.io/v1
metadata:
??name:?nfs-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:?["create",?"update",?"patch"]
---
kind:?ClusterRoleBinding
apiVersion:?rbac.authorization.k8s.io/v1
metadata:
??name:?run-nfs-provisioner
subjects:
??-?kind:?ServiceAccount
????name:?nfs-provisioner
????namespace:?default
roleRef:
??kind:?ClusterRole
??name:?nfs-provisioner-runner
??apiGroup:?rbac.authorization.k8s.io
---
kind:?Role
apiVersion:?rbac.authorization.k8s.io/v1
metadata:
??name:?leader-locking-nfs-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-provisioner
subjects:
??-?kind:?ServiceAccount
????name:?nfs-provisioner
????#?replace?with?namespace?where?provisioner?is?deployed
????namespace:?default
roleRef:
??kind:?Role
??name:?leader-locking-nfs-provisioner
??apiGroup:?rbac.authorization.k8s.io

创建NFS服务的provisioner角色,部署结果是得到一个Pod来响应各种cliet提交的存储资源请求:

编写deployment.yaml文件如下:

kind:?Deployment
apiVersion:?extensions/v1beta1
metadata:
??name:?nfs-provisioner
spec:
??replicas:?1
??strategy:
????type:?Recreate
??template:
????metadata:
??????labels:
????????app:?nfs-provisioner
????spec:
??????serviceAccount:?nfs-provisioner
??????containers:
????????-?name:?nfs-provisioner
??????????image:?registry.cn-hangzhou.aliyuncs.com/open-ali/nfs-client-provisioner
???????????#官方镜像:quay.io/external_storage/nfs-client-provisioner:latest?无法下载,使用上面阿里云镜像代替
??????????volumeMounts:
????????????-?name:?nfs-client-root
??????????????mountPath:?/persistentvolumes
??????????env:
????????????-?name:?PROVISIONER_NAME
??????????????value:?example.com/nfs
????????????-?name:?NFS_SERVER
??????????????value:?[NAS服务器的IP地址]
????????????-?name:?NFS_PATH
??????????????value:?/NAS-NFS???#NFS系统的挂载路径
??????volumes:
????????-?name:?nfs-client-root
??????????nfs:
????????????server:?[NAS服务器的IP地址]
????????????path:?/NAS-NFS???#NFS系统的挂载路径

将以上文件通过kubectl命令创建完毕后,我们查看K8S部署结果:

我们得到一个副本集和这个副本集启动一个Pod,来充当nfs-client-provisioner角色,这个角色用来响应各种存储资源请求,但是并不能直接使用,需要用StorageClass去触发。

创建存储类StorageClass

编写并创建storageclass.yaml如下:

kind:?StorageClass
apiVersion:?storage.k8s.io/v1
metadata:
??name:?nfs
provisioner:?example.com/nfs

接下来要创建测试的claim,以检测StorageClass能否正常工作:

编写并创建test-claim.yaml如下,注意storageClassName应确保与上面创建的StorageClass名称一致。

kind:?PersistentVolumeClaim
apiVersion:?v1
metadata:
??name:?test-claim1
spec:
??accessModes:
????-?ReadWriteMany
??resources:
????requests:
??????storage:?1Mi
??storageClassName:?nfs???#这里和创建的SC名称保持一致

创建后,用kubectl get pvc查看,观察新创建的PVC能够自动绑定PV。

创建一个测试的Pod使用这个PVC,编写test-pod.yaml文件如下:

kind:?Pod
apiVersion:?v1
metadata:
??name:?test-pod
spec:
??containers:
??-?name:?test-pod
????image:?busybox
????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-claim1

查看Pod状态是否变为Completed。如果是,则应该能在NFS系统的共享路径中看到一个SUCCESS文件。

这样,StorageClass动态创建PV的功能就成功实现了。

普通的pod是在编排文件里面通过声明预先手工创建PVC去请求storageclass来自动获取动态卷,实际上这种自动由于PVC的存在也属于半自动,还是不够灵活,所以,官方推荐使用statefulset;

编写statefulset.yaml文件如下:

apiVersion:?apps/v1beta1
kind:?StatefulSet
metadata:
??name:?web
spec:
??serviceName:?"nginx1"
??replicas:?2
??volumeClaimTemplates:
??-?metadata:
??????name:?test
??????annotations:
????????volume.beta.kubernetes.io/storage-class:?"nfs"???#?nfs和前面定义的storageclass的名称保持一致
????spec:
??????accessModes:?[?"ReadWriteOnce"?]
??????resources:
????????requests:
??????????storage:?1Gi
??template:
????metadata:
??????labels:
????????app:?nginx1
????spec:
??????serviceAccount:?nfs-provisioner?????#和前面创建的资源访问角色保持一致
??????containers:
??????-?name:?nginx1
????????image:?nginx
????????imagePullPolicy:?IfNotPresent
????????volumeMounts:
????????-?mountPath:?"/my_dir"??#此挂载路径可以任意指定
??????????name:?test

查看执行结果: