k8s 使用rbd存储

k8s使用rbd作为后端存储

  • 主要介绍静态创建rbd,动态创建rbd

  • pv使用rbd存储

1、ceph集群创建rbd

  • 因为是静态创建pv,有了这个rbd后,pv指定这个rbd即可
ceph osd pool create pool01
ceph osd pool application enable pool01 rbd
rbd pool init pool01
rbd create pool01/test --size 5Gi --image-format 2 --image-feature layering


[root@ceph01 ~]# rbd info pool01/test
rbd image 'test':
	size 5 GiB in 1280 objects
	order 22 (4 MiB objects)
	snapshot_count: 0
	id: 121b748877201
	block_name_prefix: rbd_data.121b748877201
	format: 2
	features: layering
	op_features: 
	flags: 
	create_timestamp: Tue Apr  7 20:57:32 2026
	access_timestamp: Tue Apr  7 20:57:32 2026
	modify_timestamp: Tue Apr  7 20:57:32 2026

2、k8s编写yaml文件

  • 这个使用的是filesystem,就是将块设备格式化后,挂载到一个目录上面

  • 也可以使用block,容器里面的参数就需要改成 volumeDevices 裸设备

[root@master01 pv]# cat b1-rbd.yml 
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: rbd-b1
  name: rbd-b1
spec:
  nodeName: master02  # 调度在02上
  volumes:
  - name: rbd 
    rbd:  # 使用rbd作为后端存储
      fsType: xfs  # 格式化了这个块设备
      keyring: /root/admin.keyring  # 密钥文件
      monitors:  # 我是单节点的ceph
      - 192.168.50.30:6789 
      pool: pool01  # rbd存储池
      image: test  # rbd存储池中创建的块
      user: admin  # 用户
      readOnly: false  # 读写都可以
  containers:
  - image: nginx:1.25
    name: rbd-b1
    resources: {}
    volumeMounts:  # rbd格式化后,作为目录挂载
    - name: rbd
      mountPath: /usr/share/nginx/html
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

1、rbd被挂载到容器内部(查看挂载)

  • 发现rbd0直接挂载了,因为上面的配置写了格式化这个rbd0
[root@master01 pv]# kubectl exec -ti rbd-b1 -- /bin/bash

# rbd0挂载到容器这个目录下了
root@rbd-b1:/# df -hT | grep rbd
/dev/rbd0                           xfs      5.0G   69M  5.0G   2% /usr/share/nginx/html

2、修改首页文件内容

root@rbd-b1:/# echo 123 > /usr/share/nginx/html/index.html

  • 访问容器
[root@master01 pv]# kubectl get pod  -o wide
NAME     READY   STATUS    RESTARTS   AGE     IP              NODE       NOMINATED NODE   READINESS GATES
rbd-b1   1/1     Running   0          6m14s   10.244.59.205   master02   <none>           <none>
[root@master01 pv]# curl 10.244.59.205
123

  • 将pod删除后,然后再次创建,看这个首页文件内容是否还存在
[root@master01 pv]# kubectl delete -f b1-rbd.yml --force

[root@master01 pv]# kubectl apply -f b1-rbd.yml 

[root@master01 pv]# kubectl get pod -o wide
NAME     READY   STATUS    RESTARTS   AGE   IP              NODE       NOMINATED NODE   READINESS GATES
rbd-b1   1/1     Running   0          10s   10.244.59.206   master02   <none>           <none>
[root@master01 pv]# curl 10.244.59.206
123

  • 发现首页文件内容还是存在的,这个存储的数据的位置在rbd块中

3、pv使用rbd

上面这个写法,还需要了解这个ceph中一些配置,不同存储不同的写法,屏蔽掉底层的写法,直接使用pv进行绑定rbd,创建一个pvc绑定pv,pod直接使用pvc

1、创建pvc和pv

# pvc配置文件

[root@master01 pv]# cat rbd-pvc.yml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: myclaim
spec:
  accessModes:
    - ReadWriteOnce
  volumeMode: Block  # 默认是filesystem ,block的话就是不格式化,不挂载目录,就是将存储当成裸设备
  resources:
    requests:
      storage: 2Gi 


