上篇文章介绍了kubernetes使用Ceph RBD进行数据持久化存储,在总结部分也说了RBD 块存储设备,只支持单节点的读写和多节点只读的功能,但是有些业务需要多节点对数据进行读写,这就需要使用我们接下来介绍的cephfs文件系统,使用它来实现多节点数据的读写。

cephfs介绍

cephfs是ceph提供的兼容POSIX协议的文件系统,对比RBD和RGW功能,这个是ceph里最晚满足production ready的一个功能,它底层还是使用rados存储数据。

cephfs的架构


cephfs

cephfs的使用方式

  • cephfs kernel module
  • cephfs-fuse

从上面的架构图中可以看到,cephfs-fuse的方式比cephfs kernel module方式在性能方面会差一些。

创建cephfs

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
1. 创建云数据服务器MDS
[root@ceph-admin ~]# ceph-deploy mds create ceph-admin ceph-01 ceph-02 ceph-03

[root@ceph-admin ~]# ceph mds stat
e8: 1/1/1 up {0=ceph-03=up:active}, 3 up:standby

检查是否启动成功:
[root@ceph-admin ~]# ps aux | grep ceph-mds
ceph 510 0.0 0.7 675592 28964 ? Ssl Apr02 2:20 /usr/bin/ceph-mds -f --cluster ceph --id ceph-admin --setuser ceph --setgroup ceph

2.创建 cephfs
[root@ceph-admin ~]# ceph osd pool create cephfs_data 128
pool 'cephfs_data' created
[root@ceph-admin ~]# ceph osd pool create cephfs_metadata 128
pool 'cephfs_metadata' created
[root@ceph-admin ~]# ceph fs new cephfs cephfs_metadata cephfs_data
new fs with metadata pool 2 and data pool 1
[root@ceph-admin ~]# ceph fs ls
name: cephfs, metadata pool: cephfs_metadata, data pools: [cephfs_data ]

3. 创建认证文件 admin.secret
[root@ceph-admin ~]# cat /etc/ceph/ceph.client.admin.keyring
[client.admin]
key = AQBJd7dar15/HhAAqvUP2INiJhfA6uJ5AQ914Q==
caps mds = "allow *"
caps mon = "allow *"
caps osd = "allow *"

[root@ceph-admin ~]# cat /etc/ceph/admin.secret
AQBJd7dar15/HhAAqvUP2INiJhfA6uJ5AQ914Q==

4.挂载cephfs文件系统
[root@ceph-admin ~]# mkdir /mnt/cephfs/
[root@ceph-admin ~]# mount -t ceph mon-hosts:6789:/kube /mnt/cephfs -o name=admin,secretfile=/etc/ceph/admin.secret

查看是否挂载成功:
[root@ceph-admin ~]# df -h
mon-hosts:6789:/ 591G 50G 542G 9% /mnt/cephfs

上面已经成功的将cephfs挂载到了/mnt/cephfs挂载点。注意:现在一个ceph存储集群只能创建一个cephfs,默认cephfs是不支持多个fs的,对多个cephfs的支持还在试验阶段的feature。
好了,对于cephfs的介绍先到这里,我也是对ceph一知半解,不是很专业:)
更多cephfs请参考官方文档: http://docs.ceph.com/docs/master/cephfs/

kubernetes使用cephfs数据持久化

kubernetes使用cephfs进行数据持久化时,主要有三种方式:

  • 使用kubernetes支持的cephfs类型volume直接挂载。
  • 使用kubernetes支持的PV&PVC方式进行数据卷的挂载。
  • 使用社区提供的一个cephfs provisioner来支持以storageClass的方式动态的分配PV,来进行挂载。kubernetes内置provisioner暂时还没有提供这个功能。

并且kubernetens使用cephfs有一些限制,是由于cephfs本身的问题导致的:

  • Kernel CephFS doesn’t work with SELinux, setting SELinux label in Pod’s securityContext will not work.
  • Kernel CephFS doesn’t support quota or capacity, capacity requested by PVC is not enforced or validated.
  • Currently each Ceph user created by the provisioner has allow r MDS cap to permit CephFS mount.

