K8s 集成

通过 Ceph CSI,K8s 可以利用 Ceph 作为 PVC 的存储提供者(Provisioner)。

配置 Ceph CSI

首先,在 Ceph 集群中创建一个名为 demo-fs 的 Ceph File System 和一个名为 demo-user 的 Ceph 用户,在管理节点中执行以下命令即可:

$ sudo ceph fs volume create demo-fs
$ sudo ceph auth get-or-create client.demo-user mon 'allow r' \
  osd 'allow rw tag cephfs *=*' mgr 'allow rw' mds 'allow rw'
[client.demo-user]
	key = AQAhuZBjSuS9AxBD77AvVjr+vAg9zhjRK7NR+g==

注意上述生成的 key 值后面会用到。

然后,查看 Ceph 集群的一些相关信息,在管理节点中执行以下命令即可:

$ sudo ceph mon dump
epoch 2
fsid 47f20cbc-914f-24ed-93dc-9f2800951ba2
last_changed 2023-01-12T06:01:55.659954+0000
created 2023-01-11T01:30:12.337519+0000
min_mon_release 17 (quincy)
election_strategy: 1
0: [v2:10.0.0.1:3300/0,v1:10.0.0.1:6789/0] mon.ds01
1: [v2:10.0.0.2:3300/0,v1:10.0.0.2:6789/0] mon.e01
dumped monmap epoch 2

注意上述输出中的 fsid (47f20cbc-914f-24ed-93dc-9f2800951ba2) 和节点列表 (10.0.0.1:6789, 10.0.0.2:6789),后面会用到。

最后,在 K8s 集群中创建相关资源,包括 ConfigMap、Secret、Deployment、DaemonSet 等等。

git clone https://github.com/ceph/ceph-csi.git
cd ceph-csi/examples

编辑 csi-config-map-sample.yaml,填入上面的 fsid 和节点列表,除此之外的其他项可以删除,示例如下:

apiVersion: v1
kind: ConfigMap
data:
 config.json: |-
   [
     {
       "clusterID": "47f20cbc-914f-24ed-93dc-9f2800951ba2",
       "monitors": [
         "10.0.0.1:6789",
         "10.0.0.2:6789"
       ]
     }
   ]
metadata:
 name: ceph-csi-config

编辑 cephfs/secret.yaml,填入上面创建的用户名和 key 值,除此之外的其他项可以删除,示例如下:

apiVersion: v1
kind: Secret
metadata:
 name: csi-cephfs-secret
 namespace: default
stringData:
 # Required for dynamically provisioned volumes
 adminID: demo-user
 adminKey: AQB7JL5jugJwFxAA+szhrjIi48JhJbZsI3feRg==

编辑 cephfs/storageclass.yaml,填入上面的 fsid 和 Ceph File System 名称,示例如下:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
 name: sc-cephfs
provisioner: cephfs.csi.ceph.com
parameters:
 clusterID: 47f20cbc-914f-24ed-93dc-9f2800951ba2
 fsName: demo-fs
 csi.storage.k8s.io/provisioner-secret-name: csi-cephfs-secret
 csi.storage.k8s.io/provisioner-secret-namespace: default
 csi.storage.k8s.io/controller-expand-secret-name: csi-cephfs-secret
 csi.storage.k8s.io/controller-expand-secret-namespace: default
 csi.storage.k8s.io/node-stage-secret-name: csi-cephfs-secret
 csi.storage.k8s.io/node-stage-secret-namespace: default
reclaimPolicy: Delete
allowVolumeExpansion: true
mountOptions:
 - debug

按照 README.md 中的指引,执行以下命令在 K8s 集群中依次创建所需资源:

kubectl apply -f ./ceph-conf.yaml
kubectl apply -f ./csi-config-map-sample.yaml
kubectl apply -f ./cephfs/secret.yaml
kubectl apply -f ./cephfs/storageclass.yaml
cd ../../deploy/cephfs/kubernetes
kubectl create -f ./csi-provisioner-provisioner.yaml
kubectl create -f ./csi-nodeplugin-rbac.yaml
kubectl create -f ./csi-cephfsplugin-provisioner.yaml
kubectl create -f ./csi-cephfsplugin.yaml
kubectl create -f ./csidriver.yaml

注意,上述资源均默认在 default namespace 中创建。

等待所创建的 Pod 成功运行后,即可创建基于 Ceph 的 PVC。

kubectl get pod -w

通过 Helm Chart 配置 Ceph CSI

理论上,我们可以在同一个 K8s 集群中部署两套 Ceph CSI,提供两个 Storage Class 以供用户使用。

在部署过程中:

  • 对于 Ceph 集群,我们需要创建两个不同的 Ceph Filesystem 及对应的用户
  • 对于 K8s 集群,我们需要创建两个不同的命名空间,并对 Storage Class、ClusterRole、ClusterRoleBinding 等集群级别资源使用不同的名称

为了方便部署,我们提供了 Helm Chart(点击此处下载),您只需要在 values.yaml 中填写参数即可。

values.yaml 示例如下:

