Kubernetes(k8s) 1.23.5 csi-ceph cephfs使用手册

释放双眼,带上耳机,听听看~!

目前官方Ceph csi版本已经支持Kubernetes 1.23,但是如果我们直接使用最新的ceph csi。在创建cephfs的时候会出现storageclass 创建pvc pending的状态。并且错误日志会提示persistentvolume-controller waiting for a volume to be created, either by external provisioner “cephfs.csi.ceph.com” or manually created by system administrator。因为我们默认yum的ceph deploy会默认给我们安装N版本的ceph,但是最新的Ceph csi版本已经到了Q版本,需要根据实际情况调整版本信息

这个报错的解决方法,修改ceph csi版本,测试得出v3.5.1可以兼容N版本。或者将Ceph集群升级为最新版

已知可用于平台
Ceph CSI驱动程序目前仅在Kubernetes环境中开发和测试。

Ceph CSI版本 容器编排器名称 测试版本
v3.6.1 Kubernetes v1.21、v1.22、v1.23
v3.6.0 Kubernetes v1.21、v1.22、v1.23
v3.5.1 Kubernetes v1.21、v1.22、v1.23
v3.5.0 Kubernetes v1.21、v1.22、v1.23
v3.4.0 Kubernetes v1.21、v1.22、v1.23

Ceph csi组件介绍

ceph-csi组件-作用介绍
(1)create pvc时,external-provisioner组件监听到pvc创建事件后,负责拼接请求,然后调用ceph-csi的CreateVolume方法来创建存储;

(2)delete pvc时,pv对象状态由bound变为release,external-provisioner监听到pv更新事件后,负责拼接请求,调用ceph-csi的DeleteVolume方法来删除存储。

(3)create pod cliam pvc时,kubelet会调用ceph-csi组件将创建好的存储从ceph集群挂载到pod所在的node上,然后再挂载到pod相应的目录上;

(4)delete pod cliam pvc时,kubelet会调用ceph-csi组件相应方法,解除存储在pod目录上的挂载,再解除存储在node上的挂载。
1658764375698.png

ceph-csi组件-服务组成

ceph-csi含有rbdType、cephfsType、livenessType三大类型服务,可以通过启动参数指定一种服务来进行启动。

而rbdType、cephfsType类型的服务可以继续细分,包括了NodeServer、ControllerServer与IdentityServer三种具体的服务,其中NodeServer与ControllerServer只能选其一进行启动,IdentityServer会伴随着NodeServer或ControllerServer的启动而启动。

环境说明

本次环境信息如下

  • kubernetes版本:v1.23.5
  • ceph版本:ceph version 14.2.22 (ca74598065096e6fcbd8433c8779a2be0c889351) nautilus (stable)
  • Ceph-CSI版本: v3.5.1

请务必确定好版本号,必须为N版,新版本需要参考官方最新csi-ceph

版本下载地址
1658686289991.png

#官方下载(后期官方会改名)
wget https://github.com/ceph/ceph-csi/archive/refs/tags/v3.5.1.zip

#abcdocker代理下载地址
wget https://d.frps.cn/file/tools/ceph-csi/cephfs/v3.5.1.zip

替换镜像

#由于官方镜像大部分都是海外k8s.io类型的,可能无法直接使用,所以我们需要替换
#解压压缩包,进入相关镜像目录
[root@k8s-01 cephfs]# cd ceph-csi-3.5.1/deploy/cephfs/kubernetes/