# pv配置文件

apiVersion: v1
kind: PersistentVolume
metadata:
  name: rbdpv
spec:
  capacity:
    storage: 2Gi
  volumeMode: Block  # 裸设备挂载
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  mountOptions:  # 这个是挂载的选项
    - hard
    - nfsvers=4.1
  rbd:
    fsType: xfs
    image: test  # rbd存储池中的test块
    keyring: /etc/ceph/ceph.client.admin.keyring  # 密钥文件
    monitors:
    - 192.168.50.30
    pool: pool01  # 存储池
    readOnly: false
    user: admin  # ceph用户为admin

# pv和pvc绑定在一起了
[root@master01 pv]# kubectl get pv,pvc
NAME                     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM             STORAGECLASS   REASON   AGE
persistentvolume/rbdpv   2Gi        RWO            Recycle          Bound    default/myclaim                           2m1s

NAME                            STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/myclaim   Bound    rbdpv    2Gi        RWO                           4m47s

2、使用pvc

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: pvc-pod
  name: pvc-pod
spec:
  nodeName: master02  # 指定调度的节点,我将ceph的一些文件传递到这个节点上了
  volumes:
  - name: rbd
    persistentVolumeClaim:
      claimName: myclaim
      readOnly: false
  containers:
  - image: busybox
    imagePullPolicy: IfNotPresent
    name: pvc-pod
    command:
    - /bin/sh
    - -c
    - "sleep 3600"
    volumeDevices:  # 使用的是块设备,所以是这个字段,而不是目录挂载参数
    - devicePath: /dev/rbd1   # 映射到容器里面块设备的名字是rbd1
      name: rbd
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

  • 创建好后,会有哪些操作呢?

    • 我的ceph一些文件传递到master02上了,就可以使用ceph集群了

    • 将rbd中的test这个块映射到容器里面了

3、进入容器查看块设备

# 说明rbd1已经在容器内部了


/ # fdisk /dev/rbd1 

4、rbd原理和绑定pv

  • 原理就是

    • rbd存储池中创建块设备

    • pv进行绑定,pvc绑定pv

    • pod绑定pvc,表现的形式是一个裸设备在容器内部,或者目录挂载也可以的

  • rbd和pv的绑定(volumeMode)

    • filesystem和block参数

    • 支持文件系统,最开始的实验就是文件系统类型的,块设备被格式化,挂载到容器目录上面去了

    • 下面的是裸设备挂载,直接映射到容器里面是一个裸设备

    • 只是容器在配置挂载的时候选项不同而已

      • volumeDevices 块设备挂载

      • volumeMounts 目录挂载

4、动态制备(ceph-csi rbd)

组件 角色 作用
PVC 用户的租房申请 我要 10G 存储
StorageClass(SC) 租房中介 / 规则 找谁租、什么配置
Ceph-CSI 真正的房东 / 工人 真正去 Ceph 里创建磁盘
PV 真实的房子 / 磁盘 最终分配出来的存储
  • 要创建哪些资源

    • 创建一个ceph-csi的pod,配置rbac,secret等等,监控pvc的一些行为

    • 创建一个storageClass,指向这个ceph-csi,是k8s和ceph集群之间的翻译器

      • 里面定义了从ceph集群自动创建rbd

      • 让pod动态的申请pvc,pv

      • 非常的重要这个存储类

img

  • 自动创建pv原理

    • 创建了一个pvc,使用的大小为5G,先去找storageClass(存储类)

    • storageClass 找对应的驱动,ceph-csi

    • ceph-csi插件使用(clusterid,pool,secret)连接ceph集群

    • 在存储池中创建块设备(image)

    • 自动生成pv,绑定pvc

    • pod挂载pvc,实际后端使用的存储为rbd

1、下载ceph-csi项目

# 这个是比较老的版本的ceph-csi
[root@master01 pv]# git clone https://gitee.com/yftyxa/ceph-csi.git

# 里面有很多的文件,rbd,cephfs都可以实现的
[root@master01 deploy]# pwd
/root/pv/ceph-csi/deploy
[root@master01 deploy]# ls
ceph-conf.yaml  cephfs                      Makefile  rbd       service-monitor.yaml
cephcsi         csi-config-map-sample.yaml  nfs       scc.yaml

