暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Kubernetes存储 — Ceph CSI

ProdanLabs 2021-06-23
2148

CSI (容器存储接口) 已经成为了容器存储编排接口规范。Ceph CSI 插件实现了容器存储编排与 Ceph 集群交互的接口,为容器编排系统提供存储服务。Ceph CSI 3 版本增加了很多特性,比如为 RBD 块存储提供了快照的创建和删除、从快照中创建持久卷等。


01

使用的环境

Kubernetes

# kubectl get nodes
NAME                      STATUS   ROLES    AGE     VERSION
izwz90brjjogtbgisvc5bnz   Ready    <none>   6d23h   v1.20.6
izwz90brjjogtbgisvc5boz   Ready    <none>   6d23h   v1.20.6
izwz90brjjogtbwd0sw5gvz   Ready    <none>   6d20h   v1.20.6

Ceph

# ceph version
ceph version 15.2.13 (c44bc49e7a57a87d84dfff2a077a2058aa2172e2) octopus (stable)


Ceph Pool

# rados lspools 
device_health_metrics
rbd


Ceph-CSI 版本信息,本文只使用 RBD


02

Ceph CSI RBD 安装

创建 ceph-csi 配置 ConfigMap 对象,ceph-csi 目前只支持旧版 V1 协议,即 6789 端口。

clusterID 是 ceph fsid

# cat <<EOF > csi-config-map.yaml
---
apiVersion: v1
kind: ConfigMap
data:
  config.json: |-
    [
      {
        "clusterID""bd241c5a-d012-11eb-8215-e977530c8b31",
        "monitors": [
          "172.16.x.x:6789",
          "172.16.x.x:6789",
          "172.16.x.x:6789"
        ]
      }
    ]
metadata:
  name: ceph-csi-config
  namespace: kube-system
EOF

# kubectl create -f  csi-config-map.yaml


ceph-csi 的最新版本还需要一个额外的 ConfigMap 对象来定义密钥管理服务 (KMS) 提供程序的详细信息。加密 KMS 配置是为了进一步提高安全稳健性,可以理解成 PVC 加密,目前 HashiCorp Vault 是唯一支持的 KMS。

如果设置 KMS,在 csi-kms-config-map.yaml 文件中放置一个空配置即可。

# cat <<EOF > csi-kms-config-map.yaml
---
apiVersion: v1
kind: ConfigMap
data:
  config.json: |-
    {}
metadata:
  name: ceph-csi-encryption-kms-config
  namespace: kube-system
EOF

# kubectl create -f  csi-kms-config-map.yaml


ceph-csi 需要 cephx 凭据才能与 Ceph 集群通信,这里使用的是 admin 用户。

# USER_KEY=$(ceph auth get-key  client.admin)
# cat <<EOF > csi-rbd-secret.yaml
---
apiVersion: v1
kind: Secret
metadata:
  name: csi-rbd-secret
  namespace: kube-system
stringData:
  userID: admin
  userKey: ${USER_KEY}
EOF

# kubectl create -f  csi-rbd-secret.yaml


ceph-csi 默认使用开发版本 (quay.io/cephcsi/cephcsi:canary), 这里换成 v3.3.1 版本。

# 下载 yaml 文件
wget https://raw.githubusercontent.com/ceph/ceph-csi/release-v3.3/deploy/rbd/kubernetes/csi-provisioner-rbac.yaml
wget https://raw.githubusercontent.com/ceph/ceph-csi/release-v3.3/deploy/rbd/kubernetes/csi-nodeplugin-rbac.yaml
wget https://raw.githubusercontent.com/ceph/ceph-csi/release-v3.3/deploy/rbd/kubernetes/csi-rbdplugin-provisioner.yaml
wget https://raw.githubusercontent.com/ceph/ceph-csi/release-v3.3/deploy/rbd/kubernetes/csi-rbdplugin.yaml


ceph-csi 默认部署在 default 命名空间,这里改到 kube-system 。

创建 rbac

sed -i "s/namespace: default/namespace: kube-system/g" $(grep -rl "namespace: default" ./)
kubectl -n kube-system create -f csi-provisioner-rbac.yaml
kubectl -n kube-system create -f csi-nodeplugin-rbac.yaml


部署 ceph-csi rbd ,有些镜像的仓库是 k8s.gcr.io , 网络有问题的需要更换仓库。

sed -i 's/v3.3-canary/v3.3.1/g' $(grep -rl "v3.3-canary" ./)

