Zer0e's Blog

【架构之路3】k8s对接cephfs

字数统计: 1.8k阅读时长: 8 min
2024/07/11 Share

前言

上篇讲了ceph集群的搭建,这篇就来对接k8s存储。

ceph对接k8s在比较新的k8s版本中废弃了对ceph的官方支持,转为社区维护ceph-csi驱动,但是纵观我能搜索到的网上的中文教程,还有驱动官方的readme,都写的不咋样。

ceph接入k8s常见的有两种方式,一种是ceph-rbd,另一种是ceph-fs,两者各有优劣,网上也有性能测试,对k8s而言,rbd不支持ReadWriteMany模式。这篇就来讲讲cephfs和k8s是如何对接的。

正文

cephfs接入k8s

打开驱动官方github地址。由于我们的k8s集群版本是1.29,因此驱动版本就使用3.11.0。

打开deploy-cephfs.md.可以看到教程很复杂,需要部署好几个yaml,但其实根本没那么复杂。。。最简单的方法就是helm.

helm是k8s的包管理工具,可以理解成pip或者npm的作用。官方其实提供了chart包供我们使用。

先安装helm,记得export代理

1
2
3
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
chmod 700 get_helm.sh
./get_helm.sh

安装完成后添加csi的repo

1
helm repo add ceph-csi https://ceph.github.io/csi-charts

先创建k8s命名空间,然后安装ceph-csi-cephfs

1
2
kubectl create namespace ceph-csi-cephfs
helm install --namespace "ceph-csi-cephfs" "ceph-csi-cephfs" ceph-csi/ceph-csi-cephfs

可以加上--version指定版本

等待安装部署完成。

部署完成后,可以在kubepi上看到ceph-csi-cephfs-nodeplugin和ceph-csi-cephfs-provisioner容器在三个节点上运行,说明就成功了,接下来我们就配置如何和ceph对接。

cephfs pool创建

我们需要在ceph上创建两个pool用于构建cephfs,在主节点执行

1
2
ceph osd pool create cephfs_k8s_metadata 64
ceph osd pool create cephfs_k8s_data 64

最后一个参数pg_num与osd数量相关,我只有三个osd因此我只能设置到64.

接着创建ceph fs

1
ceph fs new cephfs_k8s cephfs_k8s_metadata cephfs_k8s_data

设置mds

1
ceph fs set cephfs_k8s max_mds 2

创建subvolumegroup

1
ceph fs subvolumegroup create cephfs_k8s csi

我们创建获取两个token用于后续k8s与ceph通信。

1
2
3
4
// 注意 client.k8s.cephfs必须以client开头
ceph auth get-or-create client.k8s.cephfs mon 'allow r' mds 'allow rw' osd 'allow rw pool=cephfs_k8s_data, allow rw pool=cephfs_k8s_metadata'
// 记录返回的key
ceph auth get-key client.admin

分别获取k8s.cephfs和admin的token

利用storageclass自动创建pv

首先我们在ceph-csi-cephfs命名空间下可以看到名为ceph-csi-config的configMap,我们要修改它。主要修改的是config.json的内容。其中clusterID可用通过ceph -s获取。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
kubectl edit configmap ceph-csi-config -n ceph-csi-cephfs

apiVersion: v1
data:
config.json: |-
[
{
"clusterID": "ed91a6b4-3df6-11ef-9d94-000c29a7737d",
"monitors": [
"192.168.28.138:6789",
"192.168.28.139:6789",
"192.168.28.140:6789"
]
}
]
kind: ConfigMap
metadata:
annotations:
meta.helm.sh/release-name: ceph-csi-cephfs
creationTimestamp: "2024-07-10T19:38:16Z"
labels:
app: ceph-csi-cephfs
app.kubernetes.io/managed-by: Helm
chart: ceph-csi-cephfs-3.11.0
component: provisioner
heritage: Helm
release: ceph-csi-cephfs
name: ceph-csi-config
namespace: ceph-csi-cephfs
resourceVersion: "78500"
uid: 3ea503de-238f-41b8-b96c-7f54ae00effb

创建secret,将上面获取的两个token填入,vim ceph-secret.yaml

1
2
3
4
5
6
7
8
9
10
apiVersion: v1
kind: Secret
metadata:
name: csi-cephfs-secret
namespace: ceph-csi-cephfs
stringData:
userID: k8s.cephfs
userKey: AQDE049mVf8vOBAA8f4LpLckjoS6Qbhbrgr9Tw==
adminID: admin
adminKey: AQCwOo1mbQ+nFxAA5CZ4VajvzDCRd5Gpaxe6kw==

接着我们创建storageclass,vim storageclass.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: csi-cephfs-sc
provisioner: cephfs.csi.ceph.com
parameters:
clusterID: ed91a6b4-3df6-11ef-9d94-000c29a7737d
fsName: cephfs_k8s
pool: cephfs_k8s_data

