前言:K8S是一个成熟的容器业务集群管理方案,但是目前来讲,在存储方面显得过于复杂和繁琐,更不要说中间穿插着资源访问权限和认证的管理,尽管google在开源它之前有很多年的实战经验,但是从目前官方的发布文档来看,依然显得学习成本略高,我们来看看这个学习流程:
创新互联是专业的武鸣网站建设公司,武鸣接单;提供网站建设、做网站,网页设计,网站设计,建网站,PHP网站建设等专业做网站服务;采用PHP框架,可快速的进行武鸣网站开发网页制作和功能扩展;专业做搜索引擎喜爱的网站,专业的做网站团队,希望更多企业前来合作!
1,最初,学习k8s发现它罗列了一系列存储方案,无非就是对一系列本地和云存储的广泛支持:
看到这么多的存储卷类型的确很唬人,但是没有办法,在目前存储界没有达到统一(也不可能统一)之前,为了保持自己的强大的生态兼容性,K8S作出了无奈之举。
2,好在我们不需要学习每一种存储类型,只要要针对需要的存储卷类型进行了解和学习,接着,为了让Pod和存储资源管理解耦,K8S又引入了PV和PVC的概念,于是集群管理员和研发人员各司其职,但是带来了额外的PV和PVC的创建,删除以及存储卷的绑定和回收以及读写控制等资源管理工作。
3,当集群规模增长后,发现PV和PVC的管理开销惊人的时候,K8S又引入StorageClass的动态卷以及基于storageClass 的CSI的概念,这是目前K8S存储灵活分配的终极方案。
4,就在我们还没有完全理解StorageClass和CSI的时候,我们在官网又看到相关的Clone和Snapshot已经出来了。
说明一个问题,业务需求场景不断升级,业务需求量不断变大,解决方案也不断更新和变更,仅仅一个存储就前后涉及诸多概念,实在让人有点无所适从,弱水三千,取一瓢饮,今天这个实验是针对NFS的共享存储展开的。
为什么围绕NFS展开实验呢?因为从企业来讲,NFS共享在企业私有云内部非常容易取得,并且成本较低,一台普通的四盘位的企业级NAS服务器出厂即携带稳定可靠的NFS服务,无需自己部署,和企业的文件共享服务器集成,无需另外的硬件和部署成本。
首先,我们验证NAS服务器的NFS服务是否就位:
1,启动NFS客户端:
挂载前,请确保系统中已经安装了nfs-utils或nfs-common,安装方法如下:
CentOS:
yum install nfs-utils -y
注意:这一步是必须的,道理很简单,即便是K8S也没有什么神通,底层依然是通过nfs驱动去挂载文件系统,如果连nfs套件都不安装,哪怕K8S所有配置都正确无误,在创建接口pod的时候,会提示报错说NFS服务路径无法连接,为了体验这个错误,建议先不安装,假设你的nfs服务正常,后面再安装,就可以看到错误消失。
Ubuntu 或 Debian:
apt-get install nfs-common
创建挂载路径:
mkdir /nfs
确认远端NAS服务器上面存在的NFS服务和共享路径:
挂载NFS共享路径:
mount -t nfs NAS服务器的IP:/NAS-NFS
我们可以进入挂载路径尝试创建文件夹,看是否挂载成功并且读写正常;
容易出问题的是,挂载成功但是无法创建文件夹,提示文件系统只读,但是ls命令显示777,这是因为NAS服务器的NFS服务权限没有开放匿名访问的读写权限:
不同的NAS设备可能配置不太一样,请根据自己的NFS服务器的配置开启读写。
以上全部成功后进一步测试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展开):
其实动态存储的命名空间是任何一个都无所谓,因为动态创建的PV是集群级别的,可以被任何一个命名空间的pvc请求并绑定。
并且dashboard里面显示,绑定成功:
以上实验充分证明nfs系统工作正常,删除以上测试的内容,进行下一步。
注意:
如果不删除PVC来解除资源的占用,是无法直接删除PV并释放资源,违反K8S的持久化原则:
具体操作表现在三个方面:
1,kubectl delete pv 命令一直停留在执行状态不显示结果;
2,Dashboard资源对象一直正常显示存在,无视删除操作;
3,命令行强制退出删除命令,但是并不代表撤销删除操作,而是挂起,一直等待PVC手工清除,系统随即立即释放PV.
想要动态生成PV,需要运行一个NFS-Provisioner服务,将已配置好的NFS系统相关参数录入,向用户提供创建PV的服务。
官方推荐使用Deployment运行一个副本集来实现,当然也可以使用Daemonset等其他方式,这些都在官方文档中提供了。
apiVersion: v1 kind: ServiceAccount metadata: name: nfs-provisioner --- 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
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.yaml如下:
kind: StorageClass apiVersion: storage.k8s.io/v1 metadata: name: nfs provisioner: example.com/nfs
接下来要创建测试的PVC,以检测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
查看执行结果:
查看存储资源创建结果:
打开nfs的文件系统目录,发现和PV对应的资源文件夹自动生成:
文件夹的自动命名规则为pod的各种资源名称的集合。
进一步的,可以用kubectl exec -it 进入其中一个Pod中验证,可以看到K8S也不是神仙,也是通过mount的方式将NFS路径下生成一个临时路径挂载到容器内的指定的编排路径:
至此,实验基本完成。
github有官方上传的现成源码,和上面基本一致,此教程只是将过程详细证明出来:
https://github.com/kubernetes-incubator/external-storage/tree/master/nfs-client