kubectl -n kube-system create -f csi-rbdplugin-provisioner.yaml
kubectl -n kube-system create -f csi-rbdplugin.yaml


创建 StorageClass

# cat <<EOF > csi-rbd-sc.yaml
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
   name: ceph-csi
provisioner: rbd.csi.ceph.com
parameters:
   clusterID: bd241c5a-d012-11eb-8215-e977530c8b31
   pool: rbd
   imageFeatures: layering
   csi.storage.k8s.io/provisioner-secret-name: csi-rbd-secret
   csi.storage.k8s.io/provisioner-secret-namespace: kube-system
   csi.storage.k8s.io/controller-expand-secret-name: csi-rbd-secret
   csi.storage.k8s.io/controller-expand-secret-namespace: kube-system
   csi.storage.k8s.io/node-stage-secret-name: csi-rbd-secret
   csi.storage.k8s.io/node-stage-secret-namespace: kube-system
reclaimPolicy: Delete
allowVolumeExpansion: true
mountOptions:
   - discard
EOF

# kubectl create -f  csi-rbd-sc.yaml


创建 PVC

# cat <<EOF > pvc.yaml
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: rbd-pvc
spec:
  accessModes:
    - ReadWriteOnce
  volumeMode: Filesystem
#  volumeMode: Block
  resources:
    requests:
      storage: 1Gi
  storageClassName: ceph-csi
EOF
# kubectl apply -f pvc.yaml


创建 pod

# cat <<EOF > pod.yaml
---
apiVersion: v1
kind: Pod
metadata:
  name: nginx-ceph-csi-test
spec:
  containers:
    - name: nginx
      image: nginx:1.21.0-alpine
      volumeMounts:
        - name: mypvc
          mountPath: /data
  volumes:
    - name: mypvc
      persistentVolumeClaim:
        claimName: rbd-pvc
        readOnly: false
EOF
# kubectl apply -f pod.yaml


加入 pod 查看

# kubectl exec -it nginx-ceph-csi-test -- sh
/ # df -Th | grep /data
/dev/rbd1            ext4          975.9M      2.5M    957.4M   0% /data


03

PVC 扩容

PVC 支持扩容的文件系统是 XFS、Ext3 和 Ext4 ,且在 StorageClass 声明 allowVolumeExpansion: true
,Kubernetes 1.15 版本开始默认开启在线扩容,由
--feature-gates
 数中的 ExpandInUsePersistentVolumes=true
 控制。


扩容前为 1G

# kubectl get pvc rbd-pvc 
NAME      STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
rbd-pvc   Bound    pvc-937e9588-95ff-475f-9473-513e18a96f37   1Gi        RWO            ceph-csi       7m56s
# kubectl describe pv pvc-937e9588-95ff-475f-9473-513e18a96f37  | grep imageName
                           imageName=csi-vol-b16dd8bf-d364-11eb-9891-56a6d268783b
# rbd info csi-vol-b16dd8bf-d364-11eb-9891-56a6d268783b
rbd image 'csi-vol-b16dd8bf-d364-11eb-9891-56a6d268783b':
        size 1 GiB in 256 objects
        order 22 (4 MiB objects)
        snapshot_count: 0
        id: 8f71d10b5f20
        block_name_prefix: rbd_data.8f71d10b5f20
        format: 2
        features: layering
        op_features: 
        flags: 
        create_timestamp: Tue Jun 22 22:18:19 2021
        access_timestamp: Tue Jun 22 22:18:19 2021
        modify_timestamp: Tue Jun 22 22:18:19 2021


扩容比较简单,直接修改 PVC 的容量即可。

# kubectl edit pvc rbd-pvc


扩容到 2G

# kubectl get pvc rbd-pvc
NAME      STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
rbd-pvc   Bound    pvc-937e9588-95ff-475f-9473-513e18a96f37   2Gi        RWO            ceph-csi       12m
# rbd info csi-vol-b16dd8bf-d364-11eb-9891-56a6d268783b
rbd image 'csi-vol-b16dd8bf-d364-11eb-9891-56a6d268783b':
        size 2 GiB in 512 objects
        order 22 (4 MiB objects)
        snapshot_count: 0
        id: 8f71d10b5f20
        block_name_prefix: rbd_data.8f71d10b5f20
        format: 2
        features: layering
        op_features: 
        flags: 
        create_timestamp: Tue Jun 22 22:18:19 2021
        access_timestamp: Tue Jun 22 22:18:19 2021
        modify_timestamp: Tue Jun 22 22:18:19 2021