ceph:
  storageClassName: sc-cephfs
  driverName: cephfs.csi.ceph.com
  clusterID: 47f20cbc-914f-24ed-93dc-9f2800951ba2
  fsName: demo-fs
  adminID: demo-user
  adminKey: AQAhuZBjSuS9AxBD77AvVjr+vAg9zhjRK7NR+g==
  metricsPort: 8681
  monitors:
    - "10.0.0.1:6789"
    - "10.0.0.2:6789"
  # erasureCode: true
  # pool: ecpool-k4-m2
  images:
    cephCSI: quay.io/cephcsi/cephcsi:v3.8.0
    csiProvisioner: registry.k8s.io/sig-storage/csi-provisioner:v3.3.0
    csiResizer: registry.k8s.io/sig-storage/csi-resizer:v1.6.0
    csiSnapshotter: registry.k8s.io/sig-storage/csi-snapshotter:v6.1.0
    csiNodeDriverRegistrar: registry.k8s.io/sig-storage/csi-node-driver-registrar:v2.6.2

运行以下命令在 K8s 集群中创建相关资源:

unzip cephcsi-helmchart.zip
helm template ./cephcsi-helmchart -n cephfs -o ./deploy.yaml
kubectl create ns cephfs
kubectl create -n cephfs -f ./deploy.yaml
kubectl get pod -n cephfs -w

创建 PVC 并绑定 Pod

在 PVC spec 中指定 StorageClass 名称即可创建基于 Ceph 存储集群的 PVC。例如,配置 Ceph CSI 一节中创建了名为 sc-cephfs 的 Storage Class,通过如下 YAML 创建 PVC:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: cephfs-pvc
spec:
  accessModes:
  - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
  storageClassName: sc-cephfs

然后创建 Pod 绑定该 PVC:

apiVersion: v1
kind: Pod
metadata:
 name: cephfs-demo-pod
spec:
 containers:
   - name: web-server
     image: nginx:latest
     resources:
       limits:
         cpu: 100m
         memory: 200Mi
     volumeMounts:
       - name: cephfs-pvc
         mountPath: /var/lib/www
 volumes:
   - name: cephfs-pvc
     persistentVolumeClaim:
       claimName: cephfs-pvc

查看 PVC 创建/绑定失败原因

如果创建 PVC 和 Pod 后,Pod 一直无法正常运行,请按照以下步骤查找原因:

1. 查看 PVC 是否创建成功

运行以下命令获取 PVC 信息:

kubectl get pvc cephfs-pvc

如果 STATUS 字段是 Bound,则转至第 2 步。

如果 STATUS 字段是 Pending,说明 PVC 没有 provision 成功,请查看 Ceph CSI Provisioner Pod 的日志寻找原因。

通过以下命令获取 Ceph CSI Provisioner Pod 名称:

$ kubectl get pod -n cephfs -l app=csi-cephfsplugin-provisioner
NAME                                            READY   STATUS    RESTARTS   AGE
csi-cephfsplugin-provisioner-5b77dc5fff-56mr9   6/6     Running   0          6d21h
csi-cephfsplugin-provisioner-5b77dc5fff-rcpbg   6/6     Running   0          6d21h
csi-cephfsplugin-provisioner-5b77dc5fff-tkmsh   6/6     Running   0          6d21h

其中只有一个 Pod 是主要的工作 Pod,另外两个处于待命状态。通过以下命令查看其日志:

kubectl logs -n cephfs csi-cephfsplugin-provisioner-5b77dc5fff-56mr9 csi-provisioner

2. 查看 PVC 与 Pod 是否绑定成功

运行以下命令获取 Pod 信息:

kubectl describe pod cephfs-demo-pod

输出结果中的 Events 字段会显示 PVC 绑定不成功的原因。

另外,查看 Ceph CSI Plugin Pod 日志也有助于查找原因。

首先,通过以下命令查看所创建的 Pod 位于哪个节点上:

$ kubectl get pod -o wide
NAME              READY   STATUS    RESTARTS   AGE     IP               NODE
cephfs-demo-pod   1/1     Running   0          6d22h   10.233.106.203   nc13

然后,通过以下命令找到位于同一个节点上的 Ceph CSI Plugin Pod:

$ kubectl get pod -n cephfs -l app=csi-cephfsplugin -o wide
NAME                     READY   STATUS    RESTARTS   AGE    IP             NODE
csi-cephfsplugin-55nc4   3/3     Running   0          3d1h   100.64.4.74    nc14
csi-cephfsplugin-dd99m   3/3     Running   0          3d1h   100.64.4.199   nuc
csi-cephfsplugin-jcxv6   3/3     Running   0          3d1h   100.64.4.71    nc11
csi-cephfsplugin-jf4mn   3/3     Running   0          3d1h   100.64.4.209   acer
csi-cephfsplugin-jhffm   3/3     Running   0          3d1h   10.0.0.2    e01
csi-cephfsplugin-mxjh2   3/3     Running   0          3d1h   100.64.4.73    nc13
csi-cephfsplugin-rdbbp   3/3     Running   0          3d1h   100.64.4.72    nc12
csi-cephfsplugin-vql6n   3/3     Running   0          3d1h   100.64.4.132   kylin