#替换镜像
sed -i s#k8s.gcr.io/sig-storage/csi-provisioner:v3.1.0#registry.cn-beijing.aliyuncs.com/abcdocker/csi-provisioner:v3.1.0#g csi-cephfsplugin-provisioner.yaml
sed -i s#k8s.gcr.io/sig-storage/csi-resizer:v1.3.0#registry.cn-beijing.aliyuncs.com/abcdocker/csi-resizer:v1.3.0#g csi-cephfsplugin-provisioner.yaml
sed -i s#k8s.gcr.io/sig-storage/csi-snapshotter:v4.2.0#registry.cn-beijing.aliyuncs.com/abcdocker/csi-snapshotter:v4.2.0#g csi-cephfsplugin-provisioner.yaml
sed -i s#k8s.gcr.io/sig-storage/csi-attacher:v3.4.0#registry.cn-beijing.aliyuncs.com/abcdocker/csi-attacher:v3.4.0#g csi-cephfsplugin-provisioner.yaml
sed -i s#quay.io/cephcsi/cephcsi:v3.5.1#registry.cn-beijing.aliyuncs.com/abcdocker/cephcsi:v3.5.1#g csi-cephfsplugin-provisioner.yaml
sed -i s#k8s.gcr.io/sig-storage/csi-node-driver-registrar:v2.4.0#registry.cn-beijing.aliyuncs.com/abcdocker/csi-node-driver-registrar:v2.4.0#g csi-cephfsplugin-provisioner.yaml
sed -i s#quay.io/cephcsi/cephcsi:v3.5.1#registry.cn-beijing.aliyuncs.com/abcdocker/cephcsi:v3.5.1#g csi-cephfsplugin.yaml
sed -i s#k8s.gcr.io/sig-storage/csi-node-driver-registrar:v2.4.0#registry.cn-beijing.aliyuncs.com/abcdocker/csi-node-driver-registrar:v2.4.0#g csi-cephfsplugin.yaml

安装Ceph-csi

为sidecar容器和节点插件部署RBAC:

cd ceph-csi-3.5.1/deploy/cephfs/kubernetes/
kubectl create -f csi-provisioner-rbac.yaml
kubectl create -f csi-nodeplugin-rbac.yaml

这些清单部署服务帐户、集群角色和集群角色绑定。这些是RBD和CephFS CSI插件共享的,因为它们需要相同的权限。

为sidecar容器和节点插件部署 PodSecurityPolicy资源:

注意:仅当PodSecurityPolicy 准入控制器在您的集群上处于活动状态时才需要这些清单。

cd ceph-csi-3.5.1/deploy/cephfs/kubernetes/
kubectl create -f csi-provisioner-psp.yaml
kubectl create -f csi-nodeplugin-psp.yaml

为CSI插件部署ConfigMap:

获取ceph集群相关信息

  • 获取ceph集群ID
  • 获取admin key
  • 获取ceph mon节点ip

获取ceph 集群ID

[root@ceph-01 ~]# ceph -s
  cluster:
    id:     c8ae7537-8693-40df-8943-733f82049642    #这里为集群ID,需要复制保留
    health: HEALTH_OK

  services:
    mon: 3 daemons, quorum ceph-01,ceph-02,ceph-03 (age 34h)   #复制ceph mon节点ip
    mgr: ceph-03(active, since 34h), standbys: ceph-02, ceph-01
    mds: cephfs-abcdocker:1 cephfs:1 {cephfs-abcdocker:0=ceph-03=up:active,cephfs:0=ceph-02=up:active} 1 up:standby
    osd: 4 osds: 4 up (since 34h), 4 in (since 8w)
    rgw: 2 daemons active (ceph-01, ceph-02)

  task status:

  data:
    pools:   14 pools, 688 pgs
    objects: 8.73k objects, 31 GiB
    usage:   96 GiB used, 84 GiB / 180 GiB avail
    pgs:     688 active+clean

  io:
    client:   36 KiB/s wr, 0 op/s rd, 0 op/s wr

编辑configmap文件

vim ceph-csi-config.yaml

apiVersion: v1
kind: ConfigMap
data:
  config.json: |-
    [
          {
        "clusterID": "c8ae7537-8693-40df-8943-733f82049642",
        "monitors": [
          "192.168.31.20:6789",
          "192.168.31.21:6789",
          "192.168.31.22:6789"
         ]
       }
    ]
metadata:
  name: ceph-csi-config

这里不建议configmap名称修改

默认的deployment文件还有一个ceph-config configmap,这个也需要创建

vim ceph-config.yaml

apiVersion: v1
kind: ConfigMap
data:
  ceph.conf: |
    [global]
    auth_cluster_required = cephx
    auth_service_required = cephx
    auth_client_required = cephx

    # Workaround for http://tracker.ceph.com/issues/23446
    fuse_set_user_groups = false

    # ceph-fuse which uses libfuse2 by default has write buffer size of 2KiB
    # adding 'fuse_big_writes = true' option by default to override this limit
    # see https://github.com/ceph/ceph-csi/issues/1928
    fuse_big_writes = true
  # keyring is a required key and its value should be empty
  keyring: |
metadata:
  name: ceph-config

创建configmap

[root@k8s-01 kubernetes]# kubectl apply -f ceph-csi-config.yaml 
configmap/ceph-csi-config created

[root@k8s-01 kubernetes]# kubectl apply -f configmap.yaml 
configmap/ceph-config configured
[root@k8s-01 kubernetes]# kubectl get cm 
NAME               DATA   AGE
ceph-csi-config    1      3s
kube-root-ca.crt   1      36d

Ceph csi原理组件以及通信原理介绍

external-provisioner(csi-provisioner)
在启动时通过--provisioner指定自身provisioner名称,与StorageClass中的provisioner字段对应。

(1)watch PVC对象,判断PVC是否需要动态创建存储卷,标准如下:

  • PVC的annotation[volume.beta.kubernetes.io/storage-provisioner](由PV Controller创建)是否与自己的provisioner名称相等。
  • PVC对应StorageClass的VolumeBindingMode若为Immediate,则表示需要立即提供动态存储卷。
    此时调用CSI Plugin的CreateVolume接口,同时创建名为${Provisioner指定的PV前缀}-${PVC uuid}的PV

(2)watch PV对象,判断其是否需要删除,标准如下:

  • 判断其.status.phase是否为Release。
  • 判断其.spec.PersistentVolumeReclaimPolicy是否为Delete。
  • 判断其annotation[pv.kubernetes.io/provisioned-by]是否与自己的provisioner名称相等。
    若需要,则调用CSI Plugin的DeleteVolume接口,同时删除PV对象

external-attacher(csi-attacher)

  • watch VolumeAttachment对象,获得PV的所有信息,如volume ID、node ID等。根据VolumeAttachment的DeletionTimestamp和.status.attached来判断是调用CSI Plugin的ControllerPublish做attach,还是调用CntrollerUnpublish接口做detach
  • 在attacher时为相关PV打上Finalizer;当PV处于删除状态(DeletionTimestamp非空)时,删除Finalizer

external-snapshotter
(1)watch VolumeSnapshot对象,根据其状态调用CSI Plugin的CreateSnapshot接口
等存储快照生成后,它会将存储快照生成的相关信息放到VolumeSnapshotContent对象中,并和用户提交的VolumeSnapshot做bound
(2)当VolumeSnapsho处于删除状态(DeletionTimestamp非空)时,调用CSI Plugin的DeleteSnapshot接口
external-resizer
watch PVC对象,判断用户在PVC中是否增加了需求的存储空间。如果PVC状态是Bound且.status.Capacity与.spec.Resources.Requests不等,则进行卷扩展:

  • 更新PVC的.status.Conditions,表明此时处于Resizing状态
  • 调用CSI Plugin的ControllerExpandVolume接口,若返回值中NodeExpansionRequired=true(还需要Kubelet中的Volume Manager继续调用CSI Plugin的NodeExpandVolume接口进行扩容),则更新PVC的status.Conditions 为 FileSystemResizePending;否则,更新 PVC的.Status.Conditions为空,且更新PVC的status.Capacity。
  • 更新PV的spec.Capacity

node-driver-registrar

调用CSI Plugin的接口获取插件信息,通过Kubelet的插件注册机制将CSI Plugin注册到kubelet

livenessprobe

调用CSI Plugin的Probe接口,同时在/healthz暴露HTTP健康检查探针

因此,CSI分为两部分:

  • 由k8s社区驱动实现的通用的部分,如图中的csi-provisioner和csi-attacher
  • 由云存储厂商实现的csi-controller-server和csi-node-server(一般集成到一个一个CSI Plugin容器中),对接云存储厂商的API实现真正的create/delete/mount/unmount存储的相关操作

1658764767932.png

CSI插件与CSI sidecar容器的组合
一般会在一个CSI Plugin容器中同时实现所有接口,使其同时作为CSI Controller Server和CSI Node Server
它会和Kubernetes官方提供的CSI sidecar容器组成Pod,每种组合都会完成某种功能:
1658764806878.png
CSI Controller Server和External CSI SideCar、CSI Node Server和Kubelet通过Unix Socket来通信:

1658764825289.png

通过CRD管理CSI

对CSI的管理是通过CRD的形式实现的,所以引入了自定义对象类型VolumeAttachment、CSINode、CSIDriver
1658764945816.png

VolumeAttachmen
VolumeAttachment描述一个Volume的attach/detach信息。可以通过VolumeAttachment对一个Volume在某个节点上的attach状态进行跟踪。

VolumeAttachmentSpec数据结构:

  • Attacher
    根据Driver name指定由哪个CSI Plugin来进行attach/detach
  • NodeName
    指定了attach/detach是发生在哪个节点上的
  • Source
    指定了对哪一个PV进行attach/detach。

VolumeAttachmentStatus数据结构:

  • Attached
    指示了是否已经attach

    如果VolumeAttachment的DeletionTimestamp为空且Attached=false,则external-attacher需要调用CSI Plugin的ControllerPublish做attach
    如果VolumeAttachment的DeletionTimestamp不为空且Attached=true,则external-attacher需要调用CSI Plugin的ControllerUnPublish做detach

CSIDriver
CSIDriver描述了部署的CSI Plugin、定义了Kubernetes调用CSI Plugin的行为,需要管理员根据插件类型进行创建

CSIDriverSpec数据结构:

  • AttachRequired
    定义一个Plugin是否支持Attach功能。

    不需要Attach操作时,该标签就是False,说明无需部署external-attacher,也不需要VolumeAttachment对象。

例子:调用CreateVolume接口时,CreateVolumeRequest中VolumeCapability决定了是文件系统直接挂载还是块设备挂载。块存储需要Attach操作,但文件存储不需要Attach操作,例如NFS没有挂载、格式化的概念,只需要mount远端文件系统到本地即可

1658765056590.png
1658765067538.png

  • PodInfoOnMount
    定义了调用CSI Plugin的NodePublishVolume接口时是否带上Pod信息(PodName、PodUID、PodNamespace)。
    默认为false,即CSI Plugin无法获知Pod信息

  • VolumeLifecycleModes
    该CSI Plugin支持哪些VolumeLifecycleMode
    包括Persistent和Ephemeral两种

  • StorageCapacity
    若为true,表示希望调度器调度时考虑节点的存储容量

  • FSGroupPolicy
    Volume挂载前是否允许更改属主、权限的定义

  • TokenRequests
    CSI Plugin可能需要Pod的Service Account Token

  • RequiresRepublish
    若为true,表示CSI Plugin希望不断被调用NodepublishVolume接口,以更新挂载到Pod中的Volume的相关变化。
    不过只能更新Volume的contents,running状态Pod的挂载点是不能改变的

CSINode
CSINode是集群中的节点信息,由Node上的node-driver-registrar在启动时创建。
因此,可以只定义集群中一部分节点拥有CSINode。

CSINodeSpec由一组CSIDriver信息组成。每一个新的CSI Plugin注册后,都会在其中添加自身信息
每个CSI Plugin可添加的CSIDriver信息包括:

  • Name
  • NodeID
  • Allocatable

节点最多可以attach多少个Volume

  • TopologyKeys

该CSINode支持哪些TopologyKeys。进行支持拓扑感知的provisioning时,将会根据这些TopologyKeys从Node获取values,会传递给CSI Plugin
如果CSI Plugin不支持拓扑,可以置为null。

Csi原理部分需要详细查看请前往https://article.itxueyuan.com/vO01wa

部署 CSI Sidecar 容器:

kubectl create -f csi-cephfsplugin-provisioner.yaml
部署配置的部署,其中包括 CSI CephFS 的 external-provisioner、external-attacher。

部署 CSI CephFS 驱动程序:

kubectl create -f csi-cephfsplugin.yaml
#部署一个包含两个容器的守护程序集:CSI node-driver-registrar 和 CSI CephFS 驱动程序。

查看csi pod

[root@k8s-01 kubernetes]# kubectl get pod
NAME                                            READY   STATUS    RESTARTS      AGE
csi-cephfsplugin-4qcf7                          3/3     Running   0             19m
csi-cephfsplugin-982v6                          3/3     Running   0             19m
csi-cephfsplugin-bgq6t                          3/3     Running   0             19m
csi-cephfsplugin-cfpqp                          3/3     Running   0             19m
csi-cephfsplugin-gxctq                          3/3     Running   1 (19m ago)   19m
csi-cephfsplugin-provisioner-7b58b6d568-7fq7x   6/6     Running   0             11m
csi-cephfsplugin-provisioner-7b58b6d568-8snn8   6/6     Running   0             11m
csi-cephfsplugin-provisioner-7b58b6d568-x8b4c   6/6     Running   0             11m

Ceph创建cephfs

CephFS 需要两个Pools - i4t_data和i4t_metadata, 分别存储文件数据和文件元数据

ceph osd pool create i4t_data 16 16
ceph osd pool create i4t_metadata 16 16

注:一般 metadata pool 可以从相对较少的 PGs 启动, 之后可以根据需要增加 PGs. 因为 metadata pool 存储着 CephFS 文件的元数据, 为了保证安全, 最好有较多的副本数. 为了能有较低的延迟, 可以考虑将 metadata 存储在 SSDs 上.

创建一个 CephFS, 名字为 i4tfs:

这里的i4tfs名称以及i4t_metadata i4t_data都需要保留,storageclass需要使用

ceph fs new i4tfs i4t_metadata i4t_data

创建Storageclass

首先我们需要创建一个secret,csi会通过pod访问ceph集群,但是访问集群需要一个用户,我这里就使用admin用户了

获取amdin key

[root@ceph-01 ~]# ceph auth get-key client.admin
AQB1RtxhH/YeHhAAxID/JplTyq77Oa1Pso7HNQ==

使用stringData不需要base64加密

vim secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: csi-cephfs-secret
stringData:
  userID: admin
  userKey: AQB1RtxhH/YeHhAAxID/JplTyq77Oa1Pso7HNQ==
  adminID: admin
  adminKey: AQB1RtxhH/YeHhAAxID/JplTyq77Oa1Pso7HNQ==

创建seceet检查

[root@k8s-01 kubernetes]# kubectl apply -f secret.yaml 
secret/csi-cephfs-secret created
[root@k8s-01 kubernetes]# kubectl get secret
NAME                                 TYPE                                  DATA   AGE
csi-cephfs-secret                    Opaque                                4      5s

创建storageclass

vim i4t_storageclass.yaml

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: csi-cephfs-sc
provisioner: cephfs.csi.ceph.com
parameters:
  clusterID: c8ae7537-8693-40df-8943-733f82049642
  fsName: i4tfs          #cephfs名称,上面创建
  pool: i4t_data           #cephfs pool名称
  #  mounter: fuse       #挂载方式
  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

#对于支持 Delete 回收策略的卷插件,删除动作会将 PersistentVolume 对象从 Kubernetes 中移除,同时也会从外部基础设施(如 AWS EBS、GCE PD、Azure Disk 或 Cinder 卷)中移除所关联的存储资产。 动态供应的卷会继承其 StorageClass 中设置的回收策略,该策略默认 为 Delet

#只有当 PVC 的存储类中将 allowVolumeExpansion 设置为 true 时,你才可以扩充该 PVC 申领

