前言
首先,你得有个 Ceph 集群,而这个集群具体怎么搭建,这里不展开说,有很多文章讲怎么搭建,至于其中方便点的部署方式,可以尝试使用 ceph-deploy。这里主要说的是,K8S 怎么使用 Ceph 存储,但经过一番探索,发现,K8S 支持 Ceph 共享存储这个事儿虽然不是很复杂,但问题是,想让 K8S 支持带配额能力的 Ceph 还是有那么一点麻烦的。
K8S 在使用共享存储时,其a支持很多 backend,比如 GlusterFS、Ceph,这2个比较典型。之所以选择用 Ceph ,主要有几个方面:
①:Ceph 目前更主流,更多主流大厂在使用,市场更好一些。
②:整体上看,性能上可能 Ceph 更好一些(这个可能仁者见仁智者见智,性能调优之后也不好说,而且他俩的适用场景本身就有一些区别,比如 GlusterFS 更适合存储大文件,但也有 GluterFS 对小文件存储的优化方式)
其实具体用哪个存储,还是要考后边的团队,对什么存储比较熟,更有掌控力。
另外,有些文章可能提到 CephFS(Ceph 文件存储)还不能用到生产环境,而且文章还是18年中旬,但很多英文文章都在17年提及,CephFS 早就 Production Ready 了。在生产环境使用应该问题不大,不过具体能不能在生产环境使用,可能还需要摸索一番。
K8S 如何使用共享存储
那么,K8S 在对分布式存储的支持上,主要有2种方式来做:
①:静态方式:PVC + PV
②:动态方式:PVC + StorageClass
静态方式:PV + PVC
PV 其实就是持久化Volume,它是资源的定义,比如说,存储空间多大、存储类型、存储后端等,它侧重于资源本身。
PVC 是一个声明,声明自己需要多少资源,声明需要多少资源,以及访问模式等,它侧重于“需求”。
在 K8S 中,我们可以为 POD 设置 ResourceRequest,比如 CPU、内存等,然后 K8S 为其匹配合适的 Node 节点,调度过去。同理,K8S 的 PVC 也是 ResourceRequest,只是 K8S 为其匹配的目标是 PV 而已。有一点不同,K8S 为 PVC 匹配得到 PV 后,会做一个绑定,这就意味着,一个 PVC,绑定一个 PV 后,PV 的状态就会变为 Bound(束缚),两者绑定后,不会再与其他资源匹配。
使用 PV 和 PVC 模式,需要注意的是 PV。PVC很简单,但 PV 有点麻烦,其中涉及很多内容,以一个 PV 示例来说:
1 | apiVersion: v1 |
PVC 示例如下:
1 | apiVersion: v1 |
其中的 PV 里的 path 内容,需要我们提前去分布式存储系统上创建好。包括配额,也需要先做好才行。
这就有点麻烦了,我们每次创建一个 PV 之前,需要先在分布式存储系统,创建好path。但频繁这么去做,成本是有点大。所以,K8S 也有一个动态方式。
注意:PVC 有命名空间、PV 没有命名空间。
动态方式:PVC + StorageClass
动态的方式,需要借助 PVC + StorageClass ,PVC 不用说了,主要说一下 StorageClass。先来看一个 StorageClass 示例:
1 | apiVersion: storage.k8s.io/v1 |
StorageClass 定义了后端存储系统的:类型、 servers、根目录、回收策略等。
我们在创建了 PVC(持久化Volume资源声明)后,K8S 会根据 PVC 和 和 StorageClass,动态创建 PV,然后动态自行去分布式存储系统进行创建目录操作,然后进行挂载,最终映射到 POD 内。用动态方式的好处是,我们只关心资源需求 PVC 就可以了,非常方便。
但是:目前 K8S所有版本(截止到 v1.12.3),对动态方式的支持,还不全面。仅支持一些分布式存储,比如:
Volume Plugin | Internal Provisioner | Config Example |
---|---|---|
CephFS | - | - |
Glusterfs | ✔️ | Glusterfs |
注意:Ceph 和 CephFS 不一样,Ceph 是整个服务,而 CephFS 仅仅是 Ceph 的文件存储而已。Ceph 除了文件存储 CephFS 外,还支持 对象存储、块存储。
从上面来看,K8S 根本不支持 CephFS 的 动态管理文件存储支持,所以,要么,我们需要寻找一种使其支持的方式,要么,转投 GlusterFS。我们要做的,就是寻找方式,动态管理 CephFS 的文件存储。
让K8S支持动态管理CephFS(并支持配额)
这里要提一下 K8S 能够支持动态存储管理的简单原理了。
要做到动态存储管理,就意味着2点:
①:用户只需要创建 PVC 资源。
②:K8S 需要监听 PVC 资源的变化,动态创建 PV。
③:用户需要在 POD 中使用 PVC 资源。
④:K8S 需要能够在宿主机创建 Volume。
安装 cephfs-provisioner
其实,在 Kubernetes incubator (K8S 孵化器组)中,专门有一个外部存储支持的项目:https://github.com/kubernetes-incubator/external-storage/ 。这个项目中,有关于 Ceph 动态存储管理的方式,换句话说,这不是官方原装的,所以,我们需要安装它。
在 K8S 中,安装这个项目比较简单,这个项目中,也给出了 deploy 示例。总的来说,需要单独创建 ServiceAccount、Role、ClusterRole、RoleBinding、ClusterRoleBinding 等资源。
其中 ClusterRole 主要用来获取 K8S 监听和操作 PVC、PV 资源的权限、Role 是获取 Secret 资源的权限,因为 K8S 要操作 Ceph 集群,就需要认证信息,而认证信息就是放到 Secret 资源中的。下面是具体的创建内容:
①:首先是 Secret 资源,这个 CephFS 集群的访问权限(文件名如:ceph-secret-admin.yaml ),这个数据,需要你先去 CephFS 集群,通过下面方式获取:
1 | ceph auth get-key client.admin | base64 |
然后,将上面的结果,放到下面的 key 的内容中:
1 | apiVersion: v1 |
②:创建 ClusterRole 资源,clusterrolebinding.yaml
1 | kind: ClusterRoleBinding |
③:创建 ClusterRolebinding 资源,clusterrolebinding.yaml
1 | kind: ClusterRoleBinding |
④:创建 Role 资源,role.yaml
1 | apiVersion: rbac.authorization.k8s.io/v1 |
⑤:创建 Rolebinding 资源,rolebinding.yaml
1 | apiVersion: rbac.authorization.k8s.io/v1 |
⑥:创建 ServiceAccount 资源,serviceaccount.yaml
1 | apiVersion: rbac.authorization.k8s.io/v1 |
⑦:创建 StorageClass 资源,storageClass.yaml
1 | kind: StorageClass |
⑧:创建 cephfs-provisioner 的 Deployment 资源,cephfs-provisioner-deployment.yaml
1 | apiVersion: extensions/v1beta1 |
好了,执行下面的命令,进行资源创建:
1 | // 创建 Namespace |
如果如上操作后,cephfs-provisioner 就已经安装好了。上面的文件比较多,其中有几个需要注意的地方:
cephfs-provisioner Deployment 的 args 参数中,有一个 -enable-quota=true ,这个不写的话,是无法做到磁盘配额的。
创建完成后,在 cephfs 命令空间下,会有 cephfs-provisioner 的实例:
1 | [root@nodex test] |
测试CephFS动态管理
上面准备工作 cephfs-provisioner 已经安装好,下面就需要测试了,我们测试,其实仅需要创建2个资源,一个是 PVC、一个是 Deployment 的 POD 资源。
PVC 资源:pvc.yaml
1 | kind: PersistentVolumeClaim |
Deployment 资源:deploy.yaml
1 | apiVersion: extensions/v1beta1 |
然后,分别用 kubectl apply -f 文件名 创建即可。
问题处理
创建后,我们需要观察在 cephfs 命名空间下,有没有自动创建出来 pv。
1 | kubectl get pv -n cephfs -w |
如果自动创建,且后期自动完成了匹配,且 nginx POD 创建后变为 Running ,则表示一切正常。但往往事实并不如人意。我们可能遇到下面几个问题:
①:PV 没有自动创建出来。
②:我们使用了共享存储的 nginx 示例 POD 一直是 ContainerCreating 状态。
PV 无法自动创建问题
如果是 PV 没自动创建出来 ,说明 cephfs-provisioner 有问题,它没能创建好相关的资源,我们主要看它的日志信息
1 | kubectl logs -n cephfs cephfs-provisioner-6f77cd58b4-75hll |
通常来说,PV 没创建出来最大的可能就是出在 cephfs-provisioner-6f77cd58b4-75hll 这个 POD 上,其实这个 POD 做的工作主要有几个:
①:连接 CephFS 集群
②:创建 Volume
③:设置配额属性,setxattr
④:创建 PV
而这个 cephfs-provisioner 本身操作 CephFS 集群的方式,其实是通过 Golang,调用的 Python 脚本来做的这个事情。如果观察其 log ,出错在 setxattr 部分,则最大的可能性,就是版本问题。
cephfs-provisioner 处理方式如下:
官方的镜像,在我们之前的 cephfs-provisioner-deployment.yaml 中,其实它使用的 Ceph 的版本,默认是 mimic ,可以从这里看:https://github.com/kubernetes-incubator/external-storage/blob/master/ceph/cephfs/Dockerfile ,而我们的 Ceph 版本,是 hammer,而官方并没有提供 hammer 版本的 cephfs-provisioner,所以,我们只能自己来构建。构建步骤如下:
- 克隆 https://github.com/kubernetes-incubator/external-storage 项目。
- 进入 ceph/cephfs 目录下
- 修改 Dockerfile ,将 CEPH_VERSION 里的 mimic ,改为 hammer 。
- 修改 Makefile,将 REGISTRY 里的地址,改为私有镜像仓库地址,目的是推送镜像使用。
- 执行 make && make push 。
完成后,更改 deploy.yaml 里 image 为新镜像地址,然后执行 kubectl apply -f deploy.yaml
完成后,观测 cephfs-provisioner POD 正常启动,同时看到 PV 自动被创建出来了。
POD持续ContainerCreating状态处理
这种问题,很有可能是 POD 使用了 PVC 形式的 Volume,而这个 Volume 却迟迟无法创建出来,所以,这时候,可以通过 kubectl describe 来看具体原因
1 | kubectl describe pod -n cephfs nginx-use-rbd-dcfb58dc6-8f7gj |
1 | [root@node008037 glusterfs] |
如果通过结果能看到相关 Volume 信息,且在不断输出重试内容,则大概能说明是 Volume 无法创建,进而无法挂载到容器内部导致的
1 | Events: |
这种情况其实是宿主机缺少 ceph 的 client 工具,可以通过下面的方式解决:
1 | // centos 系统 |
安装结束后,k8s 会自动尝试重新挂载。
参考
- https://kubernetes.io/docs/concepts/storage/persistent-volumes/
- https://blog.csdn.net/xudawenfighting/article/details/80125389
- https://www.cnblogs.com/hukey/p/8323853.html
- https://www.cnblogs.com/yangxiaoyi/p/7795274.html
- http://dockone.io/article/558
- https://www.cnblogs.com/yswenli/p/7234579.html
- https://www.jianshu.com/p/a4e1ba361cc9
- https://www.cnblogs.com/ltxdzh/p/9173706.html
- https://baijiahao.baidu.com/s?id=1612194635156434300&wfr=spider&for=pc
- http://blog.chinaunix.net/uid-22166872-id-4959819.html
- https://www.gluster.org/glusterfs-vs-ceph/
- http://www.sysnote.org/