最后,通过以下命令查看该 Ceph CSI Plugin Pod 的日志:

kubectl logs -n cephfs csi-cephfsplugin-mxjh2 csi-cephfsplugin

如果仍然无法找到问题原因,可尝试重启该 Ceph CSI Plugin Pod:

kubectl delete -n cephfs csi-cephfsplugin-mxjh2

如果上述删除命令卡住,可通过以下命令强行删除该 Ceph CSI Plugin Pod:

kubectl delete -n cephfs csi-cephfsplugin-mxjh2 --force

PVC 备份

为了支持 PVC 备份,首先需要在 K8s 中启用 Volume Snapshot 功能;其次,需要针对不同的 PVC Provisioner 创建 VolumeSnapshotClass

Ceph CSI 提供了对应的 VolumeSnapshotClass 资源,其 YAML 如下(来源):

apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
 name: csi-cephfsplugin-snapclass
driver: cephfs.csi.ceph.com
parameters:
 # String representing a Ceph cluster to provision storage snapshot from.
 # Should be unique across all Ceph clusters in use for provisioning,
 # cannot be greater than 36 bytes in length, and should remain immutable for
 # the lifetime of the StorageClass in use.
 # Ensure to create an entry in the configmap named ceph-csi-config, based on
 # csi-config-map-sample.yaml, to accompany the string chosen to
 # represent the Ceph cluster in clusterID below
 clusterID: 47f20cbc-914f-24ed-93dc-9f2800951ba2

 # Prefix to use for naming CephFS snapshots.
 # If omitted, defaults to "csi-snap-".
 # snapshotNamePrefix: "foo-bar-"

 csi.storage.k8s.io/snapshotter-secret-name: csi-cephfs-secret
 csi.storage.k8s.io/snapshotter-secret-namespace: default
deletionPolicy: Delete

配置 Ceph CSI 一节类似,YAML 中需要填入 Ceph File System 的 fsid。

针对创建 PVC 并绑定 Pod 一节中所创建的名为 cephfs-pvc 的 PVC,我们创建一个 VolumeSnapshot 来对其进行备份,YAML 如下(来源):

apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
 name: cephfs-pvc-snapshot
spec:
 volumeSnapshotClassName: csi-cephfsplugin-snapclass
 source:
   persistentVolumeClaimName: cephfs-pvc

查看所创建的备份:

kubectl describe volumesnapshot cephfs-pvc-snapshot

基于该备份创建一个新的 PVC:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: cephfs-pvc-restore
spec:
 storageClassName: tsz-cephfs
 dataSource:
   name: cephfs-pvc-snapshot
   kind: VolumeSnapshot
   apiGroup: snapshot.storage.k8s.io
 accessModes:
   - ReadWriteMany
 resources:
   requests:
     storage: 1Gi

然后创建一个新的 Pod 绑定该 PVC:

apiVersion: v1
kind: Pod
metadata:
 name: cephfs-restore-demo-pod
spec:
 containers:
   - name: web-server
     image: nginx:latest
     resources:
       limits:
         cpu: 100m
         memory: 200Mi
     volumeMounts:
       - name: cephfs-pvc-restore
         mountPath: /var/lib/www
 volumes:
   - name: cephfs-pvc-restore
     persistentVolumeClaim:
       claimName: cephfs-pvc-restore

最后,进入 Pod 查看 PVC 中的内容是否与之前相同:

kubectl exec -it cephfs-restore-demo-pod -- /bin/bash
ls /var/lib/www

在 K8s 中启用 Volume Snapshot 功能

根据官方博客,Volume Snapshot 特性从 K8s 1.20 版本开始 GA。

通过以下命令查看 K8s 版本:

kubectl version

通过以下命令查看 K8s 中是否已经安装 Volume Snapshot 相关组件:

kubectl get deploy -n kube-system snapshot-controller
kubectl api-resouces | grep volumesnapshot

如果尚未安装,可以根据官方文档,手动安装 CRD、controller、webhook 等组件:

git clone https://github.com/kubernetes-csi/external-snapshotter.git
cd external-snapshotter
kubectl kustomize client/config/crd | kubectl create -f -
kubectl -n kube-system kustomize deploy/kubernetes/snapshot-controller | kubectl create -f -

配额管理

PVC 能够使用的最大存储空间由其 spec 指定,K8s 集群中所有基于 Ceph 的 PVC 总共能够使用的最大存储空间可通过 Ceph File System 的底层 Pool 来限制。

在任意管理节点上运行以下命令列举所有 Pool:

$ sudo ceph osd pool ls
.mgr
cephfs.demo-fs.meta
cephfs.demo-fs.data

其中,名为 cephfs.demo-fs.data 的 Pool 就是名为 demo-fs 的 Ceph File System 存储数据的 Pool,通过以下命令限制该 Pool 能够使用的最大存储空间:

sudo ceph osd pool set-quota cephfs.demo-fs.data max_bytes 10000000

参考文档: