# 3.4.执子之手：Ceph RBD

> 死生契阔，与子成说。执子之手，与子偕老。——《诗经》

    前边三个章节我们已经搭建好了K8S、Ceph、Harbor，基础环境已经有了，接下来这个章节就让K8S和Ceph联动起来，将Ceph作为K8S的底层存储引擎让二者协同工作，不论是之后的KubeSphere还是TiDB都可以直接使用本章配置的结果来访问底层存储。

![](https://22907629-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFnX8FxOr13MrNxviJuye%2Fuploads%2Fgit-blob-814204c806ab61b79e3cd8ef6a3f4ec88a120bcb%2F20221130092721.png?alt=media)

    K8S和Ceph集成有三种实现方式：

* Volumes存储卷
* PV/PVC持久化卷/持久化卷声明
* StorageClass动态存储，动态创建PV、PVC

    Ceph支持K8S存储有两种类型：

* CephFS：文件系统
* Ceph RBD：块存储

> **注意**：一般写CephFS会将Ceph和FS连写，而RBD则中间加一空白来写！

## 1. ceph-csi

    CSI[^1]全称Container Storage Interface，它是Ceph的一个插件，它的目的是定义行业标准“容器存储接口”，使存储供应商（SP）可以开发一个符合CSI标准的插件并使其能够在多个容器编排（CO）系统中工作。

    本章K8S通过`ceph-csi`（csi plugin）来接入ceph存储（csi相关组件的分析以rbd为例进行分析），对csi系统结构、涉及的k8s对象和组件进行简单介绍，以及k8s对存储进行相关操作流程分析，存储相关操作包括**存储创建、存储扩容、存储挂载、解除存储、存储删除**操作。

### 1.1. 整体架构

> 图参考文档中内容重绘，PV/PVC/SC此处不解释其作用（烂大街的概念），下文主要围绕CSI部分。

![](https://22907629-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFnX8FxOr13MrNxviJuye%2Fuploads%2Fgit-blob-8255f110fcd45858b541dd5ee391f5a48973e950%2F20221130113616.png?alt=media)

#### VolumeAttachment组件

    该组件记录了PV挂载的相关信息：**挂载到哪个Node节点、由哪个Volume Plugin来挂载**等。AD Controller会创建一个VolumeAttachment，而External-Attacher通过观察该VolumeAttachment，根据状态属性来执行存储的挂载、卸载操作。

#### CSINode

    **CSINode**记录了`csi plugin`相关信息（**NodeId、DriverName、拓扑**），当Node Driver Register向kubelet注册一个csi plugin之后，会创建（更新）一个CSINode对象，记录csi plugin的相关信息。

#### Volume Plugin

    该组件扩展各种存储类型的卷管理能力，实现第三方存储各种操作能力和K8S存储系统结合，并调用第三方存储的接口或命令，从而提供数据卷的创建/删除、attach/detach、mount/umount具体操作实现，可以认为是第三方存储代理人。

* **in-tree**：在K8S源码内部实现，和K8S一起发布、管理，更新迭代慢、灵活性差。
* **out-of-tree**：代码独立于K8S，由存储厂商实现，有`csi, flexvolume`两种实现。

#### CSI Plugin

    `ceph-csi`就属于csi plugin，它主要分为ControllerServer和NodeServer，负责不同的存储操作。

#### External Plugin

    主要包含四个子组件（参考图），它辅助csi plugin组件共同完成存储相关的操作。

| 组件          | 作用                                                      |
| ----------- | ------------------------------------------------------- |
| provisioner | Watch PVC对象，调用csi plugin创建存储，最终创建PV。                    |
| attacher    | Watch VolumeAttachment对象，调用csi plugin做attach/dettach操作。 |
| resizer     | Watch PVC对象，调用csi plugin来做存储扩容。                         |
| snapshotter | 创建快照。                                                   |

#### Node-Driver-Registrar

    该组件负责实现csi plugin（NodeServer）的注册，让kubelet感知csi plugin的存在。

#### AD/PV Controller

    PV Controller负责PV、PVC绑定和生命周期管理（创建/删除底层存储、创建/删除PV对象、PV和PVC对象状态变更）。

    AD Controller全称Attachment/Detachment控制器，主要负责创建、删除VolumeAttachment对象，并调用volume plugin来做存储设备的Attach/Detach操作（将数据卷挂载到特定node节点上/从特定node节点上解除挂载），以及更新node.Status.VolumesAttached等。

> 关于这部分内容参考引用博文第一章，这里就不再做过多介绍，本章节的基本介绍只是起一个抛砖引玉的作用。

### 1.2. CSI插件

    ceph-csi的块设备功能要`K8S v1.13`以上或更高版本才可用，它动态提供了RBD映像以支持K8S卷并将这些RBD映像映射为工作节点上的块设备（可选地挂载映像中包含的文件系统）运行引用RBD支持卷的Pod。它的整体结构如下：

![](https://22907629-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFnX8FxOr13MrNxviJuye%2Fuploads%2Fgit-blob-89021fda74ecf468ef27f007d99982c8ad989c45%2F20221130122943.png?alt=media)

    所以您可以通过kubernetes sidecar部署provisioner, attacher, resizer, driver-registrar, snapshotter组件以支持CSI功能。ceph-csi插件实现了支持CSI的Container Orchestrator（OC）和Ceph集群之间的接口，允许动态供应Ceph卷并将它们附加到工作负载中。默认情况下ceph-csi使用RBD内核模块，可能不支持所有的Ceph CRUSH可调参数或RBD映像等特性。

***

## 2. Ceph RBD部署

### 2.1.Ceph: Pool

1. 默认情况下，Ceph块设备使用rbd池，使用下边命令为K8S创建一个池：

   ```shell
   # 存储池名称：k8s.store
   # 在目前三节点的集群中，推荐后边不使用128 128，而是32 32两个值，否则等待更新的时间会很长
   ceph osd pool create k8s.store 128 128
   # 新创建的池必须在使用之前初始化，此时需要使用rbd工具初始化
   rbd pool init k8s.store
   ```

   ![](https://22907629-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFnX8FxOr13MrNxviJuye%2Fuploads%2Fgit-blob-09b0d292caaed6d19e2b811c95abe40349ae5ac1%2F20221130133600.png?alt=media)

   您可以登录Ceph集群管理界面等待任务执行完成（截图中可以看到**Applications类型**是`rbd`）：

   ![](https://22907629-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFnX8FxOr13MrNxviJuye%2Fuploads%2Fgit-blob-f7926d7bd54dfe87a50cb007818e84448c0381be%2F20221130133811.png?alt=media)
2. 为K8S创建新的Ceph账号

   ```shell
   # 账号信息
   ceph auth get-or-create client.k8s \
       mon 'profile rbd' \
       osd 'profile rbd pool=k8s.store' \
       mgr 'profile rbd pool=k8s.store'
   # 查看创建账号
   ceph auth list
   ```

   ![](https://22907629-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFnX8FxOr13MrNxviJuye%2Fuploads%2Fgit-blob-7e40fa7d59ce8bbf20f1a32b6454bc9034c28019%2F20221130140504.png?alt=media)

   ![](https://22907629-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFnX8FxOr13MrNxviJuye%2Fuploads%2Fgit-blob-743c8255ce41f2895732b0383d12e1e398c9032d%2F20221130140558.png?alt=media)
3. 账号创建完成后，ceph-csi需要一个存储在K8S中的ConfigMap对象来定义Ceph集群的Ceph mon地址

   ```shell
   ceph mon dump
   ceph -s|grep mon
   ```

   ![](https://22907629-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFnX8FxOr13MrNxviJuye%2Fuploads%2Fgit-blob-855ab64a83513fe52c6bff4c67220c9552583325%2F20221130140857.png?alt=media)

### 2.2.K8S: ConfigMap

1. 将部署配置放在`~/deploy/ceph`中，clusterID需要和上边取得的id保持一致，并且需要修改mon地址，多个地址后面要使用逗号分隔。

   ```shell
   cd /root/deploy/ceph
   vim config-map-csi.yaml
   ```

   文件内容如下：

   ```yaml
   # 文件：config-map-csi.yaml
   # 名称：ceph-csi-config
   apiVersion: v1
   kind: ConfigMap
   data:
       config.json: |-
           [
               {
                   "clusterID":"79ed3cf4-6a04-11ed-8db2-fa163ec820ba",
                   "monitors":[
                       "192.168.0.154:6789",
                       "192.168.0.123:6789",
                       "192.168.0.208:6789"
                   ]
               }
           ]
   metadata:
       name: ceph-csi-config
   ```

   ![](https://22907629-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFnX8FxOr13MrNxviJuye%2Fuploads%2Fgit-blob-08058a44832b2ac4ec1636091d1afffb7fd31c14%2F20221130141828.png?alt=media)
2. 在K8S中创建该ConfigMap对象：

   ```shell
   kubectl apply -f config-map-csi.yaml
   kubectl get cm ceph-csi-config
   ```

   ![](https://22907629-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFnX8FxOr13MrNxviJuye%2Fuploads%2Fgit-blob-929c28c519c6d4bab114897192aeb6d235756bb6%2F20221130141915.png?alt=media)
3. 按照步骤4-5创建额外的几个ConfigMap（必须）

   ```yaml
   # 文件：config-map-csi-kms.yaml
   # 名称：ceph-csi-encryption-kms-config
   apiVersion: v1
   kind: ConfigMap
   data:
       config.json: |-
           {}
   metadata:
       name: ceph-csi-encryption-kms-config

   ------
   # 文件：config-map-ceph.yaml
   # 名称：ceph-config
   apiVersion: v1
   kind: ConfigMap
   data:
       ceph.conf: |
           [global]
           auth_cluster_required = cephx
           auth_service_required = cephx
           auth_client_required = cephx
       # keyring is a required key and its value should be empty
       keyring: |
   metadata:
       name: ceph-config
   ```

### 2.3.K8S: RBAC

1. `ceph-csi`需要创建ServiceAccount和RBAC用于访问集群内部信息，先下载yaml文件：

   ```shell
   # csi-provisioner-rbac.yaml
   wget https://raw.githubusercontent.com/ceph/ceph-csi/master/deploy/rbd/kubernetes/csi-provisioner-rbac.yaml

   # csi-nodeplugin-rbac.yaml
   wget https://raw.githubusercontent.com/ceph/ceph-csi/master/deploy/rbd/kubernetes/csi-nodeplugin-rbac.yaml
   # /root/deploy/ceph目录下
   ll
   ```

   ![](https://22907629-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFnX8FxOr13MrNxviJuye%2Fuploads%2Fgit-blob-ec0f505cde8fd49b54d12e1c01d8ba04dee34cc7%2F20221130145027.png?alt=media)
2. 将下载的两个yaml文件内容配置到K8S中：

   ```shell
   kubectl apply -f csi-provisioner-rbac.yaml
   kubectl apply -f csi-nodeplugin-rbac.yaml
   ```

   ![](https://22907629-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFnX8FxOr13MrNxviJuye%2Fuploads%2Fgit-blob-d95137922a5271c061b51b0928b2fba1a3face8d%2F20221130145202.png?alt=media)

### 2.4.K8S: provisioner

1. 下载两个yaml文件到本地：

   ```shell
   # csi-rbdplugin-provisioner.yaml
   wget https://raw.githubusercontent.com/ceph/ceph-csi/master/deploy/rbd/kubernetes/csi-rbdplugin-provisioner.yaml

   # csi-rbdplugin.yaml
   wget https://raw.githubusercontent.com/ceph/ceph-csi/master/deploy/rbd/kubernetes/csi-rbdplugin.yaml

   ll
   ```

   ![](https://22907629-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFnX8FxOr13MrNxviJuye%2Fuploads%2Fgit-blob-90ef5541d44145db01af93a2cb2585886ca7cd3c%2F20221130151257.png?alt=media)
2. 查看第一个yaml文件中的镜像，手动拉取镜像（推荐）

   ```shell
   # csi-rbdplugin-provisioner.yaml
   # Resizer
   docker pull registry.k8s.io/sig-storage/csi-resizer:v1.6.0
   # Attacher
   docker pull registry.k8s.io/sig-storage/csi-attacher:v4.0.0
   # Snapshotter
   docker pull registry.k8s.io/sig-storage/csi-snapshotter:v6.1.0
   # Provisioner
   docker pull registry.k8s.io/sig-storage/csi-provisioner:v3.3.0

   # csi-rbdplugin.yaml
   docker pull registry.k8s.io/sig-storage/csi-node-driver-registrar:v2.6.0

   # 关键镜像（两个文件都需要）
   docker pull quay.io/cephcsi/cephcsi:canary
   ```
3. 将两个配置文件内容配置到K8S中：

   ```shell
   kubectl apply -f csi-rbdplugin.yaml
   kubectl apply -f csi-rbdplugin-provisioner.yaml
   ```
4. 查看csi插件是否已经启动，`FailedScheduling`问题参考问题章节：

   ![](https://22907629-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFnX8FxOr13MrNxviJuye%2Fuploads%2Fgit-blob-11aa64b36a5fa219b16b91e69fe5378296312167%2F20221130222128.png?alt=media)

### 2.5.K8S: Secret

1. 获取`ceph`用户信息，找到`client.admin`用户，复制后边的Key，然后创建一个Secret对象：

   ```yaml
   # 文件：secret-csi-rbd.yaml
   # 名称：csi-rbd-secret
   apiVersion: v1
   kind: Secret
   metadata:
       name: csi-rbd-secret
       namespace: default
   stringData:
       userID: k8s
       userKey: xxx
   ```
2. 最终结果如下：

   ```shell
   kubectl get secret
   kubectl get cm
   ```

   ![](https://22907629-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFnX8FxOr13MrNxviJuye%2Fuploads%2Fgit-blob-2e636750b95694379a8c802c59be99ca9adfbc57%2F20221130144434.png?alt=media)

### 2.6.K8S: StorageClass

1. 先获取集群ID

   ```shell
   ceph -s|grep id|awk -F "[ ]+" '{print $3}'
   ```
2. 创建新的yaml文件（StorageClass）

   ```yaml
   # 文件：sc-csi-rbd.yaml
   # 名称：ceph-rbd-k8s
   apiVersion: storage.k8s.io/v1
   kind: StorageClass
   metadata:
       # storageclass名称
       name: ceph-rbd-k8s   
       # 设置默认，有这步就不用后边手工处理了
       annotations:
           storageclass.kubernetes.io/is-default-class: "true"
   provisioner: rbd.csi.ceph.com   
   parameters:
       # ceph集群id
       clusterID: 79ed3cf4-6a04-11ed-8db2-fa163ec820ba 
       # pool名称 k8s.store   
       pool: k8s.store            
       # rbd特性
       imageFeatures: layering   
       csi.storage.k8s.io/provisioner-secret-name: csi-rbd-secret
       csi.storage.k8s.io/provisioner-secret-namespace: default
       csi.storage.k8s.io/controller-expand-secret-name: csi-rbd-secret
       csi.storage.k8s.io/controller-expand-secret-namespace: default
       csi.storage.k8s.io/node-stage-secret-name: csi-rbd-secret
       csi.storage.k8s.io/node-stage-secret-namespace: default
   reclaimPolicy: Delete           #pvc回收机制
   allowVolumeExpansion: true      #对扩展卷进行扩展
   # StorageClass 动态创建的 PersistentVolume 
   # 将使用类中 mountOptions 字段指定的挂载选项
   mountOptions:                   
       - discard
   ```
3. 将Yaml文件内容配置到K8S

   ```shell
   kubectl apply -f sc-csi-rbd.yaml
   kubectl get sc
   ```

   ![](https://22907629-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFnX8FxOr13MrNxviJuye%2Fuploads%2Fgit-blob-8da9450f11694ec7997c975cc95e3e44b84c786a%2F20221130223340.png?alt=media)
4. **注**：上述`ceph-rbd-k8s`如果并没有带`(default)`标记，证明它不是默认的SC，您需要执行如下命令将它设置成默认：

   ```shell
   kubectl patch storageclass ceph-rbd-k8s \
       -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
   kubectl get sc
   ```

   ![](https://22907629-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFnX8FxOr13MrNxviJuye%2Fuploads%2Fgit-blob-875eec628ebb8496cce0fa4ffd0966e45639b4a0%2F20221202085654.png?alt=media)
5. 最后创建`PVC`验证当前SC是否可用：

   ```yaml
   # 文件：pvc-csi-block.yaml
   # 名称：test-block-pvc
   ---
   apiVersion: v1
   kind: PersistentVolumeClaim
   metadata:
       name: test-block-pvc     #pvc名称
   spec:
       accessModes:
           - ReadWriteOnce     #访问模式
       volumeMode: Block     #数据卷类型
       resources:
           requests:
               storage: 1Gi           #存储空间
       storageClassName: ceph-rbd-k8s   #后端storageclass名称
   ```

   ![](https://22907629-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFnX8FxOr13MrNxviJuye%2Fuploads%2Fgit-blob-9fa2de6c9f9f4b1120961cfd1f57dcec8fb9b8f2%2F20221201140131.png?alt=media)

   注意成功的标记是状态必须是Bound，如果状态不是这个值，证明有问题，可使用如下命令查看日志：

   ```shell
   describe pvc test-block-pvc
   ```

### 2.7. imageFeatures

    上述SC中配置了一个`imageFeatures`的属性，对Ceph而言，该属性的值如下：

| 类型             | 特性                                                                                                                              |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| layering       | image的克隆操作，可对image创建快照并保护，然后从快照克隆新的image，父子image之间使用COW技术，共享对象数据。                                                               |
| striping v2    | 条带化对象数据，类似raid 0，可改善顺序读写场景较多情况下的性能。                                                                                             |
| exclusive lock | 保护image数据一致性，对image做修改时，需要持有此锁。这个可以看做是一个分布式锁，在开启的时候，确保只有一个客户端在访问image，否则锁的竞争会导致io急剧下降。 主要应用场景是qemu live-migration。              |
| object map     | 此特性依赖于exclusive lock。因为image的对象分配是thin-provisioning，此特性开启的时候，会记录image所有对象的一个位图，用以标记对象是否真的存在，在一些场景下可以加速io。                       |
| fast diff      | 此特性依赖于object map和exlcusive lock。快速比较image的snapshot之间的差异。                                                                        |
| deep-flatten   | layering特性使得克隆image的时候，父子image之间采用COW，他们之间的对象文件存在依赖关系，flatten操作的目的是解除父子image的依赖关系，但是子image的快照并没有解除依赖，deep-flatten特性使得快照的依赖也解除。  |
| journaling     | 依赖于exclusive lock。将image的所有修改操作进行日志化，并且复制到另外一个集群（mirror)，可以做到块存储的异地灾备。这个特性在部署的时候需要新部署一个daemon进程，目前还在试验阶段，不过这个特性很重要，可以做跨集群/机房容灾。 |
| Exclusive Lock | 从上面可以看出，很多特性都依赖于exclusive lock，重点介绍一下。                                                                                          |
| exclusive lock | 是分布式锁，实现的时候默认是客户端在第一次写的时候获取锁，并且在收到其他客户端的锁请求时自动释放锁。这个特性在jewel默认开启后，本身没什么问题， 客户端可以自动获取和释放锁，在客户端crash后也能够正确处理。                     |

***

## 3. CephFS 部署

    前文讲述了Ceph中Block存储块的部署教程，并且借用`CSI`架构在K8S中初始化了将要使用的SC（Storage Class），本章节基于CephFS搭建另一个SC，搭建之前先看搭建完成后的总体拓扑图（**注意ConfigMap共享**）：

![](https://22907629-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFnX8FxOr13MrNxviJuye%2Fuploads%2Fgit-blob-59414b21babeb4f987ff65e33f7926b71c3416c7%2F20221203011453.png?alt=media)

    CephFS部署的文件地址从<https://raw.githubusercontent.com/ceph/ceph-csi/master/deploy/cephfs/kubernetes/>下载，将前边命令中的下载地址稍做修改即可，而前文中已经创建了CephFS:

![](https://22907629-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFnX8FxOr13MrNxviJuye%2Fuploads%2Fgit-blob-8b49a6c73bcbc6c551542dd52ba1f8e65ae92033%2F20221203011802.png?alt=media)

    所以跳过前边所有内容的`apply`，直接进入第二章节的第五步。

![](https://22907629-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFnX8FxOr13MrNxviJuye%2Fuploads%2Fgit-blob-d9aa162d2aa448839e0fec7c608417df81050d20%2F20221203012011.png?alt=media)

    查看运行情况：

![](https://22907629-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFnX8FxOr13MrNxviJuye%2Fuploads%2Fgit-blob-9d35b3b69f517fa7d925f4b4942e9c5a07c70df5%2F20221203012056.png?alt=media)

### 3.1. K8S: Secret

1. 使用下边命令查看账号信息`admin`和`k8s`:

   ```shell
   auth get-key client.k8s     # k8s
   auth get-key client.admin   # admin
   ```

   ![](https://22907629-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFnX8FxOr13MrNxviJuye%2Fuploads%2Fgit-blob-2eba00bf5de4f3a98a03db2351acf6845aab6641%2F20221203012353.png?alt=media)
2. 根据两个密钥创建一个新的Secret

   ```yaml
   # 文件：secret-csi-cephfs.yaml
   # 名称：csi-cephfs-secret
   apiVersion: v1
   kind: Secret
   metadata:
       name: csi-cephfs-secret
       namespace: default
   stringData:
       userID: k8s
       userKey: xxx
       adminID: admin
       adminKey: xxx
   ```

   ![](https://22907629-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFnX8FxOr13MrNxviJuye%2Fuploads%2Fgit-blob-5d21d9528ec2f10a4dc1f1e71598756ab7dba0c2%2F20221203012850.png?alt=media)

### 3.2.K8S: StorageClass

1. 先获取集群ID

   ```shell
   ceph -s|grep id|awk -F "[ ]+" '{print $3}'
   ```
2. 编辑配置文件创建SC

   ```yaml
   # 文件：sc-csi-cephfs.yaml
   # 名称：ceph-fs-k8s
   apiVersion: storage.k8s.io/v1
   kind: StorageClass
   metadata:
       name: ceph-fs-k8s
   provisioner: cephfs.csi.ceph.com
   parameters:
       clusterID: 79ed3cf4-6a04-11ed-8db2-fa163ec820ba
       fsName: k8s.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:
       - discard
   ```
3. 将Yaml文件内容配置到K8S

   ```shell
   kubectl apply -f sc-csi-cephfs.yaml
   kubectl get sc
   ```

   ![](https://22907629-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFnX8FxOr13MrNxviJuye%2Fuploads%2Fgit-blob-8fce80d39aa56b52e27e1a0040ec237fb2ce4dd9%2F20221203013641.png?alt=media)
4. 最后创建`PVC`验证当前SC是否可用：

   ```yaml
   # 文件：pvc-csi-fs.yaml
   # 名称：test-fs-pvc
   ---
   apiVersion: v1
   kind: PersistentVolumeClaim
   metadata:
       name: test-fs-pvc     #pvc名称
   spec:
       accessModes:
           - ReadWriteOnce     #访问模式
       resources:
           requests:
               storage: 1Gi           #存储空间
       storageClassName: ceph-fs-k8s   #后端storageclass名称
   ```

   ![](https://22907629-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFnX8FxOr13MrNxviJuye%2Fuploads%2Fgit-blob-2f2786fec2130d279b8bb0a292f8c1cc8e7dd0f0%2F20221203014435.png?alt=media)
5. 最后切换默认SC：

   ```shell
   kubectl patch storageclass ceph-fs-k8s \
       -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
   kubectl get sc
   ```

   ![](https://22907629-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFnX8FxOr13MrNxviJuye%2Fuploads%2Fgit-blob-2c000718fbd4641d6e8e59a1beeeff82c2803ba4%2F20221203014544.png?alt=media)

## 4. 问题

### 4.1. FailedScheduling

```shell
Warning  FailedScheduling  2m16s  default-scheduler  0/3 nodes are available: 1 node(s) had untolerated taint {node-role.kubernetes.io/control-plane: }, 2 node(s) didn't match pod anti-affinity rules. preemption: 0/3 nodes are available: 1 Preemption is not helpful for scheduling, 2 node(s) didn't match pod anti-affinity rules.
```

![](https://22907629-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFnX8FxOr13MrNxviJuye%2Fuploads%2Fgit-blob-ad8162f02241f3559fe6685897ae96e95dcf733c%2F20221130215407.png?alt=media)

    这个问题的主要原因是K8S的Master节点默认是不参与调度的，且在Master节点上有一个**污点**NoSchedule（表示K8S不会将Pod调度到具有污点的Node上），若想让master节点参与调度，则需要先删除污点，允许k8s将Pod调度到该节点Node上，再添加master为nodes角色。

1. 先查看node以及污点

   ```shell
   kubectl get nodes
   kubectl describe node k8s-master |grep Taints
   ```

   ![](https://22907629-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFnX8FxOr13MrNxviJuye%2Fuploads%2Fgit-blob-52b5cfcd410b86b26094102ea30a2edac4cc04bd%2F20221130221150.png?alt=media)
2. 删除污点

   ```shell
   kubectl taint nodes --all node-role.kubernetes.io/control-plane-
   ```

   ![](https://22907629-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFnX8FxOr13MrNxviJuye%2Fuploads%2Fgit-blob-a8f8eb34b4492b9794e7b229772e84050e67ea9c%2F20221130221255.png?alt=media)
3. 再查看Pods运行情况：

   ```shell
   kubectl get pods --all-namespaces -o wide
   ```

   ![](https://22907629-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FFnX8FxOr13MrNxviJuye%2Fuploads%2Fgit-blob-c4233ffd8eb94aa4b9f09eae5da07d39344e58cf%2F20221130221628.png?alt=media)
4. [Kubernetes(k8s) 1.24 csi-ceph rbd使用手册](https://i4t.com/5474.html)

[^1]: [kubernetes ceph-csi分析目录导航（系列）](https://blog.csdn.net/kyle18826138721/article/details/115531669), 作者：[良凯尔](https://blog.csdn.net/kyle18826138721?type=blog)