2、部署ceph-csi

  • 创建一个csi的命名空间
[root@master01 deploy]# kubectl create ns csi

  • 修改第一个文件csi-rbdplugin-provisioner.yaml
[root@master01 kubernetes]# vim csi-rbdplugin-provisioner.yaml

# 改成false 有2处需要改
            - "--extra-create-metadata=false"

  • 修改第二个文件csi-config-map.yaml,配置ceph-csi用于连接ceph monitor的配置文件
[root@master01 kubernetes]# cat csi-config-map.yaml 

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: "ceph-csi-config"
data:
  config.json: |-
    [
      {
        "clusterID": "391a3056-24f0-11f1-abc4-000c2903217e",
        "monitors": ["192.168.50.30"]
    }

]
  • 上面的clusterID 可以 通过 ceph -s 查询到id

  • 修改第三个文件csidriver.yaml

[root@master01 kubernetes]# cat csidriver.yaml 
#
# /!\ DO NOT MODIFY THIS FILE
#
# This file has been automatically generated by Ceph-CSI yamlgen.
# The source for the contents can be found in the api/deploy directory, make
# your modifications there.
#
---
apiVersion: storage.k8s.io/v1
kind: CSIDriver
metadata:
  name: "rbd.csi.ceph.com"
spec:
  attachRequired: true
  podInfoOnMount: false
  #seLinuxMount: true  # 注释这个字段,不识别这个字段
  fsGroupPolicy: File

  • 编写一个configmap,ceph-csi需要一个cm,定义一个空的即可
# 需要有这个才行,否则后面会不成功的
[root@master01 kubernetes]# cat csi-kms-config-map.yaml
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: ceph-csi-encryption-kms-config
data:
  config-json: |-
    {}

3、为ceph-csi生成ceph认证文件

  • ceph的管理员用户的keyring配置成secret

[root@ceph01 ceph]# cat ceph.client.admin.keyring 
[client.admin]
	key = AQBRPL5pKo68KhAAnvurJfOM19nOS5sOAPzO1g==
	caps mds = "allow *"
	caps mgr = "allow *"
	caps mon = "allow *"
	caps osd = "allow *"

# 只需要这个key部分即可

# 编写一个csi-secret.yml

[root@master01 kubernetes]# cat  csi-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: csi-secret
stringData:
  userID: admin
  userKey: AQBRPL5pKo68KhAAnvurJfOM19nOS5sOAPzO1g==
  adminID: admin
  adminKey: AQBRPL5pKo68KhAAnvurJfOM19nOS5sOAPzO1g==

  • ceph-csi还要一个ceph.conf文件,位于deploy目录下,ceph-conf.yaml,不需要修改,默认创建即可

4、替换所有的ns

[root@master01 kubernetes]# sed -i "s/namespace: default/namespace: csi/g"  *.yaml

5、部署

# /root/pv/ceph-csi/deploy/rbd/kubernetes/下面的所有yaml文件部署
kubectl apply -f . -n csi

# 部署ceph-conf.yml文件,位于deploy下面

[root@master01 kubernetes]# kubectl get pod -n csi 

[root@master01 kubernetes]# kubectl get pod -n csi 
NAME                                         READY   STATUS    RESTARTS   AGE
csi-rbdplugin-66t6n                          3/3     Running   0          19s
csi-rbdplugin-7wknj                          3/3     Running   0          19s
csi-rbdplugin-provisioner-648469fc58-77vcb   7/7     Running   0          19s
csi-rbdplugin-provisioner-648469fc58-swvwz   7/7     Running   0          19s


# 如果你的worker节点数量少于3个的话,是需要将 csi-rbdplugin-provisioner.yaml这个文件里面的replicas改小一点的。我改成了2个

5、使用动态制备

1、创建storageClass

[root@master01 rbd]# pwd
/root/pv/ceph-csi/examples/rbd

[root@master01 rbd]# grep -Ev "\s*#|^$" storageclass.yaml 
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
   name: csi-rbd-sc
provisioner: rbd.csi.ceph.com  
parameters:
   clusterID: <cluster-id>
   pool: <rbd-pool-name>
   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
   csi.storage.k8s.io/fstype: ext4
reclaimPolicy: Delete
allowVolumeExpansion: true
mountOptions:
   - discard


  • 将这个里面的内容复制出来
vim q-storageclass.yaml

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
   name: csi-rbd-sc
provisioner: rbd.csi.ceph.com  # 指向了ceph-csi,与ceph-csi进行了绑定
parameters:
   clusterID: 391a3056-24f0-11f1-abc4-000c2903217e  # 集群id
   pool: pool01  # 存储池
   imageFeatures: "layering"
   csi.storage.k8s.io/provisioner-secret-name: csi-secret
   csi.storage.k8s.io/provisioner-secret-namespace: csi
   csi.storage.k8s.io/controller-expand-secret-name: csi-secret
   csi.storage.k8s.io/controller-expand-secret-namespace: csi
   csi.storage.k8s.io/node-stage-secret-name: csi-secret
   csi.storage.k8s.io/node-stage-secret-namespace: csi
   csi.storage.k8s.io/fstype: ext4
reclaimPolicy: Delete
allowVolumeExpansion: true
mountOptions:
   - discard

# apply这个storageClass

[root@master01 pv]# kubectl get storageclasses.storage.k8s.io 
NAME         PROVISIONER        RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
csi-rbd-sc   rbd.csi.ceph.com   Delete          Immediate           true                   15m

修改成这个样子,这里面的clusterID改成自己的,secret-name自己查一下

2、创建pvc

[root@master01 pv]# cat sc-pvc.yml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: sc-pvc
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: "csi-rbd-sc"
  resources:
    requests:
      storage: 3Gi


[root@master01 pv]# kubectl get pvc
NAME     STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
sc-pvc   Bound    pvc-2d948bbe-dbe6-460b-a762-f0279d42437d   3Gi        RWO            csi-rbd-sc     16m

# 自动创建了一个pv出来了
[root@master01 pv]# kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM            STORAGECLASS   REASON   AGE
pvc-2d948bbe-dbe6-460b-a762-f0279d42437d   3Gi        RWO            Delete           Bound    default/sc-pvc   csi-rbd-sc              16m
[root@master01 pv]# 

  • 查看rbd存储池
# pool01里面创建了一个块设备
[root@ceph01 ceph]# rbd ls -p pool01
csi-vol-5b0aa3cf-92aa-498e-84dd-b9ae19eae5d9

3、将sc设置为默认

  • 不设置默认的话,每次pvc都需要指定storageClass,设置默认的话,就会自己去找
[root@master01 pv]# cat q-storageclass.yaml 
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
   name: csi-rbd-sc
   annotations:
     storageclass.kubernetes.io/is-default-class: "true"  # 添加这个为默认的
provisioner: rbd.csi.ceph.com


# 就会有一个default出来
[root@master01 pv]# kubectl get sc 
NAME                   PROVISIONER        RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
csi-rbd-sc (default)   rbd.csi.ceph.com   Delete          Immediate           true                   21m

  • 创建pvc,不指定sc(存储类)
# 没有指定sc
[root@master01 pv]# cat sc-pvc1.yml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: sc-pvc1
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 3Gi


[root@master01 pv]# kubectl get pvc
NAME      STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
sc-pvc    Bound    pvc-2d948bbe-dbe6-460b-a762-f0279d42437d   3Gi        RWO            csi-rbd-sc     24m
sc-pvc1   Bound    pvc-d60250cb-a74d-4131-a703-bc4b04583b72   3Gi        RWO            csi-rbd-sc     41s


# 自动创建了pv,
  • ceph-csi会自动的关联存储类吗

    • 不会

    • 需要这个clusterid

    • provisione

6、总结

1、动态制备的总结

  • 需要一个存储类,ceph-csi

  • pvc创建,ceph-csi能够在ceph集群中创建rbd,pv绑定rbd,pvc绑定pv

2、静态制备

  • 现在ceph集群中创建rbd

  • pv绑定rbd,pvc绑定pv

posted @ 2026-04-07 23:04  乔的港口  阅读(5)  评论(0)    收藏  举报