需要注意的是,storageclass需要和上面创建的secret名称对应上csi-cephfs-secret以及命名空间

创建sc并查看

[root@k8s-01 kubernetes]# kubectl apply -f i4t_storageclass.yaml
storageclass.storage.k8s.io/csi-cephfs-sc created
[root@k8s-01 kubernetes]# kubectl get sc
NAME            PROVISIONER           RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
csi-cephfs-sc   cephfs.csi.ceph.com   Delete          Immediate           true                   3s

创建pvc测试

编写pvc文件测试

vim pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: abcdocker-fs-data
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
  storageClassName: csi-cephfs-sc

#pvc名称为abcdocker-fs-data
#资源大小为1G
#ReadWriteMany # PV以read-write挂载到多个节点,cephfs特有访问模式

检查pvc

[root@k8s-01 kubernetes]# kubectl apply -f pvc.yal 
persistentvolumeclaim/abcdocker-fs-data created

我们可以看到,创建好pvc后会自动将我们pvc绑定到pv节点上

[root@k8s-01 kubernetes]# kubectl get pvc
NAME                STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS    AGE
abcdocker-fs-data   Bound    pvc-f931e74a-991b-440e-9180-9c7c283bf4a2   1Gi        RWX            csi-cephfs-sc   4s

可以顺便看一下pv

[root@k8s-01 kubernetes]# kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                           STORAGECLASS    REASON   AGE
pvc-f931e74a-991b-440e-9180-9c7c283bf4a2   1Gi        RWX            Delete           Bound    default/abcdocker-fs-data       csi-cephfs-sc            55s

挂载Pod测试

cat >nginx.yaml<<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
 name: nginx-abcdocker
spec:
 replicas: 2
 selector:
  matchLabels:
   app: nginx
 template:
  metadata:
   labels:
    app: nginx
  spec:
   containers:
   - name: nginx
     image: nginx:latest
     ports:
     - containerPort: 80
       name: web
     volumeMounts:
     - name: www
       mountPath: /usr/share/nginx/html
       subPath: html
   volumes:
   - name: www
     persistentVolumeClaim:
       claimName: abcdocker-fs-data  #填写pvc名称
EOF

进入到nginx容器1中创建静态文件

[root@k8s-01 kubernetes]# kubectl get pod|grep nginx-abcdocker
nginx-abcdocker-7bb898c45c-48t9k                1/1     Running       0             64s
nginx-abcdocker-7bb898c45c-7mvtw                1/1     Running       0             64s
[root@k8s-01 kubernetes]# kubectl exec -it nginx-abcdocker-7bb898c45c-48t9k bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.

root@nginx-abcdocker-7bb898c45c-48t9k:/# 
root@nginx-abcdocker-7bb898c45c-48t9k:/# echo "abcdocker" >>/usr/share/nginx/html/index.html

到nginx 2中查看

[root@k8s-01 kubernetes]# kubectl get pod|grep nginx-abcdocker
nginx-abcdocker-7bb898c45c-48t9k                1/1     Running       0             2m19s
nginx-abcdocker-7bb898c45c-7mvtw                1/1     Running       0             2m19s
[root@k8s-01 kubernetes]# kubectl exec -it nginx-abcdocker-7bb898c45c-7mvtw bash
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
root@nginx-abcdocker-7bb898c45c-7mvtw:/# cat /usr/share/nginx/html/index.html 
abcdocker

给TA买糖
共{{data.count}}人
人已赞赏
Kubernetes

腾讯云Ubuntu二进制搭建高可用(k8s)Kubernetes v1.24.3集群

2022-7-19 15:10:33

Kubernetes

Kubernetes VPA实现Pod垂直缩放

2022-9-23 0:31:20

4 条回复 A文章作者 M管理员
  1. didiplus

    按照你的文章,在我本地的k8s使用ceph的fs一直处于pengding

  2. didiplus

    我在安装ceph是没有指定cluster-network,就指定了public-network,不影响吧

  3. didiplus

    在ceph本地挂载报错😭

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索