#
 kubectl exec -it nginx-ceph-csi-test -- sh
/ # df -Th | grep /data
/dev/rbd1            ext4            1.9G      3.0M      1.9G   0% /data
/ # 


04

卷快照

从 Kubernetes 1.17 开始卷快照(Volume Snapshot)功能默认开启,由 --feature-gates
参数中的  VolumeSnapshotDataSource=true
控制。卷快照功能不属于 Kubernetes 核心 API。它的 API 对象 VolumeSnapshot
VolumeSnapshotContent
VolumeSnapshotClass
是通过 CRDs 实现的。


卷快照控制器 (snapshot controller) 是独立于 CSI 之外的,目前由 external-snapshotter 项目提供支持,无论 Kubernetes 中部署了多少个 CSI ,都需要部署一个卷快照控制器。


// 拷贝源码到本地
# git clone https://github.com/kubernetes-csi/external-snapshotter
# cd external-snapshotter

// 安装快照 CRD
kubectl create -f client/config/crd

// 安装通用快照控制器
kubectl create -f deploy/kubernetes/snapshot-controller

// 安装 CSI 驱动程序, 这里安装到 kube-system 命名空间
sed -i "s/namespace: default/namespace: kube-system/g" .deploy/kubernetes/csi-snapshotter/*
kubectl create -f deploy/kubernetes/csi-snapshotter   -n kube-system 


创建 snapshotclass

# cat <<EOF > snapshotclass.yaml
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
  name: csi-rbdplugin-snapclass
driver: rbd.csi.ceph.com
parameters:
  clusterID: bd241c5a-d012-11eb-8215-e977530c8b31
  csi.storage.k8s.io/snapshotter-secret-name: csi-rbd-secret
  csi.storage.k8s.io/snapshotter-secret-namespace: kube-system
deletionPolicy: Delete
EOF

# kubectl create -f  snapshotclass.yaml

# kubectl get volumesnapshotclass
NAME                      DRIVER             DELETIONPOLICY   AGE
csi-rbdplugin-snapclass   rbd.csi.ceph.com   Delete           46s


加入 pod 写入一些数据进行测试

# kubectl exec -it nginx-ceph-csi-test -- sh
/ # cd /data/
/data # for i in $(seq 1 100); do echo $i; echo $RANDOM  >>./datatest.db; done


创建快照

# cat <<EOF > rbd-pvc-snapshot.yaml
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: rbd-pvc-snapshot
spec:
  volumeSnapshotClassName: csi-rbdplugin-snapclass
  source:
    persistentVolumeClaimName: rbd-pvc
EOF

# kubectl create -f  rbd-pvc-snapshot.yaml

# kubectl get volumesnapshot
NAME               READYTOUSE   SOURCEPVC   SOURCESNAPSHOTCONTENT   RESTORESIZE   SNAPSHOTCLASS             SNAPSHOTCONTENT                                    CREATIONTIME   AGE
rbd-pvc-snapshot   true         rbd-pvc                             2Gi           csi-rbdplugin-snapclass   snapcontent-b0dfbe62-0b11-4aa9-a473-ddb07866fdb3   14s            15s


查看快照

# rbd ls
csi-snap-6e94b74c-d368-11eb-84a2-82c03fe56569
csi-vol-b16dd8bf-d364-11eb-9891-56a6d268783b

# rbd snap ls  csi-snap-6e94b74c-d368-11eb-84a2-82c03fe56569 -p rbd
SNAPID  NAME                                           SIZE   PROTECTED  TIMESTAMP               
     5  csi-snap-6e94b74c-d368-11eb-84a2-82c03fe56569  2 GiB             Tue Jun 22 22:45:06 2021


删除测试数据

# kubectl exec -it nginx-ceph-csi-test -- sh
/ # cd /data/
/data # ls -lrt
total 20
drwx------    2 root     root         16384 Jun 22 14:21 lost+found
-rw-r--r--    1 root     root           564 Jun 22 14:23 datatest.db
/data # rm -f datatest.db 
/data # ls -lrt
total 16
drwx------    2 root     root         16384 Jun 22 14:21 lost+found


恢复快照

# cat <<EOF > rbd-pvc-snapshot.yaml
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: rbd-pvc-restore
spec:
  storageClassName: ceph-csi
  dataSource:
    name: rbd-pvc-snapshot
    kind: VolumeSnapshot
    apiGroup: snapshot.storage.k8s.io
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi
EOF
# kubectl create -f  rbd-pvc-snapshot.yaml


从快照中创建了一个的 PVC

# kubectl get pvc
NAME              STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
rbd-pvc           Bound    pvc-937e9588-95ff-475f-9473-513e18a96f37   2Gi        RWO            ceph-csi       36m
rbd-pvc-restore   Bound    pvc-ffbb56a4-be3f-47fb-b92e-c2db1df92a97   2Gi        RWO            ceph-csi       12s

# rbd ls
csi-snap-6e94b74c-d368-11eb-84a2-82c03fe56569
csi-vol-b16dd8bf-d364-11eb-9891-56a6d268783b
csi-vol-c4785c04-d369-11eb-9891-56a6d268783b


编辑 pod ,把新创建的 PVC 挂载上去

# cat pod.yaml 
---
apiVersion: v1
kind: Pod
metadata:
  name: nginx-ceph-csi-test
spec:
  containers:
    - name: nginx
      image: nginx:1.21.0-alpine
      volumeMounts:
        - name: mypvc
          mountPath: /data
  volumes:
    - name: mypvc
      persistentVolumeClaim:
        claimName: rbd-pvc-restore
        readOnly: false
# kubectl create -f pod.yaml 
# kubectl exec -it nginx-ceph-csi-test -- sh
/ # cd /data/
/data # ls -lrt
total 20
drwx------    2 root     root         16384 Jun 22 14:21 lost+found
-rw-r--r--    1 root     root           564 Jun 22 14:23 datatest.db
/data # more datatest.db 
17542
26974
29622
32377
9929
29734
26492
...


也可以使用 ceph CLI 进行操作。


pod 使用原来的 rbd-pvc ,然后写入数据数据

# kubectl exec -it nginx-ceph-csi-test -- sh
/ # cd /data/
/data # for i in $(seq 1 100); do echo $i; echo $RANDOM  >>./datatest.db; done


创建快照

# rbd snap create rbd/csi-vol-b16dd8bf-d364-11eb-9891-56a6d268783b@snapshot1
# rbd snap ls rbd/csi-vol-b16dd8bf-d364-11eb-9891-56a6d268783b
SNAPID  NAME       SIZE   PROTECTED  TIMESTAMP               
     6  snapshot1  2 GiB             Tue Jun 22 23:14:24 2021


删除测试数据

# kubectl exec -it nginx-ceph-csi-test -- sh
/ # cd data/
/data # ls -lrt
total 20
drwx------    2 root     root         16384 Jun 22 14:21 lost+found
-rw-r--r--    1 root     root           574 Jun 22 15:12 datatest.db
/data # rm -f datatest.db 
/data # ls -lrt
total 16
drwx------    2 root     root         16384 Jun 22 14:21 lost+found


恢复快照

# rbd snap rollback rbd/csi-vol-b16dd8bf-d364-11eb-9891-56a6d268783b@snapshot1
Rolling back to snapshot: 100% complete...done.


重启 pod 后验证。

# kubectl exec -it nginx-ceph-csi-test -- sh
/ # cd /data/
/data # ls -lrt
total 20
drwx------    2 root     root         16384 Jun 22 14:21 lost+found
-rw-r--r--    1 root     root           574 Jun 22 15:12 datatest.db


05

写在最后

在 Ceph 中 object (对象)是最小存储单元,默认是 4MB,无论使用对象存储、块存储还是文件系统挂载的存储方式,存储的数据都会被切分成对象,由 PG (Place Group) 管理,object 通过 Hash 映射到 PG 中,一个 PG 可以包含多个 object ,PG 再通过 CRUSH 计算映射到 OSD 中。如果是三副本的,则每个 PG 都会映射到三个 OSD ,保证了数据的冗余。数据迁移或拷贝时,也是以 PG 作为基本单位进行的,Ceph 不会直接操作对象。


数据是一家企业的基石,数据安全的重要性毋庸置疑。在 Kubernetes 中卷快照功能,velero 也可以做到,还可以备份 Kubernetes 其他资源对象的数据,感兴趣的读者可以去了解下。



Kubernetes存储 — Ceph RBD

Kubernetes网络 — Cilium eBPF模式

Kubernetes网络 — Calico BGP模式

文章转载自ProdanLabs,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论