1. 程式人生 > >Kubernetes 使用 ceph-csi 消費 RBD 作為持久化儲存

Kubernetes 使用 ceph-csi 消費 RBD 作為持久化儲存

> 原文連結:[https://fuckcloudnative.io/posts/kubernetes-storage-using-ceph-rbd/](https://fuckcloudnative.io/posts/kubernetes-storage-using-ceph-rbd/) 本文詳細介紹瞭如何在 Kubernetes 叢集中部署 `ceph-csi`(v3.1.0),並使用 `RBD` 作為持久化儲存。 需要的環境參考下圖: ![](https://img2020.cnblogs.com/other/1737323/202010/1737323-20201020092618116-1062883357.png) **本文使用的環境版本資訊:** Kubernetes 版本: ```bash $ kubectl get node NAME STATUS ROLES AGE VERSION sealos01 Ready master 23d v1.18.8 sealos02 Ready master 23d v1.18.8 sealos03 Ready master 23d v1.18.8 ``` Ceph 版本: ```bash $ ceph version ceph version 14.2.11 (f7fdb2f52131f54b891a2ec99d8205561242cdaf) nautilus (stable) ``` 以下是詳細部署過程: ## 1. 新建 Ceph Pool 建立一個新的 ceph 儲存池(pool) 給 Kubernetes 使用: ```bash $ ceph osd pool create kubernetes pool ' kubernetes' created ``` 檢視所有的 `pool`: ```bash $ ceph osd lspools 1 cephfs_data 2 cephfs_metadata 3 .rgw.root 4 default.rgw.control 5 default.rgw.meta 6 default.rgw.log 7 kubernetes ``` ## 2. 新建使用者 為 Kubernetes 和 ceph-csi 單獨建立一個新使用者: ```bash $ ceph auth get-or-create client.kubernetes mon 'profile rbd' osd 'profile rbd pool=kubernetes' mgr 'profile rbd pool=kubernetes' [client.kubernetes] key = AQBnz11fclrxChAAf8TFw8ROzmr8ifftAHQbTw== ``` 後面的配置需要用到這裡的 key,如果忘了可以通過以下命令來獲取: ```bash $ ceph auth get client.kubernetes exported keyring for client.kubernetes [client.kubernetes] key = AQBnz11fclrxChAAf8TFw8ROzmr8ifftAHQbTw== caps mgr = "profile rbd pool=kubernetes" caps mon = "profile rbd" caps osd = "profile rbd pool=kubernetes" ``` ## 3. 部署 ceph-csi 拉取 ceph-csi 的[最新 release 分支(v3.1.0)](https://github.com/ceph/ceph-csi/tree/v3.1.0): ```bash $ git clone --depth 1 --branch v3.1.0 https://gitclone.com/github.com/ceph/ceph-csi ``` + 這裡使用 [gitclone](https://gitclone.com) 來加速拉取。 ### 修改 Configmap 獲取 `Ceph` 叢集的資訊: ```bash $ ceph mon dump dumped monmap epoch 1 epoch 1 fsid 154c3d17-a9af-4f52-b83e-0fddd5db6e1b last_changed 2020-09-12 16:16:53.774567 created 2020-09-12 16:16:53.774567 min_mon_release 14 (nautilus) 0: [v2:172.16.1.21:3300/0,v1:172.16.1.21:6789/0] mon.sealos01 1: [v2:172.16.1.22:3300/0,v1:172.16.1.22:6789/0] mon.sealos02 2: [v2:172.16.1.23:3300/0,v1:172.16.1.23:6789/0] mon.sealos03 ``` 這裡需要用到兩個資訊: + **fsid** : 這個是 Ceph 的叢集 ID。 + 監控節點資訊。目前 ceph-csi 只支援 `v1` 版本的協議,所以監控節點那裡我們只能用 `v1` 的那個 IP 和埠號(例如,`172.16.1.21:6789`)。 進入 ceph-csi 的 `deploy/rbd/kubernetes` 目錄: ```bash $ cd deploy/rbd/kubernetes $ ls -l ./ total 36 -rw-r--r-- 1 root root 100 Sep 14 04:49 csi-config-map.yaml -rw-r--r-- 1 root root 1686 Sep 14 04:49 csi-nodeplugin-psp.yaml -rw-r--r-- 1 root root 858 Sep 14 04:49 csi-nodeplugin-rbac.yaml -rw-r--r-- 1 root root 1312 Sep 14 04:49 csi-provisioner-psp.yaml -rw-r--r-- 1 root root 3105 Sep 14 04:49 csi-provisioner-rbac.yaml -rw-r--r-- 1 root root 5497 Sep 14 04:49 csi-rbdplugin-provisioner.yaml -rw-r--r-- 1 root root 5852 Sep 14 04:49 csi-rbdplugin.yaml ``` 將以上獲取的資訊寫入 `csi-config-map.yaml`: ```yaml --- apiVersion: v1 kind: ConfigMap data: config.json: |- [ { "clusterID": "154c3d17-a9af-4f52-b83e-0fddd5db6e1b", "monitors": [ "172.16.1.21:6789", "172.15.1.22:6789", "172.16.1.23:6789" ] } ] metadata: name: ceph-csi-config ``` 建立一個新的 namespace 專門用來部署 ceph-csi: ```bash $ kubectl create ns ceph-csi ``` 將此 Configmap 儲存到 Kubernetes 叢集中: ```bash $ kubectl -n ceph-csi apply -f csi-config-map.yaml ``` ### 新建 Secret 使用建立的 kubernetes 使用者 ID 和 `cephx` 金鑰生成 `Secret`: ```yaml cat < csi-rbd-secret.yaml apiVersion: v1 kind: Secret metadata: name: csi-rbd-secret namespace: ceph-csi stringData: userID: kubernetes userKey: AQBnz11fclrxChAAf8TFw8ROzmr8ifftAHQbTw== EOF ``` 部署 Secret: ```bash $ kubectl apply -f csi-rbd-secret.yaml ``` ### RBAC 授權 將所有配置清單中的 `namespace` 改成 `ceph-csi`: ```bash $ sed -i "s/namespace: default/namespace: ceph-csi/g" $(grep -rl "namespace: default" ./) $ sed -i -e "/^kind: ServiceAccount/{N;N;a\ namespace: ceph-csi # 輸入到這裡的時候需要按一下回車鍵,在下一行繼續輸入 }" $(egrep -rl "^kind: ServiceAccount" ./) ``` 建立必須的 `ServiceAccount` 和 RBAC ClusterRole/ClusterRoleBinding 資源物件: ```bash $ kubectl create -f csi-provisioner-rbac.yaml $ kubectl create -f csi-nodeplugin-rbac.yaml ``` 建立 PodSecurityPolicy: ```bash $ kubectl create -f csi-provisioner-psp.yaml $ kubectl create -f csi-nodeplugin-psp.yaml ``` ### 部署 CSI sidecar 將 `csi-rbdplugin-provisioner.yaml` 和 `csi-rbdplugin.yaml` 中的 kms 部分配置註釋掉: ![](https://img2020.cnblogs.com/other/1737323/202010/1737323-20201020092618889-616290017.png) ![](https://img2020.cnblogs.com/other/1737323/202010/1737323-20201020092619461-152127025.png) 部署 `csi-rbdplugin-provisioner`: ```bash $ kubectl -n ceph-csi create -f csi-rbdplugin-provisioner.yaml ``` 這裡麵包含了 6 個 Sidecar 容器,包括 `external-provisioner`、`external-attacher`、`csi-resizer` 和 `csi-rbdplugin`。 ### 部署 RBD CSI driver 最後部署 `RBD CSI Driver`: ```bash $ kubectl -n ceph-csi create -f csi-rbdplugin.yaml ``` Pod 中包含兩個容器:`CSI node-driver-registrar` 和 `CSI RBD driver`。 ### 建立 Storageclass ```yaml $ cat < storageclass.yaml --- apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: csi-rbd-sc provisioner: rbd.csi.ceph.com parameters: clusterID: 154c3d17-a9af-4f52-b83e-0fddd5db6e1b pool: kubernetes imageFeatures: layering csi.storage.k8s.io/provisioner-secret-name: csi-rbd-secret csi.storage.k8s.io/provisioner-secret-namespace: ceph-csi csi.storage.k8s.io/controller-expand-secret-name: csi-rbd-secret csi.storage.k8s.io/controller-expand-secret-namespace: ceph-csi csi.storage.k8s.io/node-stage-secret-name: csi-rbd-secret csi.storage.k8s.io/node-stage-secret-namespace: ceph-csi csi.storage.k8s.io/fstype: ext4 reclaimPolicy: Delete allowVolumeExpansion: true mountOptions: - discard EOF ``` + 這裡的 `clusterID` 對應之前步驟中的 `fsid`。 + `imageFeatures` 用來確定建立的 image 特徵,如果不指定,就會使用 RBD 核心中的特徵列表,但 Linux 不一定支援所有特徵,所以這裡需要限制一下。 ## 3. 試用 ceph-csi Kubernetes 通過 `PersistentVolume` 子系統為使用者和管理員提供了一組 API,將儲存如何供應的細節從其如何被使用中抽象出來,其中 `PV`(PersistentVolume) 是實際的儲存,`PVC`(PersistentVolumeClaim) 是使用者對儲存的請求。 下面通過官方倉庫的示例來演示如何使用 ceph-csi。 先進入 ceph-csi 專案的 `example/rbd` 目錄,然後直接建立 PVC: ```bash $ kubectl apply -f pvc.yaml ``` 檢視 PVC 和申請成功的 PV: ```bash $ kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE rbd-pvc Bound pvc-44b89f0e-4efd-4396-9316-10a04d289d7f 1Gi RWO csi-rbd-sc 8m21s $ kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pvc-44b89f0e-4efd-4396-9316-10a04d289d7f 1Gi RWO Delete Bound default/rbd-pvc csi-rbd-sc 8m18s ``` 再建立示例 Pod: ```bash $ kubectl apply -f pod.yaml ``` 進入 Pod 裡面測試讀寫資料: ```bash $ kubectl exec -it csi-rbd-demo-pod bash root@csi-rbd-demo-pod:/# cd /var/lib/www/ root@csi-rbd-demo-pod:/var/lib/www# ls -l total 4 drwxrwxrwx 3 root root 4096 Sep 14 09:09 html root@csi-rbd-demo-pod:/var/lib/www# echo "https://fuckcloudnative.io" > sealos.txt root@csi-rbd-demo-pod:/var/lib/www# cat sealos.txt https://fuckcloudnative.io ``` 列出 kubernetes `pool` 中的 rbd `images`: ```bash $ rbd ls -p kubernetes csi-vol-d9d011f9-f669-11ea-a3fa-ee21730897e6 ``` 檢視該 image 的特徵: ```bash $ rbd info csi-vol-d9d011f9-f669-11ea-a3fa-ee21730897e6 -p kubernetes rbd image 'csi-vol-d9d011f9-f669-11ea-a3fa-ee21730897e6': size 1 GiB in 256 objects order 22 (4 MiB objects) snapshot_count: 0 id: 8da46585bb36 block_name_prefix: rbd_data.8da46585bb36 format: 2 features: layering op_features: flags: create_timestamp: Mon Sep 14 09:08:27 2020 access_timestamp: Mon Sep 14 09:08:27 2020 modify_timestamp: Mon Sep 14 09:08:27 2020 ``` 可以看到對 image 的特徵限制生效了,這裡只有 `layering`。 實際上這個 `image` 會被掛載到 node 中作為一個塊裝置,到執行 Pod 的 Node 上可以通過 `rbd` 命令檢視對映資訊: ```bash $ rbd showmapped id pool namespace image snap device 0 kubernetes csi-vol-d9d011f9-f669-11ea-a3fa-ee21730897e6 - /dev/rbd0 ``` 在 node 上檢視掛載資訊: ```bash $ lsblk -l|grep rbd rbd0 252:32 0 1G 0 disk /var/lib/kubelet/pods/15179e76-e06e-4c0e-91dc-e6ecf2119f4b/volumes/kubernetes.io~csi/pvc-44b89f0e-4efd-4396-9316-10a04d289d7f/mount ``` 在 容器中檢視掛載資訊: ```bash $ kubectl exec -it csi-rbd-demo-pod bash root@csi-rbd-demo-pod:/# lsblk -l|grep rbd rbd0 252:32 0 1G 0 disk /var/lib/www/html ``` 一切正常! ## 4. 試用卷快照功能 要想使用卷快照(`Volume Snapshot`)功能,首先需要在 `apiserver` 的 `--feature-gates` 引數中加上 `VolumeSnapshotDataSource=true`,不過從 Kubernetes 1.17 開始這個特性已經預設開啟了,不需要再手動新增。 卷快照功能不是 Kubernetes 的核心 API,它是通過 `CRD` 來實現的,同時還需要一個卷快照控制器(需要單獨部署)。卷快照控制器和 `CRD` 獨立於特定的 CSI 驅動,無論 Kubernetes 叢集中部署了多少 CSI 驅動,每個叢集都必須只執行一個卷快照控制器和一組卷快照 CRD。 卷快照 CRD 和控制器都在這個專案中:[https://github.com/kubernetes-csi/external-snapshotter](https://github.com/kubernetes-csi/external-snapshotter)。 將 [external-snapshotter](https://github.com/kubernetes-csi/external-snapshotter) 專案拉取到本地: ```bash $ git clone --depth 1 https://github.com/kubernetes-csi/external-snapshotter ``` 建立卷快照 CRD: ```bash $ cd external-snapshotter $ kubectl create -f client/config/crd ``` 將卷快照部署清單中的 namespace 改成 `kube-system`: ```bash $ sed -i "s/namespace: default/namespace: kube-system/g" $(grep -rl "namespace: default" deploy/kubernetes/snapshot-controller) ``` 部署卷快照控制器: ```bash $ kubectl create -f deploy/kubernetes/snapshot-controller ``` 現在可以回到 `ceph-csi` 的 `examples/rbd` 目錄試用卷快照功能了。先將 `snapshotclass.yaml` 中的 `clusterID` 改成 Ceph 的叢集 ID: ```yaml --- apiVersion: snapshot.storage.k8s.io/v1beta1 kind: VolumeSnapshotClass metadata: name: csi-rbdplugin-snapclass driver: rbd.csi.ceph.com parameters: # String representing a Ceph cluster to provision storage 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: 154c3d17-a9af-4f52-b83e-0fddd5db6e1b # Prefix to use for naming RBD snapshots. # If omitted, defaults to "csi-snap-". # snapshotNamePrefix: "foo-bar-" csi.storage.k8s.io/snapshotter-secret-name: csi-rbd-secret csi.storage.k8s.io/snapshotter-secret-namespace: ceph-csi deletionPolicy: Delete ``` 然後建立 snapshot class: ```bash $ kubectl create -f snapshotclass.yaml ``` 檢視 snapshot class 是否建立成功: ```bash $ kubectl get volumesnapshotclass NAME DRIVER DELETIONPOLICY AGE csi-rbdplugin-snapclass rbd.csi.ceph.com Delete 2s ``` 還記得上一節建立的 `rbd-pvc` 嗎,現在我們可以直接建立該 PVC 的快照來進行備份了,卷快照的配置清單如下: ```yaml --- apiVersion: snapshot.storage.k8s.io/v1beta1 kind: VolumeSnapshot metadata: name: rbd-pvc-snapshot spec: volumeSnapshotClassName: csi-rbdplugin-snapclass source: persistentVolumeClaimName: rbd-pvc ``` 通過該配置清單建立 PVC `rbd-pvc` 的快照: ```bash $ kubectl create -f snapshot.yaml ``` 驗證快照是否建立成功: ```bash $ kubectl get volumesnapshot NAME READYTOUSE SOURCEPVC SOURCESNAPSHOTCONTENT RESTORESIZE SNAPSHOTCLASS SNAPSHOTCONTENT CREATIONTIME AGE rbd-pvc-snapshot false rbd-pvc csi-rbdplugin-snapclass snapcontent-9011a05f-dc34-480d-854e-814b0b1b245d 16s ``` 在 Ceph 叢集中可以看到新建立快照的 `image` 名稱: ```bash $ rbd ls -p kubernetes csi-snap-4da66c2e-f707-11ea-ba22-aaa4b0fc674d csi-vol-d9d011f9-f669-11ea-a3fa-ee21730897e6 ``` 檢視新建立的快照資訊: ```bash $ rbd snap ls csi-snap-4da66c2e-f707-11ea-ba22-aaa4b0fc674d -p kubernetes SNAPID NAME SIZE PROTECTED TIMESTAMP 9 csi-snap-4da66c2e-f707-11ea-ba22-aaa4b0fc674d 1 GiB Tue Sep 15 03:55:34 2020 ``` 快照也是 pool 中的一個 `image`,所以可以用常規的命令檢視快照的詳細資訊: ```bash $ rbd info csi-snap-4da66c2e-f707-11ea-ba22-aaa4b0fc674d -p kubernetes rbd image 'csi-snap-4da66c2e-f707-11ea-ba22-aaa4b0fc674d': size 1 GiB in 256 objects order 22 (4 MiB objects) snapshot_count: 1 id: 66cdcd259693 block_name_prefix: rbd_data.66cdcd259693 format: 2 features: layering, deep-flatten, operations op_features: clone-child flags: create_timestamp: Tue Sep 15 03:55:33 2020 access_timestamp: Tue Sep 15 03:55:33 2020 modify_timestamp: Tue Sep 15 03:55:33 2020 parent: kubernetes/csi-vol-d9d011f9-f669-11ea-a3fa-ee21730897e6@33d02b70-bc82-4def-afd3-b7a40567a8db overlap: 1 GiB ``` 如果想恢復快照,可以直接基於快照建立 PVC,配置清單內容如下: ```yaml --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: rbd-pvc-restore spec: storageClassName: csi-rbd-sc dataSource: name: rbd-pvc-snapshot kind: VolumeSnapshot apiGroup: snapshot.storage.k8s.io accessModes: - ReadWriteOnce resources: requests: storage: 1Gi ``` 建立 PVC: ```bash $ kubectl apply -f pvc-restore.yaml ``` 檢視 PVC 和申請成功的 PV: ```bash $ kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE rbd-pvc Bound pvc-44b89f0e-4efd-4396-9316-10a04d289d7f 1Gi RWO csi-rbd-sc 22h rbd-pvc-restore Bound pvc-e0ef4f6a-03dc-4c3b-a9c2-db03baf35ab0 1Gi RWO csi-rbd-sc 2m45s $ kubectl get pv pvc-44b89f0e-4efd-4396-9316-10a04d289d7f 1Gi RWO Delete Bound default/rbd-pvc csi-rbd-sc 22h pvc-e0ef4f6a-03dc-4c3b-a9c2-db03baf35ab0 1Gi RWO Delete Bound default/rbd-pvc-restore csi-rbd-sc 2m14s ``` 可以看到 PV 申請成功了,對應到 Ceph 裡面就多了一個 RBD image: ```bash $ rbd ls -p kubernetes csi-snap-4da66c2e-f707-11ea-ba22-aaa4b0fc674d csi-vol-d9d011f9-f669-11ea-a3fa-ee21730897e6 csi-vol-e32d46bd-f722-11ea-a3fa-ee21730897e6 ``` 建立一個新 Pod,使用該 PV 作為持久化儲存: ```bash $ kubectl apply -f pod-restore.yaml ``` 待 Pod 執行成功後,到執行 Pod 的 Node 上可以通過 `rbd` 命令檢視對映資訊: ```bash $ rbd showmapped id pool namespace image snap device 0 kubernetes csi-vol-d9d011f9-f669-11ea-a3fa-ee21730897e6 - /dev/rbd0 1 kubernetes csi-vol-e32d46bd-f722-11ea-a3fa-ee21730897e6 - /dev/rbd1 ``` ## 5. 清理 結束對示例應用的體驗後,就可以使用下面的命令來完成應用的刪除和清理了: ```bash $ kubectl delete -f pod-restore.yaml $ kubectl delete -f pvc-restore.yaml $ kubectl delete -f snapshot.yaml $ kubectl delete -f snapshotclass.yaml $ kubectl delete -f pod.yaml $ kubectl delete -f pvc.yaml ``` ---- Kubernetes 1.18.2 1.17.5 1.16.9 1.15.12離線安裝包釋出地址http://store.lameleg.com ,歡迎體驗。 使用了最新的sealos v3.3.6版本。 作了主機名解析配置優化,lvscare 掛載/lib/module解決開機啟動ipvs載入問題, 修復lvscare社群netlink與3.10核心不相容問題,sealos生成百年證書等特性。更多特性 https://github.com/fanux/sealos 。歡迎掃描下方的二維碼加入釘釘群 ,釘釘群已經整合sealos的機器人實時可以看到sealos的動態。 ![](https://img2020.cnblogs.com/other/1737323/202010/1737323-20201020092620228-632147