好了,下面我们会分别实验这几种方式来对cephfs文件系统进行挂载。

使用kubernetes支持的cephfs类型volume直接挂载

cephfs卷允许将现有的cephfs卷挂载到你的Pod中,与emptyDir类型不同的是,emptyDir会在删除Pod时把数据清除掉,而cephfs卷的数据会被保留下来,仅仅是被卸载,并且cephfs可以被多个设备进行读写。

我们以官方提供的一个例子作为实验:
https://github.com/kubernetes/examples/tree/master/staging/volumes/cephfs

1.创建一个ceph secret
ceph_secret.yaml文件的定义如下:

1
2
3
4
5
6
7
apiVersion: v1
kind: Secret
metadata:
name: ceph-secret
type: kubernetes.io/rbd
data:
key: QVFCSmQ3ZGFyMTUvSGhBQXF2VVAySU5pSmhmQTZ1SjVBUTkxNFE9PQo=

注意: ceph_secret.yaml文件中key需要进行base64编码,之后在文件中使用。
创建一个ceph_secret实例:

1
2
# kubectl create -f ceph-secret.yaml 
secret "ceph-secret" created

2.创建一个Pod直接使用cephfs类型的volume进行挂载
定义的文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: v1
kind: Pod
metadata:
name: kube-cephfs
spec:
containers:
- name: cephfs-rw
image: busybox
command: ["sleep", "60000"]
volumeMounts:
- mountPath: "/mnt/cephfs"
name: cephfs
volumes:
- name: cephfs
cephfs:
monitors:
- mon-hosts:6789
user: admin
path: /
secretRef:
name: ceph-secret

ok,创建我们的pod,并挂载cephfs卷:

1
2
3
4
5
# kubectl create -f cephfs.yaml 
pod "kube-cephfs" created
# kubectl get pod kube-cephfs
NAME READY STATUS RESTARTS AGE
kube-cephfs 1/1 Running 0 16m

具体验证留给你:)

使用kubernetes支持的PV&PVC方式进行数据卷的挂载

对于PV&PVC的概念我上篇文章已经介绍过,详情请看kubernetes持久化存储Ceph RBD

接下来我们直接上重点:
1.创建PV, 定义的文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: v1
kind: PersistentVolume
metadata:
name: cephfs-pv
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
cephfs:
monitors:
- mon-hosts:6789
user: admin
path: /
secretRef:
name: ceph-secret
readOnly: false
persistentVolumeReclaimPolicy: Delete

创建PV, 如果PV的状态为Available,则说明PV创建成功,可以提供给PVC使用。

1
2
3
4
5
# kubectl create -f cephfs-pv.yaml 
persistentvolume "cephfs-pv" created
# kubectl get pv cephfs-pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
cephfs-pv 1Gi RWX Delete Available 25s

2.创建PVC,定义的文件如下:

1
2
3
4
5
6
7
8
9
10
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: cephfs-pv-claim
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi

注意:PVC的访问模式和存储大小必须和PV的匹配才能绑定成功。好了,创建我们的PVC资源:

1
2
3
4
5
# kubectl create -f cephfs-pv-claim.yaml 
persistentvolumeclaim "cephfs-pv-claim" created
# kubectl get pvc cephfs-pv-claim
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
cephfs-pv-claim Bound cephfs-pv 1Gi RWX 15s

3.创建Pod挂载该PVC,定义的文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: v1
kind: Pod
metadata:
labels:
test: cephfs-pvc-pod
name: cephfs-pv-pod2
spec:
containers:
- name: cephfs-pv-busybox2
image: busybox
command: ["sleep", "60000"]
volumeMounts:
- mountPath: "/mnt/cephfs"
name: cephfs-vol2
readOnly: false
volumes:
- name: cephfs-vol2
persistentVolumeClaim:
claimName: cephfs-pv-claim

创建Pod,并查看cephfs卷是否挂载上:

1
2
3
4
5
# kubectl create -f cephfs-pvc-pod2.yaml 
pod "cephfs-pv-pod2" created
# kubectl get pod cephfs-pv-pod2
NAME READY STATUS RESTARTS AGE
cephfs-pv-pod2 1/1 Running 0 15s

