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

参考