Rook是一个开源的云原生存储编排器,为Ceph存储提供平台、框架和支持,使其能够与云原生环境进行本地集成。Ceph是一个分布式存储系统,提供文件(file)、块(block)和对象存储(object storage),并在大规模生产集群中部署。
使用Rook可以自动部署和管理Ceph,提供自我管理、自我扩展和自我修复的存储服务。Rook Operator通过Kubernetes Resources来部署(deploy)、配置(configure)、供应(provision)、扩展(scale)、升级(upgrade)和监控(monitor)Ceph。
Rook v1.15支持以下Ceph版本:
- Ceph Squid v19.2.0或更新版本
- Ceph Reef v18.2.0或更新版本
- Ceph Quincy v17.2.0或更新版本
本文将实践使用Rook 1.15部署和管理Ceph(Reef) 18.2.1。
1.准备
1.1 K8S集群准备
Rook 1.15支持Kubernetes从v1.26到v1.31版本。
本文使用的Kubernetes集群如下:
kubectl get node
NAME STATUS ROLES AGE VERSION
node85 Ready control-plane,edge 22h v1.31.3
node86 Ready <none> 21h v1.31.3关于容器运行时的配置,这里的Kubernetes集群的容器运行时是Containerd。
注意如果Containerd的systemd配置containerd.service中如果有LimitNOFILE=infinity的配置,后边在使用rook启动Ceph集群时,Ceph的Mon组件会有问题,会出现ms_dispatch进程的cpu一直是100%,Rook社区有两个ISSUES ISSUE 11253和ISSUE 10110讨论了这个问题,需要将LimitNOFILE设置一个合适的值,这里设置的是1048576。
1.2 设置各个服务器节点的时间同步
注意设置各个服务器节点的时间同步,这个十分重要,如果各个服务器节点时间不同步时,rook ceph operator在操作时,ceph mon组件的可能会无法正常工作。
关于时间同步推荐使用chronyd。
1.3 本地存储准备(LVM逻辑卷)
要配置Ceph存储集群,至少需要以下其中一种本地存储:
- 原始设备(Raw devices)(无分区或格式化文件系统)
- 原始分区(Raw partitions)(无格式化文件系统)
- LVM逻辑卷(无格式化文件系统)
- 以块模式(block mode)在存储类(storage class)中提供的持久卷。
本文将使用的本地存储是LVM逻辑卷。
本文中node85, node86三台主机上都各有2个未格式化文件系统的逻辑卷(LV),将被用作Ceph集群的本地存储。
lvdisplay
--- Logical volume ---
LV Path /dev/ceph_c/osd_c
LV Name osd_c
VG Name ceph_c
LV Size <256.00 GiB
--- Logical volume ---
LV Path /dev/ceph_b/osd_b
LV Name osd_b
VG Name ceph_b
LV Size 256.00 GiB2个逻辑卷的基本信息如下:
- 逻辑卷名称
osd_c,所属卷组ceph_c,路径为/dev/ceph_c/osd_c - 逻辑卷名称
osd_b,所属卷组为ceph_b,路径为/dev/ceph_b/osd_b
2.部署Rook Operator
本文使用的Kubernetes集群只有node85,node86这2个节点, Ceph集群的各个组件混部在这2个节点上,对于更多节点的生产级别配置,可以对label做更精细化的配置,例如node-role.kubernetes.io/ceph-mon=ceph-mon等等。
这里将2个节点都打上role=ceph的label:
kubectl label nodes node85 role=ceph
kubectl label nodes node86 role=ceph将通过使用Rook Helm Chart来部署rook ceph operator。
Rook目前将Ceph Operator的构建版本发布到发布(release)和主要(master)通道。发布通道是Rook的最新稳定版。
helm repo add rook-release https://charts.rook.io/release
helm install --create-namespace --namespace rook-ceph rook-ceph rook-release/rook-ceph -f values.yaml或者从https://charts.rook.io/release/rook-ceph-v1.15.6.tgz下载rook-ceph的helm chart,再使用下面的命令安装:
helm install --create-namespace --namespace rook-ceph rook-ceph rook-ceph-v1.15.6.tgz -f values.yaml关于values.yaml中配置的内容,可以根据文档https://github.com/rook/rook/blob/master/deploy/charts/rook-ceph-cluster/values.yaml中的内容按需定制。
以下是这里所定制的内容,主要配置了在部署Rook Operator和Ceph时使用私有的镜像仓库地址,以及调度相关的配置。
image:
pullPolicy: IfNotPresent
repository: registry.frognew.com/library/rook/ceph
tag: v1.13.1
imagePullSecrets:
- name: regsecret
tolerations:
- key: "dedicated"
operator: "Equal"
value: "ceph"
effect: "NoSchedule"
provisionerNodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: role
operator: In
values:
- ceph
provisionerTolerations:
- key: "dedicated"
operator: "Equal"
value: "ceph"
effect: "NoSchedule"
pluginNodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: role
operator: In
values:
- ceph
pluginTolerations:
- key: "dedicated"
operator: "Equal"
value: "ceph"
effect: "NoSchedule"
discover:
tolerations:
- key: "dedicated"
operator: "Equal"
value: "ceph"
effect: "NoSchedule"
nodeAffinity:
nodeSelectorTerms:
- matchExpressions:
- key: role
operator: In
values:
- ceph
admissionController:
tolerations:
- key: "dedicated"
operator: "Equal"
value: "ceph"
effect: "NoSchedule"
- key: "node-role.kubernetes.io/master"
operator: "Exists"
effect: "PreferNoSchedule"
nodeAffinity:
nodeSelectorTerms:
- matchExpressions:
- key: role
operator: In
values:
- ceph
csi:
kubeletDirPath: /var/lib/kubelet
cephcsi:
# -- Ceph CSI image repository
repository: registry.frognew.com/gcr/quay.io/cephcsi/cephcsi
registrar:
# -- Kubernetes CSI registrar image repository
repository: registry.frognew.com/gcr/registry.k8s.io/sig-storage/csi-node-driver-registrar
provisioner:
# -- Kubernetes CSI provisioner image repository
repository: registry.frognew.com/gcr/registry.k8s.io/sig-storage/csi-provisioner
snapshotter:
# -- Kubernetes CSI snapshotter image repository
repository: registry.frognew.com/gcr/registry.k8s.io/sig-storage/csi-snapshotter
attacher:
# -- Kubernetes CSI Attacher image repository
repository: registry.frognew.com/gcr/registry.k8s.io/sig-storage/csi-attacher
resizer:
# -- Kubernetes CSI resizer image repository
repository: registry.frognew.com/gcr/registry.k8s.io/sig-storage/csi-resizerhttps://github.com/rook/rook/blob/v1.15.6/deploy/examples/images.txt这个地址里面有部署Rook Operator和Ceph所需的所有容器镜像,可以根据需要预先同步到私有镜像仓库中。
本文中用到的镜像如下:
rook/ceph:v1.15.6
quay.io/ceph/ceph:v19.2.0
quay.io/ceph/cosi:v0.1.2
quay.io/cephcsi/cephcsi:v3.12.2
quay.io/csiaddons/k8s-sidecar:v0.9.1
registry.k8s.io/sig-storage/csi-attacher:v4.6.1
registry.k8s.io/sig-storage/csi-node-driver-registrar:v2.11.1
registry.k8s.io/sig-storage/csi-provisioner:v5.0.1
registry.k8s.io/sig-storage/csi-resizer:v1.11.1
registry.k8s.io/sig-storage/csi-snapshotter:v8.0.1部署完成后,确认rook-ceph-operator的正常启动:
kubectl get pods -n rook-ceph -l "app=rook-ceph-operator"
NAME READY STATUS RESTARTS AGE
rook-ceph-operator-746cf54f54-qsttv 1/1 Running 0 3m36s3.创建Ceph集群
3.1 参考文档
Rook文档侧重于在各种环境中启动Rook。在创建Ceph集群时,可以考虑在以下的示例集群清单基础上做定制:
- cluster.yaml:用于在裸机上运行的生产集群的集群设置。需要至少三个工作节点。
- cluster-on-pvc.yaml:用于在动态云环境中运行的生产集群的集群设置。
- cluster-test.yaml:用于测试环境(如 minikube)的集群设置。
有关更多详细信息,可参考Ceph的示例配置。
Rook Ceph Operator已经部署完成并正常运行,接下来可以创建Ceph集群了,这里选择的是cluster.yaml。
3.2 创建集群
基于cluster.yaml定制我们自己的cluster.yaml,以下是只包含cluster.yaml的修改内容:
...
apiVersion: ceph.rook.io/v1
kind: CephCluster
metadata:
name: rook-ceph
namespace: rook-ceph
spec:
cephVersion:
image: registry.frognew.com/gcr/quay.io/ceph/ceph:v19.2.0
dataDirHostPath: /home/rook
mon:
count: 3
# 本文的试验环境只有2个k8s node, 所以这里设置allowMultiplePerNode=true, 即允许多个ceph mon实例在同一个节点上
allowMultiplePerNode: true
...
dashboard:
enabled: true
ssl: false
...
# storage:
# useAllNodes: true
# useAllDevices: true
# devices:
# - name: /dev/disk/by-id/dm-name-ceph-osd
# config:
# osdsPerDevice: "1"
storage:
useAllNodes: true
useAllDevices: true
devices:
# /dev/disk/by-id/dm-name-<vgName>-<lvName>
- name: /dev/disk/by-id/dm-name-ceph_b-osd_b
- name: /dev/disk/by-id/dm-name-ceph_c-osd_c
config:
osdsPerDevice: "1"
...
placement:
all:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: role
operator: In
values:
- ceph
podAffinity:
podAntiAffinity:
topologySpreadConstraints:
tolerations:
- key: "dedicated"
operator: "Equal"
value: "ceph"
effect: "NoSchedule"
- key: "node-role.kubernetes.io/master"
operator: "Exists"
effect: "PreferNoSchedule"
...因为Ceph集群的本地存储将使用前面创建的未格式化文件系统的LVM逻辑卷,将要使用的逻辑卷如下:
- 逻辑卷名称
osd_c,所属卷组ceph_c,路径为/dev/ceph_c/osd_c - 逻辑卷名称
osd_b,所属卷组为ceph_b,路径为/dev/ceph_b/osd_b
Rook是从1.9开始支持使用LVM逻辑卷作为本地存储的,具体实现的代码是这个PR https://github.com/rook/rook/pull/7967。
文档CephCluster CRD中对如何使用逻辑卷作存储的说明不是特别详细。从PR的实现代码上看,当前是要在CephCluster的资源定义中的spec.storage.devices[].name配置为/dev/disk/by-id/dm-name-<vgName>-<lvName>。
所以我们的cluster.yaml配置的spec.storage部分, devices[].name的值是:
devices:
# /dev/disk/by-id/dm-name-<vgName>-<lvName>
- name: /dev/disk/by-id/dm-name-ceph_b-osd_b
- name: /dev/disk/by-id/dm-name-ceph_c-osd_c创建Ceph集群:
kubectl create -f cluster.yaml
cephcluster.ceph.rook.io/rook-ceph created通过查看rook-ceph命名空间中的pod,验证集群是否正在运行。
kubectl get po -n rook-ceph
NAME READY STATUS RESTARTS AGE
csi-cephfsplugin-k4pj5 3/3 Running 9 34m
csi-cephfsplugin-provisioner-56ff664cd5-9hmk2 6/6 Running 0 11m
csi-cephfsplugin-provisioner-56ff664cd5-fl9r4 6/6 Running 0 11m
csi-cephfsplugin-vdpsl 3/3 Running 9 34m
csi-rbdplugin-6ghxv 3/3 Running 9 34m
csi-rbdplugin-j7p6g 3/3 Running 9 34m
csi-rbdplugin-provisioner-b99bb6cdd-g4ttv 6/6 Running 0 11m
csi-rbdplugin-provisioner-b99bb6cdd-gws6x 6/6 Running 0 11m
rook-ceph-crashcollector-node85-77997c7f8-n9k8s 1/1 Running 0 33m
rook-ceph-crashcollector-node86-6c7fcffbd7-pknnk 1/1 Running 0 33m
rook-ceph-exporter-node85-6cf4bb86c6-vtjdp 1/1 Running 0 32m
rook-ceph-exporter-node86-6697d7d985-x6hrp 1/1 Running 0 32m
rook-ceph-mgr-a-6bf55b47b5-mns2x 3/3 Running 0 33m
rook-ceph-mgr-b-57c667df64-dh8c9 3/3 Running 0 33m
rook-ceph-mon-a-f585c9764-bjx5l 2/2 Running 0 34m
rook-ceph-mon-b-67c4cf8866-grz7l 2/2 Running 0 33m
rook-ceph-mon-c-6d7db87656-tj9l9 2/2 Running 0 33m
rook-ceph-operator-746cf54f54-qsttv 1/1 Running 0 54m
rook-ceph-osd-0-84db95b9c6-l4br7 2/2 Running 0 33m
rook-ceph-osd-1-9bd4595cd-fkzcq 2/2 Running 0 33m
rook-ceph-osd-2-5b6646f565-w4sst 2/2 Running 0 33m
rook-ceph-osd-3-688b87cb5b-78xc9 2/2 Running 0 33m
rook-ceph-osd-prepare-node85-2r7xs 0/1 Completed 0 33m
rook-ceph-osd-prepare-node86-6dfql 0/1 Completed 0 33mosd pod的数量取决于集群中的节点数量和配置的设备数量。对于上述默认的cluster.yaml,将为每个节点上找到的每个可用设备创建一个OSD。
创建过程如果遇到问题可以查看rook-ceph-operator的Pod的日志。
如需重新运行rook-ceph-osd-prepare-<nodename> Job,扫描可用本地存储添加OSD,可以执行以下命令:
# 删除旧的job
kubectl get job -n rook-ceph | awk '{system("kubectl delete job "$1" -n rook-ceph")}'
# 重启operator
kubectl rollout restart deploy rook-ceph-operator -n rook-ceph每个节点上的osd能否添加成功,要注意查看rook-ceph-osd-prepare-<nodename> Job对应Pod的日志。
4.验证集群状态
为了验证集群处于健康状态, 需要Rook工具箱。
kubectl apply -f https://raw.githubusercontent.com/rook/rook/release-1.15/deploy/examples/toolbox.yaml
kubectl get po -n rook-ceph | grep rook-ceph-tools
rook-ceph-tools-8bd944548-srfrz 1/1 Running 0 103s注: 当前release-1.15/deploy/examples/toolbox.yaml中的Ceph镜像还是v18.2.4,可以手动修改成v19.2.0
连接到工具箱,并运行ceph status 命令:
kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- bash警告
因为这个试验环境部署的Ceph集群虽然有4个OSD,但这4个OSD分布在2个主机上,当前集群上的存储池.mgr默认是3副本的,这在默认情况下无法满足要求(默认要求3副本的osd必须分布在3个主机上)。
ceph osd lspools
1 .mgr
ceph osd pool get .mgr size
size: 3
ceph osd pool get .mgr min_size
min_size: 2因为这里只是试验环境,故可调整存储池.mgr的配置,将副本数设置为2:
ceph osd pool set .mgr size 2
ceph osd pool set .mgr min_size 1实际生产环境要求至少3个主机节点,3个以上osd。
以下是健康状态的验证要点:
- 所有的 monitor (mon) 节点应该处于 quorum(一致性)状态。
- 一个管理器 (mgr) 节点应该处于活动状态。
- 至少有三个 OSD 节点应该处于上线并可用状态。
如果健康状态不是 HEALTH_OK,则应该调查警告或错误的原因。
ceph status
cluster:
id: <id>
health: HEALTH_OK
services:
mon: 3 daemons, quorum a,b,c (age 1h)
mgr: a(active, since 1h), standbys: b
osd: 4 osds: 4 up (since 1h), 4 in (since 1h)
data:
pools: 1 pools, 1 pgs
objects: 2 objects, 449 KiB
usage: 106 MiB used, 1024 GiB / 1024 GiB avail
pgs: 1 active+clean从输出可以看出集群状态一切正常,集群中部署了3个mon, 2个mgr, 4个osd。
查看一下当前集群中的存储池:
ceph osd lspools
1 .mgr
ceph osd tree
ID CLASS WEIGHT TYPE NAME STATUS REWEIGHT PRI-AFF
-1 1.00000 root default
-5 0.50000 host node85
0 hdd 0.25000 osd.0 up 1.00000 1.00000
2 hdd 0.25000 osd.2 up 1.00000 1.00000
-3 0.50000 host node86
1 hdd 0.25000 osd.1 up 1.00000 1.00000
3 hdd 0.25000 osd.3 up 1.00000 1.00000可以看到当前集群中只有一个名称为.mgr的存储池。这表示在这个Ceph集群中只创建了默认的管理池(mgr pool),这是一个特殊的池,用于存储管理和监控相关的数据。
4.使用存储
Ceph提供三种类型的存储接口: 块存储(Block)、共享文件系统(Shared Filesystem)、对象存储(Object)。
下面演示对于使用Rook部署和管理的Ceph集群,如何使用这三种存储。
通过Rook使用Ceph提供的三种存储类型以及它们的用途如下:
- 块存储(Block)适用于为单个 Pod 提供读写一致性(RWO)的存储
- CephFS 共享文件系统(Shared Filesystem)适用于多个Pod之间共享读写(RWX)的存储
- 对象存储(Object)提供了一个可通过内部或外部的Kubernetes集群的S3端点访问的存储
使用存储的详细内容这里略过,具体可查看之前编写的Rook 1.11部署指南中的"使用存储"。
5.Ceph Dashboard
通过使用Ceph Dashboard可以查看集群的状态。使用Rook部署的Ceph集群已经默认启用了Ceph Dashboard。

rook-ceph-mgr-dashboard是其在Kubernetes集群中的Service:
kubectl get svc rook-ceph-mgr-dashboard -n rook-ceph
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
rook-ceph-mgr-dashboard ClusterIP 10.102.189.193 <none> 8443/TCP 1h可通过Ingress将其暴露的Kubernetes集群外部。
Ceph Dashboard admin用户的命名可以通过下面的命令查看:
kubectl -n rook-ceph get secret rook-ceph-dashboard-password -o jsonpath="{['data']['password']}" | base64 --decode && echo