在K8S环境中,大多数情况下都是多个Pod资源同时挂载一个存储端,共享存储中的数据,在这个普遍应用场景下,Ceph集群的RBD块存储和Cephfs文件系统有着非常明显的区别。
无论是RBD还是Cephfs与K8S集群集成都没有想象中那么好,RBD不支持跨Node节点的Pod一起使用,而Cephfs则不支持指定使用某个Cephfs文件系统,但是在我不懈努力之下,终于研究出了指定某个Cephfs文件系统的方法。
Cephfs更加友好,起码支持跨节点的Pod都可以同时使用,并且可以指定使用哪一个Cephfs文件系统,我们可以为K8S集群单独创建一个Cephfs文件系统。
Cephfs文件系统常用的几种方式:
为不同的客户端创建不同Cephfs文件系统,挂载时指定使用不同的Cephfs。
集群中只创建一个Cephfs,为不同的客户端在Cephfs文件系统中创建不同的子目录,挂载时指定不同的子目录路径。
在实际生产者中第二种方式最为常见,但是如果一个Ceph集群中要为不同类型的客户端提供存储服务,那么建议创建出多个Cephfs文件系统,客户端通过参数分别指定使用哪一个Cephfs。
K8S集群连接Cephfs文件系统时,默认情况下是连接的Ceph集群中默认的Cephfs文件系统,也就是数据资源池为cephfs_data和元数据资源池cephfs_metadata的Cephfs文件系统,并且K8S官方的对接Cephfs的文档中,如果Ceph集群中有多个Cephfs文件系统时,中并没有说明使用什么参数可以指定使用某一个的Cephfs文件文件系统。
好在功夫不负有心人,再查阅了大量的资料后,终于找到了可以让K8S各种存储卷指定使用某一个Cephfs文件系统的方法。
我们K8S对接Ceph集群的Cephfs文件系统的环境如下:
当前集群中存在多个Cephfs文件系统,我们会为K8S集群创建单独的Cephfs文件系统,K8S集群Volume、PV、StorageClass访问Cephfs时,会通过具体的参数指定要使用Ceph集群的哪一个Cephfs文件系统,来实现数据的存储。
1)首先创建Cephfs依赖的数据池和元数据池
[root@ceph-node-1 ~]# ceph osd pool create kubernetes_cephfs_data 16 16
pool 'kubernetes_cephfs_data' created
[root@ceph-node-1 ~]# ceph osd pool create kubernetes_cephfs_metadata 16 16
pool 'kubernetes_cephfs_metadata' created
2)创建一个Cephfs文件系统
[root@ceph-node-1 ~]# ceph fs new kubernetes_cephfs kubernetes_cephfs_metadata kubernetes_cephfs_data
new fs with metadata pool 14 and data pool 13
3)查看集群中所有的Cephfs文件系统
发型当前集群有两个Cephfs文件系统,后面会通过具体的参数,指定存储卷使用某一个Cephfs文件系统。
[root@ceph-node-1 ~]# ceph fs ls
name: kubernetes_cephfs, metadata pool: kubernetes_cephfs_metadata, data pools: [kubernetes_cephfs_data ]
name: cephfs-storage, metadata pool: cephfs2_data, data pools: [cephfs2_metadata ]
4)查看Cephfs文件系统的状态
[root@ceph-node-1 ~]# ceph fs status kubernetes_cephfs
kubernetes_cephfs - 0 clients
=================
+------+--------+-------------+---------------+-------+-------+
| Rank | State | MDS | Activity | dns | inos |
+------+--------+-------------+---------------+-------+-------+
| 0 | active | ceph-node-2 | Reqs: 0 /s | 0 | 0 |
+------+--------+-------------+---------------+-------+-------+
+----------------------------+----------+-------+-------+
| Pool | type | used | avail |
+----------------------------+----------+-------+-------+
| kubernetes_cephfs_metadata | metadata | 1728k | 17.9G |
| kubernetes_cephfs_data | data | 0 | 17.9G |
+----------------------------+----------+-------+-------+
+-------------+
| Standby MDS |
+-------------+
| ceph-node-1 |
+-------------+
+-----------------------------------------------------------------------------------+-------------+
| version | daemons |
+-----------------------------------------------------------------------------------+-------------+
| None | ceph-node-2 |
| ceph version 14.2.22 (ca74598065096e6fcbd8433c8779a2be0c889351) nautilus (stable) | ceph-node-1 |
+-----------------------------------------------------------------------------------+-------------+
挂载到本地路径的原因是为了给K8S集群不同类型的存储卷,提供一个子目录,不同的存储卷挂载不同的子目录来存储持久化文件。
使用mount命令中的mds_namespace参数指定要将哪个Cephfs文件系统挂载到本地路径。
[root@ceph-node-1 ~]# mount -t ceph 192.168.20.20:6789,192.168.20.21:6789,192.168.20.22:6789:/nginx_conf /nginx_conf/ -o name=admin,mds_namespace=kubernetes_cephfs
[root@ceph-node-1 kubernetes_cephfs]# df -hT /kubernetes_cephfs/
文件系统 类型 容量 已用 可用 已用% 挂载点
192.168.20.20:6789,192.168.20.21:6789,192.168.20.22:6789:/ ceph 18G 0 18G 0% /kubernetes_cephfs
[root@ceph-node-1 ~]# ceph auth get-or-create client.kubernetes_cephfs mon "allow r" mds "allow rw" osd "allow rw pool=kubernetes_cephfs_data, allow rw pool=kubernetes_cephfs_metadata"
[client.kubernetes_cephfs]
key = AQAVMFpi1gm6GBAARrJdTXsxYQwGiA1D7h2jHw==
在Cephfs文件系统中为PV类型的存储卷创建独立的子目录,来持久化容器的数据。
现在属于实验环境,如果是线上环境时,还要在子子目录下为不同应用程序挂载分别创建三级目录。
[root@ceph-node-1 ~]# mkdir /kubernetes_cephfs/pv_storage
我们在前面创建了一个专门用于K8S访问Cephfs文件系统的认证用户,将该用户的Key通过Base64进行加密,然后保存在Secret资源中,最后在创建存储卷的资源编排文件中,引用这个Secret资源。
1)将认证用户的Key进行Base64加密
[root@ceph-node-1 ~]# ceph auth get-key client.kubernetes_cephfs | base64
QVFBVk1GcGkxZ202R0JBQVJySmRUWHN4WVF3R2lBMUQ3aDJqSHc9PQ==
2)将加密后的用户认证Key存储在Secret资源中
[root@k8s-master volumes]# vim cephfs-volumes-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: cephfs-secret
data:
key: QVFBVk1GcGkxZ202R0JBQVJySmRUWHN4WVF3R2lBMUQ3aDJqSHc9PQo=
3)创建Secret并查看资源的状态
[root@k8s-master volumes]# kubectl apply -f cephfs-volumes-secret.yaml
secret/cephfs-secret created
[root@k8s-master volumes]# kubectl get secret
NAME TYPE DATA AGE
cephfs-secret Opaque 1 3m30s
创建一个PV资源采用Cephfs文件系统作为底层存储端。
1)编写资源编排文件
PV指定使用某个Cephfs文件系统主要是通过mountOptions
参数来实现的,这个参数是为挂载存储卷时设置一些挂载参数,在宿主机使用mount挂载Cephfs时有参数可以指定挂载哪一个Cephfs,同理在PV中也提供了这种参数,通过这个参数,我们就可以指定使用哪一个Cephfs文件系统了。
[root@k8s-master pv]# cat cephfs-pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: cephfs-pv
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteMany
mountOptions: #指定使用哪一个Cephfs文件系统
- mds_namespace=kubernetes_cephfs #Cephfs文件系统的名称
cephfs: #存储源使用Cephfs类型
monitors: #Monitor组件的地址
- 192.168.20.20:6789
- 192.168.20.21:6789
- 192.168.20.22:6789
path: /pv_storage #挂载Cephfs文件系统中的哪一个子目录
user: kubernetes_cephfs #使用Cephfs文件系统的认证用户
readOnly: false
secretRef: #认证用户的Secret
name: cephfs-secret
persistentVolumeReclaimPolicy: Recycle
2)创建PV资源并查看资源的状态
[root@k8s-master pv]# kubectl apply -f cephfs-pv.yaml
persistentvolume/cephfs-pv created
[root@k8s-master pv]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
cephfs-pv 10Gi RWX Recycle Available 5m12s
PV已经创建完成了,下面来创建PVC资源,关联PV,从PV中分配存储空间给Pod资源使用。
1)编写资源编排文件
[root@k8s-master pv]# cat cephfs-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: cephfs-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 10Gi
2)创建PVC并查看资源的状态
[root@k8s-master pv]# kubectl apply -f cephfs-pvc.yaml
persistentvolumeclaim/cephfs-pvc created
[root@k8s-master pv]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
cephfs-pvc Bound cephfs-pv 10Gi RWX 3s
PVC已经与PV资源进行了绑定,下面就可以给Pod资源使用了。
使用Cephfs文件系统作为存储源的PV和PVC资源都已经准备就绪了,下面来创建一个Pod资源,挂载PVC,将数据持久化到Cephfs文件系统中。
1)编写资源编排文件
[root@k8s-master pv]# cat cephfs-pv-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: cephfs-pod
spec:
containers:
- image: nginx:1.15
name: cephfs-pod
ports:
- name: web
containerPort: 80
protocol: TCP
volumeMounts:
- name: data
mountPath: /data #将PVC挂载到/data目录
volumes:
- name: data
persistentVolumeClaim:
claimName: cephfs-pvc #关联PVC的名称
2)创建Pod并查看资源的状态
[root@k8s-master pv]# kubectl apply -f cephfs-pv-pod.yaml
pod/cephfs-pod created
[root@k8s-master pv]# kubectl get pod
NAME READY STATUS RESTARTS AGE
cephfs-pod 1/1 Running 0 11s
Pod资源已经创建完成,下面进入到Pod中创建一些文件,看看是否能持久化到Cephfs文件系统中。
1)在Pod资源中写入数据文件
[root@k8s-master pv]# kubectl exec -it cephfs-pod bash
root@cephfs-pod:/# cd /data/
root@cephfs-pod:/data# touch file{1..10}.txt
2)查看Cephfs文件系统中是否有Pod持久化的数据文件
到查看这一步,就要尽显当初将Cephfs文件系统的根目录挂载到本地路径的好处了,我们可以直接进入到挂载的目录中,查看来自客户端写入的数据。
[root@ceph-node-1 ~]# cd /kubernetes_cephfs/
[root@ceph-node-1 kubernetes_cephfs]# tree pv_storage/
pv_storage/
├── aa
├── file10.txt
├── file1.txt
├── file2.txt
├── file3.txt
├── file4.txt
├── file5.txt
├── file6.txt
├── file7.txt
├── file8.txt
└── file9.txt
0 directories, 11 files
Pod数据持久化成功。
StoragecClass存储类动态分配PV,需要依赖第三方的客户端插件,通过客户端插件连接到Cephfs文件系统,从而自动分配PV资源。
由于K8S没有内置Cephfs的Provisioner,故需要安装第三方的Provisioner客户端
Cephfs-Provisioner主要组件:
Cephfs-Provisioner客户端在GitHub的地址:https://github.com/kubernetes-retired/external-storage/tree/master/ceph/cephfs/deploy/rbac
完整的Cephfs-Provisioner客户端资源编排文件内容:
[root@k8s-master cephfs-provisioner]# cat cephfs-provisioner.yaml
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: cephfs-provisioner
namespace: kube-system
rules:
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "update", "patch"]
- apiGroups: [""]
resources: ["services"]
resourceNames: ["kube-dns","coredns"]
verbs: ["list", "get"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: cephfs-provisioner
subjects:
- kind: ServiceAccount
name: cephfs-provisioner
namespace: kube-system
roleRef:
kind: ClusterRole
name: cephfs-provisioner
apiGroup: rbac.authorization.k8s.io
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: cephfs-provisioner
namespace: kube-system
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["create", "get", "delete"]
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: cephfs-provisioner
namespace: kube-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: cephfs-provisioner
subjects:
- kind: ServiceAccount
name: cephfs-provisioner
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: cephfs-provisioner
namespace: kube-system
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: cephfs-provisioner
namespace: kube-system
spec:
replicas: 1
selector:
matchLabels:
app: cephfs-provisioner
strategy:
type: Recreate
template:
metadata:
labels:
app: cephfs-provisioner
spec:
containers:
- name: cephfs-provisioner
image: "quay.io/external_storage/cephfs-provisioner:latest"
env:
- name: PROVISIONER_NAME
value: ceph.com/cephfs
- name: PROVISIONER_SECRET_NAMESPACE
value: cephfs
command:
- "/usr/local/bin/cephfs-provisioner"
args:
- "-id=cephfs-provisioner-1"
serviceAccount: cephfs-provisioner
在集群中部署Cephfs-Provisioner客户端。
[root@k8s-master cephfs-provisioner]# kubectl apply -f cephfs-provisioner.yaml
clusterrole.rbac.authorization.k8s.io/cephfs-provisioner created
clusterrolebinding.rbac.authorization.k8s.io/cephfs-provisioner created
role.rbac.authorization.k8s.io/cephfs-provisioner created
rolebinding.rbac.authorization.k8s.io/cephfs-provisioner created
serviceaccount/cephfs-provisioner created
deployment.apps/cephfs-provisioner created
当看到Cephfs-Provisioner客户端的Pod资源处于Running状态就表示部署成功了。
[root@k8s-master cephfs-provisioner]# kubectl get pod -n kube-system | grep cephfs
cephfs-provisioner-67dd56fb57-l7xxm 1/1 Running 0 21m
Volumes类型的存储卷无法像PV、PVC等通过mountOptions
参数指定要使用的Cephfs文件系统,因此Volumes存储卷只能使用默认的Cephfs文件系统,基于这种场景,我们可以在默认的Cephfs文件系统中创建出多个子目录供不同的客户端去使用,这也是Cephfs文件系统最常用的方法。
所谓默认的Cephfs文件系统指的是数据资源池为cephfs_data、元数据资源池为cephfs_metadata的Cephfs文件系统。
在Cephfs文件系统中为Volumes类型的存储卷创建独立的子目录,来持久化容器的数据。
1)默认的Cephfs文件系统的创建方法
1.创建元数据资源池
[root@ceph-node-1 ~]# ceph osd pool create cephfs_metadata 16 16
pool 'cephfs_metadata' created
2.创建数据资源池
[root@ceph-node-1 ~]# ceph osd pool create cephfs_data 16 16
pool 'cephfs_data' created
3.创建Cephfs文件系统
[root@ceph-node-1 ~]# ceph fs new cephfs-storage cephfs_metadata cephfs_data
new fs with metadata pool 8 and data pool 9
2)挂载Cephfs文件系统
[root@ceph-node-1 ceph-deploy]# mount -t ceph 192.168.20.20:6789,192.168.20.21:6789,192.168.20.22:6789:/ /kubernetes_cephfs/ -o name=admin
3)为Volumes存储创建子目录
[root@ceph-node-1 ~]# mkdir /kubernetes_cephfs/volumes_storage
可以直接使用admin用户连接Ceph集群,也可以专门创建一个。
1)将认证用户的Key进行Base64加密
[root@ceph-node-1 ~]# ceph auth get-key client.admin | base64
QVFCSVdVaGlFbWFGT0JBQTZKcjZpdFVlSGlMVlZPZVlGVnBSb2c9PQ==
2)将加密后的用户认证Key存储在Secret资源中
[root@k8s-master volumes]# vim cephfs-volumes-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: cephfs-volumes-secret
data:
key: QVFCSVdVaGlFbWFGT0JBQTZKcjZpdFVlSGlMVlZPZVlGVnBSb2c9PQ==
3)创建Secret并查看资源的状态
[root@k8s-master volumes]# kubectl apply -f cephfs-volumes-secret.yaml
secret/cephfs-secret created
[root@k8s-master volumes]# kubectl get secret
NAME TYPE DATA AGE
cephfs-secret Opaque 1 3m30s
创建一个Pod资源使用Volumes存储卷,将Pod资源的数据持久化到Cephfs文件系统中的子目录里。
1)编写Pod资源的资源编排文件
[root@k8s-master volumes]# vim cephfs-volumes-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: cephfs-pod-volumes
spec:
containers:
- name: cephfs-pod-volumes
image: nginx:1.15
volumeMounts:
- mountPath: "/data"
name: cephfs-volume
volumes:
- name: cephfs-volume
cephfs: #使用cephfs类型
monitors: #monitor集群的地址
- 192.168.20.21:6789
- 192.168.20.22:6789
- 192.168.20.23:6789
path: /volumes_storage #挂载文件系统中的哪一个子目录
user: admin #连接Ceph集群的用户
secretRef: #用户的Secret资源名称
name: cephfs-volumes-secret
2)创建Pod资源并查看资源的状态
[root@k8s-master volumes]# kubectl apply -f cephfs-volumes-pod.yaml
pod/cephfs-pod-volumes created
[root@k8s-master volumes]# kubectl get pod
NAME READY STATUS RESTARTS AGE
cephfs-pod-volumes 1/1 Running 0 4m18s
1)产生数据
[root@k8s-master volumes]# kubectl exec -it cephfs-pod-volumes bash
root@cephfs-pod-volumes:/# cd /data/
root@cephfs-pod-volumes:/data# touch web{1..5}.index
root@cephfs-pod-volumes:/data# ls
web1.index web2.index web3.index web4.index web5.index
2)查看Cephfs文件系统中的数据持久化结构
之前已经将文件系统挂载到本地路径了,可以直接看到一级一级目录的数据内容。
[root@ceph-node-1 ~]# tree /kubernetes_cephfs/
/kubernetes_cephfs/
└── volumes_storage
├── web1.index
├── web2.index
├── web3.index
├── web4.index
└── web5.index
1 directory, 5 files