csi.storage.k8s.io/provisioner-secret-name: csi-cephfs-secret
csi.storage.k8s.io/provisioner-secret-namespace: ceph-csi-cephfs
csi.storage.k8s.io/controller-expand-secret-name: csi-cephfs-secret
csi.storage.k8s.io/controller-expand-secret-namespace: ceph-csi-cephfs
csi.storage.k8s.io/node-stage-secret-name: csi-cephfs-secret
csi.storage.k8s.io/node-stage-secret-namespace: ceph-csi-cephfs

# 生产环境建议改成Retain
reclaimPolicy: Delete
allowVolumeExpansion: true
# 注意这里mountOptions不要有任何东西
# mountOptions:
# - context="system_u:object_r:container_file_t:s0:c0,c1"

部署secret和storageclass

1
2
kubectl apply -f ceph-secret.yaml
kubectl apply -f storageclass.yaml

至此,申请pvc时,将会自动向ceph集群申请存储卷,并自动创建pv。

创建测试容器

先创建一个pvc。

1
2
3
4
5
6
7
8
9
10
11
12
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: csi-cephfs-pvc-test
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 2Gi
storageClassName: csi-cephfs-sc

记得apply一下。

如果发现pv无法自动创建出来,记得检查下密码或者subvolume是否创建出来,可以到csi-provisioner看看日志。

再创建一个nginx测试好了,vim nginx-deployment.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx-pod
template:
metadata:
labels:
app: nginx-pod
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: mypvc
mountPath: /usr/share/nginx/html
volumes:
- name: mypvc
persistentVolumeClaim:
claimName: csi-cephfs-pvc-test
readOnly: false
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx-pod
type: NodePort
ports:
- port: 80
targetPort: 80

apply一下看看。

1
2
kubectl get pods
kubectl get svc -o wide

如果容器不是pending,那么说明挂载成功了。我们获取访问端口看看。

1
2
nginx-service   NodePort    10.43.24.66   <none>        80:31162/TCP   29h    app=nginx-pod
curl http://worker1:31162/

这里提示403是正常的,因为我们挂载的根节点没有东西。

我们进入容器内随意加点东西,可以通过kubepi的进入终端方便一点,也可以kubectl exec -it nginx-deployment-7c565ff488-qqfkz -- /bin/bash

1
2
cd /usr/share/nginx/html/
echo `date` > index.html

再访问发现正常了。

接下来我们结束容器让其重新部署看看。

1
kubectl delete pod nginx-deployment-7c565ff488-qqfkz

刚才pod部署在节点3,现在删除后重新部署在了节点2,再次访问http://worker1:31162/可以看到我们的更改还在。

至此我们便完成了cephfs与k8s的对接,值得一提的是这种方式是支持动态扩容的。只需修改pvc的容量,pv的容量也会自动调整。

至此我们搭建就完成了,但是也存在一些问题。

问题

经常性自动创建PV失败

当声明pvc后,csi-ceph的插件容器会自动向ceph集群创建volume,GRPC调用/csi.v1.Controller/CreateVolume,但是第一次请求总是没有响应,可能是因为超时,所以后续会重复调用CreateVolume,导致后续请求响应都是an operation with the given Volume ID xxx already exists.我看了下默认的超时时间是60s,provisioner.timeout,可能是我ceph集群性能不好,没找到原因,但是我重启虚拟机后又正常了,奇怪。

pv无法自动回收

通过storageclass创建的pv,当删除pvc时,pv会被标记为release,但是回收会出现问题,导致pv资源一直存在。看了容器日志应该是和ceph集群通信有问题,导致删除失败,GRPC调用/csi.v1.Controller/DeleteVolume似乎超时了,后续再调用时和上面问题一样一直出现 already exists。这个目前没有找到解决办法。

自动回收不适用生产环境

storageclass中的reclaimPolicy应该修改为Retain,保证数据安全。

总结

尽管搭建了ceph集群,并且使用cephfs对接了k8s,但实际上体验不是很好,不知道是虚拟硬盘导致的ceph集群问题,还是本身就有bug存在,总之一番体验下来,不建议使用cephfs对接k8s。

至于为什么不手动创建pv,是因为网上那些例子其实都是过时的,从k8s1.28开始就已经将pv里的spec.cephfs标记为过时了,并且这种方式需要在pv里声明monitor的地址列表,当pv数量足够多时很难去管理。

目前上一家公司用的就是ceph-rbd对接的k8s。看下后续的ceph-rbd对接能不能有更好的体验,如果还是存在问题,那就是我的ceph集群有问题。

原文作者:Zer0e

原文链接:https://re0.top/2024/07/11/devops3/

发表日期:July 11th 2024, 9:30:00 pm

更新日期:July 12th 2024, 2:30:31 pm

版权声明:本文采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可

CATALOG
  1. 1. 前言
  2. 2. 正文
    1. 2.1. cephfs接入k8s
    2. 2.2. cephfs pool创建
    3. 2.3. 利用storageclass自动创建pv
    4. 2.4. 创建测试容器
  3. 3. 问题
    1. 3.1. 经常性自动创建PV失败
    2. 3.2. pv无法自动回收
    3. 3.3. 自动回收不适用生产环境
  4. 4. 总结