具体验证留给你:)

使用cephfs provisioner动态分配PV供PVC使用

由于kubernetes官方并没有对cephfs提供类似ceph RBD动态分配PV的storageClass的功能。


cephfs

补充: storageClass有一个分配器,用来决定使用哪个卷插件来分配PV.

但是社区提供了一个cephfs-provisioner来实现这个功能,可能在使用的过程中存在一些坑。😁

接下来我们直接使用cephfs-provisioner来进行试验:

  1. 创建admin-secret.yaml
1
2
3
ceph auth get client.admin 2>&1 |grep "key = " |awk '{print  $3'} |xargs echo -n > /tmp/secret
kubectl create ns cephfs
kubectl create secret generic ceph-secret-admin --from-file=/tmp/secret --namespace=cephfs

2.启动 CephFS provisioner

详情参考:Install with RBAC roles

3.创建一个storageclass:

1
2
3
4
5
6
7
8
9
10
11
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: cephfs
namespace: cephfs
provisioner: ceph.com/cephfs
parameters:
monitors: mon-hosts:6789
adminId: admin
adminSecretName: ceph-secret-admin
adminSecretNamespace: "cephfs"

检查cephfs storageClass是否创建成功:

1
2
3
4
5
kubectl create -f local-class.yaml 
storageclass "cephfs" created
# kubectl get storageclass
NAME PROVISIONER AGE
cephfs ceph.com/cephfs 56s

4.创建PVC使用cephfs storageClass动态分配PV

1
2
3
4
5
6
7
8
9
10
11
12
13
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: claim-local
namespace: cephfs
annotations:
volume.beta.kubernetes.io/storage-class: "cephfs"
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi

检查claim-local PVC是否成功的被cephfs storageClass分配PV。如果PVC的状态是Bound则代表绑定成功,如果状态是Pending or Failed则表示绑定PVC失败,请describe或者查看日志来确定问题出错在哪。

1
2
3
4
5
# kubectl create -f local-claim.yaml 
persistentvolumeclaim "claim-local" created
# kubectl get pvc claim-local -n cephfs
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
claim-local Bound pvc-e6272a45-4067-11e8-af69-f0921c10a7bc 1Gi RWX cephfs 41s

ok,绑定成功,并且cephfs storageClass成功的分配一个匹配的PV给PVC.

5.接下来我们创建一个Pod绑定该PVC,来验证是否成功的将cephfs绑定的Pod中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
kind: Pod
metadata:
labels:
test: cephfs-pvc-pod
name: cephfs-pv-pod1
namespace: cephfs
spec:
containers:
- name: cephfs-pv-busybox1
image: busybox
command: ["sleep", "60000"]
volumeMounts:
- mountPath: "/mnt/cephfs"
name: cephfs-vol1
readOnly: false
volumes:
- name: cephfs-vol1
persistentVolumeClaim:
claimName: claim-local

创建Pod,并检查是否挂载cephfs卷成功:)

1
2
3
4
5
# kubectl create -f test-pod.yaml -n cephfs
pod "cephfs-pv-pod1" created
# kubectl get pod cephfs-pv-pod1 -n cephfs
NAME READY STATUS RESTARTS AGE
cephfs-pv-pod1 1/1 Running 0 20s

ok,成功了。具体验证留给你:)

总结

kubernetes使用ceph RBD和cephfs基本上可以满足了大多数业务对数据持久化的需求,也介绍了如何使的kubernetes与ceph的结合使用,但是在真正的业务使用中,上面的这些测试时远远不够的,还需要更细粒度的进行测试。如:在使用kubernetes部署服务使用ceph进行数据存储时,服务回滚数据是保存快照,还是进行md5sum等等:)

参考

http://docs.ceph.com/docs/master/cephfs/
https://kubernetes.io/docs/concepts/storage/volumes/
https://kubernetes.io/docs/concepts/storage/storage-classes/#provisioner
https://github.com/kubernetes/examples/tree/master/staging/volumes/cephfs
https://github.com/kubernetes-incubator/external-storage/tree/master/ceph/cephfs