在Kubernetes上使用CephFS作为文件存储
2018-04-17
1.PV ReadWriteMany的需求 #
最近一个正在开发的服务对PersistentVolume的Access Mode有ReadWriteMany的需求。 PersistentVolume持久化卷(即PV)是Kubernetes对存储的抽象,PV可以是网络存储,不属于任何Node,但可以在每个Node上访问。PV有以下三种访问模式(Access Mode):
- ReadWriteOnce:只可被一个Node挂载,这个Node对PV拥有读写权限
- ReadOnlyMany: 可以被多个Node挂载,这些Node对PV只有只读权限
- ReadWriteMany: 可以被多个Node挂载,这些Node对PV拥有读写权限
我们之前使用Ceph RBD作为Kubernetes集群的PV,在使用场景上基于Kubernetes的Dynamic Storage Provision特性,使用provisioner: kubernetes.io/rbd
的StorageClass来动态创建PV并由volumeClaimTemplates中声明自动创建的PVC去绑定,当前这种形式很稳定的支撑了我们业务的需求。
但RBD的访问模式是ReadWriteOnce的,面对最近的ReadWriteMany的需求,我们需要引入新的存储类型。在 Persistent Volumes文档中以表格的形式列出了当前Kubernetes个Volume Plugin支持的访问模式:
Volume Plugin | ReadWriteOnce | ReadOnlyMany | ReadWriteMany |
---|---|---|---|
AWSElasticBlockStore | ✓ | - | - |
AzureFile | ✓ | ✓ | - |
AzureDisk | ✓ | - | - |
CephFS | ✓ | ✓ | ✓ |
Cinder | ✓ | - | - |
FC | ✓ | ✓ | - |
FlexVolume | ✓ | ✓ | - |
Flocker | ✓ | - | - |
GCEPersistentDisk | ✓ | ✓ | - |
Glusterfs | ✓ | ✓ | ✓ |
HostPath | ✓ | - | - |
iSCSI | ✓ | ✓ | - |
PhotonPersistentDisk | ✓ | - | - |
Quobyte | ✓ | ✓ | ✓ |
NFS | ✓ | ✓ | ✓ |
RBD | ✓ | ✓ | - |
VsphereVolume | ✓ | - | -(works when pods are collocated) |
PortworxVolume | ✓ | - | ✓ |
ScaleIO | ✓ | ✓ | - |
StorageOS | ✓ | - | - |
选择不是很多,有CephFS、Glusterfs、NFS等。由于我们已经在使用Ceph的块存储RBD和对象存储,而且当前这个正在开发的服务也不是很关键,所以这里选择使用CephFS。
2.在Ceph集群上创建CephFS #
CephFS是一个支持POSIX接口的文件系统。文件系统对于客户端来说可以方便的挂载到本地使用。之前整理过一篇《Ceph文件系统存储之Ceph FS》。
使用ceph-deploy为集群添加MDS:
1ceph-deploy --overwrite-conf mds create node1 node2 node3
Ceph当前的版本还不支持一个集群中创建多个CephFS,会报Error EINVAL: Creation of multiple filesystems is disabled. To enable this experimental feature, use 'ceph fs flag set enable_multiple true'
的错误,即正式环境不建议使用多文件系统,改特性当前只能体验。所以这里我们只创建一个名称为cephfs的CephFS。
一个CephFS需要两个pool来存储数据和元数据:
1ceph osd pool create cephfs.data 8
2ceph osd pool create cephfs.metadata 8
创建CephFS:
1ceph fs new cephfs cephfs.metadata cephfs.data
创建一个cephfs.client用户,并授权。cephfs默认不会限制客户端用户对路径的访问权限,可以使用下面的命令设置权限同时创建好用户:
1ceph fs authorize cephfs client.cephfs / r /data rw
这里设置cephfs用户对/有读权限,对/data有读写权限。
接下来我们使用admin用户挂载/,并创建好对应的目录:
1mkdir /mnt/mycephfs
2mount -t ceph node1:6789,node2:6789,node3:6789:/ /mnt/mycephfs -o name=admin,secret=thesecret
3cd /mnt/mycephfs
4mkdir data
5cd data
6mkdir myservice
此时cephfs的/data/myservice目录将作为我们正在开发的这个服务的数据目录。
3.在Kubernetes上挂载CephFS #
基于使用RBD时使用了Kubernetes的Dynamic Storage Provision特性,在使用CephFS时首先想到了也要使用这个特性。 遗憾的是当前版本的Kubernetes还不支持CephFS作为Internal Provisioner。
Volume Plugin | Internal Provisioner |
---|---|
AWSElasticBlockStore | ✓ |
AzureFile | ✓ |
AzureDisk | ✓ |
CephFS | - |
Cinder | ✓ |
FC | - |
FlexVolume | - |
Flocker | ✓ |
GCEPersistentDisk | ✓ |
Glusterfs | ✓ |
iSCSI | - |
PhotonPersistentDisk | ✓ |
Quobyte | ✓ |
NFS | - |
RBD | ✓ |
VsphereVolume | ✓ |
PortworxVolume | ✓ |
ScaleIO | ✓ |
StorageOS | ✓ |
Local | - |
所以这里我们手动创建PV和PVC,并在服务的Deployment中使用PVC挂载数据卷。
将client.cephfs的keyring转成base64编码:
1ceph auth get-key client.cephfs | base64
2QVFBemNZVlo2c2JKTGhBQTdxQ0J5d00raVBSZ0FHOTdGdG9YSXc9PQ==
创建Secret ceph-secret-client-cephfs
1apiVersion: v1
2kind: Secret
3metadata:
4 name: ceph-secret-client-cephfs
5 namespace: dev
6type: kubernetes.io/rbd
7data:
8 key: QVFBemNZVlo2c2JKTGhBQTdxQ0J5d00raVBSZ0FHOTdGdG9YSXc9PQ==
创建PV和PVC:
1---
2apiVersion: v1
3kind: PersistentVolume
4metadata:
5 name: myservice-pv
6 labels:
7 name: myservice-pv
8spec:
9 capacity:
10 storage: 2Gi
11 accessModes:
12 - ReadWriteMany
13 cephfs:
14 monitors:
15 - node1:6789
16 - node2:6789
17 - node3:6789
18 path: /data/myservice
19 user: cephfs
20 secretRef:
21 name: ceph-secret-client-cephfs
22 readOnly: false
23 persistentVolumeReclaimPolicy: Retain
24
25---
26apiVersion: v1
27kind: PersistentVolumeClaim
28metadata:
29 name: myservice-pvc
30 namespace: dev
31spec:
32 accessModes:
33 - ReadWriteMany
34 storageClassName: ""
35 resources:
36 requests:
37 storage: 2Gi
38 selector:
39 matchLabels:
40 name: myservice-pv
注意这里的storageClassName要给"",这是因为我们的集群中已经创建了默认的StorageClass,如果不给"“的话,将会按默认的StorageClass来。
最后在Deployment中使用myservice-pvc
这个PVC即可:
1---
2kind: Deployment
3apiVersion: apps/v1beta2
4metadata:
5 labels:
6 app: myservice
7 name: myservice
8 namespace: dev
9spec:
10 replicas: 1
11 selector:
12 matchLabels:
13 app: myservice
14 template:
15 metadata:
16 labels:
17 app: myservice
18 spec:
19 containers:
20 - name: myservice
21 image: harbor.frognew.com/public/myservice:latest
22 imagePullPolicy: Always
23 resources:
24 requests:
25 memory: "2Gi"
26 cpu: "250m"
27 limits:
28 memory: "2Gi"
29 cpu: "500m"
30 volumeMounts:
31 - name: data
32 mountPath: /data
33 ports:
34 - containerPort: 8080
35 protocol: TCP
36 volumes:
37 - name: data
38 persistentVolumeClaim:
39 claimName: myservice-pvc