使用Rook自动部署和管理Ceph集群
2023-06-18
1.Rook介绍 #
1.1 Rook简介 #
Rook是一个开源的云原生存储编排器,为Ceph存储提供平台、框架和支持,使其能够与云原生环境进行本地集成。 Rook是云原生计算基金会(CNCF)的一个项目,从2018年成为孵化项目,并在2020年成为毕业项目。
Ceph是一个分布式存储系统,提供文件(file)、块(block)和对象存储(object storage),并在大规模生产集群中部署。
使用Rook可以自动部署和管理Ceph,提供自我管理、自我扩展和自我修复的存储服务。Rook Operator通过Kubernetes Resources来部署(deploy)、配置(configure)、供应(provision)、扩展(scale)、升级(upgrade)和监控(monitor)Ceph。
通过Rook Operator,在一个Kubernetes集群中启动Ceph就像执行几个kubectl命令一样简单。
1.2 为什么要使用Rook #
为什么要使用Rook呢?
让我们先来看一下Ceph官方提供的部署工具发展过程。Ceph官方在部署Ceph系统时提供了几个工具,其中包括ceph-deploy、ceph-ansible和cephadm:
- ceph-deploy是Ceph早期版本中推荐的部署工具和集群管理工具。它能够简化部署过程,自动配置和安装Ceph节点,并提供一些管理操作的便捷功能。当前ceph-deploy已经不再被维护,而且它还没有在比Ceph 14 (Nautilus)更新的Ceph 版本上进行测试,不支持 RHEL8、CentOS 8或更新版本的操作系统。
- ceph-ansible是一个基于Ansible的Ceph部署工具,它提供了一套Ansible playbook和roles,用于自动化配置和部署Ceph集群。ceph-ansible使用Ansible的特性,可以根据用户的需求进行高度定制化的部署,同时支持多种操作系统和Ceph版本。虽然当前ceph-ansible项目还在被维护,但在其项目首页上已经直接给了通知,推荐迁移到cephadm。
- cephadm是Ceph官方从Ceph 15(Octopus)中引入的部署工具,它是一个基于容器的管理工具,使用Ceph Orchestrator模块来管理Ceph集群。cephadm 提供了一种更简单和灵活的方式来部署和管理Ceph集群,它使用容器技术来隔离和管理Ceph组件,可以方便地进行版本升级和配置更改。
从Ceph官方部署工具的发展来看,已经从早期和中期的ceph-deploy和ceph-ansible提供的裸机二进制包部署方案发展到了cephadm的容器部署方式。也说明了使用容器来部署和管理Ceph集群的方案已经变得成熟。
Rook虽然也是通过容器来部署和管理Ceph集群,但它在构建在Kubernetes上,下面是Rook相对于cephadm的一些优势和特点:
- 简化部署和管理:Rook提供了一种基于Kubernetes的部署模型,利用Kubernetes的强大功能来简化存储集群的部署和管理。相比之下,cephadm需要在主机上安装和配置容器运行时,并使用cephadm工具来管理Ceph集群。
- 自动化和可伸缩性:Rook利用Kubernetes的自动化和可伸缩性能力,可以轻松地管理和扩展存储集群。它可以自动处理节点故障、动态扩展存储容量,并提供了灵活的存储资源调度和分配策略。
- 多存储后端支持:Rook 不仅支持Ceph 存储后端,还提供了对其他存储解决方案的支持,如EdgeFS、NFS、CockroachDB等。这使得 Rook成为一个更加多样化和灵活的存储管理工具,可以根据具体需求选择适合的存储后端。
- 基于声明性配置:Rook使用Kubernetes的声明性配置模型,通过YAML文件定义存储集群的期望状态。这种模型可以简化管理任务,确保存储集群始终处于所需的状态,并允许跟踪和回滚配置更改。
- 社区支持和生态系统:Rook拥有一个活跃的开源社区,有大量的文档、示例和社区支持可供参考。此外,Rook还与Kubernetes生态系统紧密集成。
选择使用cephadm,还是Rook取决于具体的使用场景和需求。cephadm提供了更直接的Ceph集群管理方式,而Rook在Kubernetes环境下提供了更全面的存储解决方案,并与Kubernetes紧密集成。
接下来我们将体验安装Rook这个云原生存储编排平台,为Kubernetes集群提供高可用、持久化的Ceph存储。
2.部署 #
2.1 系统需求和前置准备 #
本文档使用的Rook是v1.11.8,Ceph(Quincy) 17.2.6。
当前Rook支持Kubernetes v1.21或更高版本。
Rook发布包支持的架构包括amd64 / x86_64
和arm64
。
在部署Rook之前,要检查Kubernetes集群是否准备好使用Rook,请查看以下先决条件:
要配置Ceph存储集群,至少需要以下其中一种本地存储:
- 原始设备(Raw devices)(无分区或格式化文件系统)
- 原始分区(Raw partitions)(无格式化文件系统)
- LVM逻辑卷(无格式化文件系统)
- 以块模式(block mode)在存储类(storage class)中提供的持久卷
这里使用的Kubernetes集群如下:
1NAME STATUS ROLES AGE VERSION
2node1 Ready <none> 2d4h v1.27.3
3node2 Ready <none> 2d4h v1.27.3
4node3 Ready <none> 2d4h v1.27.3
5node4 Ready <none> 2d4h v1.27.3
6node5 Ready <none> 2d4h v1.27.3
7node6 Ready <none> 2d4h v1.27.3
假设我们要在node4, node5, node6这3个节点部署Ceph。为了控制将Ceph集群各个组件调度到哪些Kubernetes节点上,预先为相关的K8S节点打上Tag, 这里假设我们将Ceph的mon,osd,mrg等调度到node4, node5, node6上,下面给这3个节点打上role=ceph
的label,并加上dedicated=ceph:NoSchedule
的taint。
1kubectl label node node4 role=ceph
2kubectl label node node5 role=ceph
3kubectl label node node6 role=ceph
4kubectl taint nodes node4 dedicated=ceph:NoSchedule
5kubectl taint nodes node5 dedicated=ceph:NoSchedule
6kubectl taint nodes node6 dedicated=ceph:NoSchedule
当前node4~node6的磁盘和分区信息如下:
1fdisk -l
2Disk /dev/vda: 100 GiB, 107374182400 bytes, 209715200 sectors
3Units: sectors of 1 * 512 = 512 bytes
4Sector size (logical/physical): 512 bytes / 512 bytes
5I/O size (minimum/optimal): 512 bytes / 512 bytes
6Disklabel type: dos
7Disk identifier: 0x53af6437
8
9Device Boot Start End Sectors Size Id Type
10/dev/vda1 2048 4194303 4192256 2G e W95 FAT16 (LBA)
11/dev/vda2 4194304 83886079 79691776 38G 83 Linux
根据输出中的信息,磁盘 /dev/vda
的总容量为 100 GiB,其中已经使用了40 GiB(38 GiB + 2 GiB)。因此,根据这些信息,还有剩余的60GiB空间可供使用。我们这里的情况适用于前面三种类型的本地存储中的原始分区(Raw partitions)(无格式化文件系统).
分别在node4~node6三个节点上,创建新的分区/dev/vda3
1fdisk /dev/vda
2# 省略分区过程...
3
4fdisk -l
5Disk /dev/vda: 100 GiB, 107374182400 bytes, 209715200 sectors
6Units: sectors of 1 * 512 = 512 bytes
7Sector size (logical/physical): 512 bytes / 512 bytes
8I/O size (minimum/optimal): 512 bytes / 512 bytes
9Disklabel type: dos
10Disk identifier: 0x53af6437
11
12Device Boot Start End Sectors Size Id Type
13/dev/vda1 2048 4194303 4192256 2G e W95 FAT16 (LBA)
14/dev/vda2 4194304 83886079 79691776 38G 83 Linux
15/dev/vda3 83886080 209715199 125829120 60G 83 Linux
关于容器运行时的配置,这里的Kubernetes集群的容器运行时是Containerd。当前Containerd官方的systemd配置模板https://raw.githubusercontent.com/containerd/containerd/main/containerd.service中的LimitNOFILE=infinity
,如果是使用这个containerd.service,后边在使用rook启动Ceph集群时,Mon组件会有问题,会出现ms_dispatch
进程的cpu一直是100%,Rook社区有两个ISSUES ISSUE 11253和ISSUE 10110讨论了这个问题,需要将LimitNOFILE
设置一个合适的值,我这里设置的是1048576
。
2.2 部署Rook Operator #
注: 这里只有node4~node6这3个节点, Ceph集群的各个组件混部在这3个节点上,对于更多节点的生产级别配置,可以对label做更精细化的配置,例如
node-role.kubernetes.io/ceph-mon=ceph-mon
等等。
我们将通过使用Rook Helm Chart来部署rook ceph operator。
Rook目前将Ceph Operator的构建版本发布到发布(release)和主要(master)通道。发布通道是Rook的最新稳定版本。
1helm repo add rook-release https://charts.rook.io/release
2helm install --create-namespace --namespace rook-ceph rook-ceph rook-release/rook-ceph -f values.yaml
关于values.yaml中配置的内容,可以根据文档https://github.com/rook/rook/blob/master/deploy/charts/rook-ceph-cluster/values.yaml中的内容按需定制。
以下是当前我所定制的内容,主要配置了在部署Rook Operator和Ceph时使用私有的镜像仓库地址,以及调度相关的配置。
https://github.com/rook/rook/blob/master/deploy/examples/images.txt这个地址里面有部署Rook Operator和Ceph所需的所有容器镜像,可以根据需要预先同步到我们的私有镜像仓库中。
1image:
2 pullPolicy: IfNotPresent
3 repository: registry.frognew.com/library/rook/ceph
4 tag: v1.11.8
5imagePullSecrets:
6 - name: regsecret
7
8tolerations:
9 - key: "dedicated"
10 operator: "Equal"
11 value: "ceph"
12 effect: "NoSchedule"
13
14provisionerNodeAffinity:
15 requiredDuringSchedulingIgnoredDuringExecution:
16 nodeSelectorTerms:
17 - matchExpressions:
18 - key: role
19 operator: In
20 values:
21 - ceph
22provisionerTolerations:
23 - key: "dedicated"
24 operator: "Equal"
25 value: "ceph"
26 effect: "NoSchedule"
27pluginNodeAffinity:
28 requiredDuringSchedulingIgnoredDuringExecution:
29 nodeSelectorTerms:
30 - matchExpressions:
31 - key: role
32 operator: In
33 values:
34 - ceph
35pluginTolerations:
36 - key: "dedicated"
37 operator: "Equal"
38 value: "ceph"
39 effect: "NoSchedule"
40
41
42csi:
43 cephcsi:
44 # -- Ceph CSI image
45 # @default -- `quay.io/cephcsi/cephcsi:v3.8.0`
46 image: registry.frognew.com/gcr/quay.io/cephcsi/cephcsi:v3.8.0
47 registrar:
48 # -- Kubernetes CSI registrar image
49 # @default -- `registry.k8s.io/sig-storage/csi-node-driver-registrar:v2.7.0`
50 image: registry.frognew.com/gcr/registry.k8s.io/sig-storage/csi-node-driver-registrar:v2.7.0
51 provisioner:
52 # -- Kubernetes CSI provisioner image
53 # @default -- `registry.k8s.io/sig-storage/csi-provisioner:v3.4.0`
54 image: registry.frognew.com/gcr/registry.k8s.io/sig-storage/csi-provisioner:v3.4.0
55 snapshotter:
56 # -- Kubernetes CSI snapshotter image
57 # @default -- `registry.k8s.io/sig-storage/csi-snapshotter:v6.2.1`
58 image: registry.frognew.com/gcr/registry.k8s.io/sig-storage/csi-snapshotter:v6.2.1
59 attacher:
60 # -- Kubernetes CSI Attacher image
61 # @default -- `registry.k8s.io/sig-storage/csi-attacher:v4.1.0`
62 image: registry.frognew.com/gcr/registry.k8s.io/sig-storage/csi-attacher:v4.1.0
63 resizer:
64 # -- Kubernetes CSI resizer image
65 # @default -- `registry.k8s.io/sig-storage/csi-resizer:v1.7.0`
66 image: registry.frognew.com/gcr/registry.k8s.io/sig-storage/csi-resizer:v1.7.0
部署完成后,确认rook-ceph-operator的正常启动:
1kubectl get pods -n rook-ceph -l "app=rook-ceph-operator"
2NAME READY STATUS RESTARTS AGE
3rook-ceph-operator-8f4d9cd47-vk2wn 1/1 Running 0 4m9s
2.3 集群环境 #
Rook文档侧重于在各种环境中启动Rook。在创建Ceph集群时,可以考虑在以下的示例集群清单基础上做定制:
- cluster.yaml:用于在裸机上运行的生产集群的集群设置。需要至少三个工作节点。
- cluster-on-pvc.yaml:用于在动态云环境中运行的生产集群的集群设置。
- cluster-test.yaml:用于测试环境(如 minikube)的集群设置。
有关更多详细信息,请参阅Ceph的示例配置。
Rook Ceph Operator已经部署完成并正常运行,我们可以创建Ceph集群了,这里选择的是cluster.yaml
。
2.4 创建集群 #
基于cluster.yaml创建并定制我们自己的cluster.yaml,以下是只包含我对这个cluster.yaml的修改内容:
1...
2spec:
3 cephVersion:
4 image: registry.frognew.com/gcr/quay.io/ceph/ceph:v17.2.6
5...
6 dashboard:
7 enabled: true
8 ssl: false
9...
10 placement:
11 all:
12 nodeAffinity:
13 requiredDuringSchedulingIgnoredDuringExecution:
14 nodeSelectorTerms:
15 - matchExpressions:
16 - key: role
17 operator: In
18 values:
19 - ceph
20 podAffinity:
21 podAntiAffinity:
22 topologySpreadConstraints:
23 tolerations:
24 - key: "dedicated"
25 operator: "Equal"
26 value: "ceph"
27 effect: "NoSchedule"
28...
1kubectl create -f cluster.yaml
通过查看rook-ceph
命名空间中的pod,验证集群是否正在运行。
1kubectl get po -n rook-ceph
2NAME READY STATUS RESTARTS AGE
3csi-cephfsplugin-ccx2t 2/2 Running 0 70m
4csi-cephfsplugin-provisioner-5975dbc847-9fmjz 5/5 Running 0 70m
5csi-cephfsplugin-provisioner-5975dbc847-p5rsp 5/5 Running 0 70m
6csi-cephfsplugin-qsdh7 2/2 Running 0 13m
7csi-cephfsplugin-trqtz 2/2 Running 0 13m
8csi-rbdplugin-b296t 2/2 Running 0 13m
9csi-rbdplugin-provisioner-5866f96769-7mspx 5/5 Running 0 70m
10csi-rbdplugin-provisioner-5866f96769-jtjqz 5/5 Running 0 70m
11csi-rbdplugin-sqwtr 2/2 Running 0 13m
12csi-rbdplugin-vzb8h 2/2 Running 0 70m
13rook-ceph-crashcollector-node4-7d8c99bb7b-thcb8 1/1 Running 0 70m
14rook-ceph-crashcollector-node5-54f44699cf-2qd56 1/1 Running 0 14m
15rook-ceph-crashcollector-node6-79c7bfc46-g7rmc 1/1 Running 0 14m
16rook-ceph-mgr-a-6b84cf75f4-4vsw7 3/3 Running 0 71m
17rook-ceph-mgr-b-76f7ffb4f-sqglf 3/3 Running 0 70m
18rook-ceph-mon-a-7f6c678998-b9gsg 1/2 Running 0 72m
19rook-ceph-mon-b-798544c8c6-g4jml 1/2 Running 0 71m
20rook-ceph-mon-c-5f769c966c-66zmj 2/2 Running 0 71m
21rook-ceph-operator-75bc9447c6-hfqhl 1/1 Running 0 15m
22rook-ceph-osd-0-55ffc5446b-xlz68 2/2 Running 0 26m
23rook-ceph-osd-1-57688f847-pvm8l 2/2 Running 0 14m
24rook-ceph-osd-2-7dc6686bfb-jps57 2/2 Running 0 14m
25rook-ceph-osd-prepare-node4-dxg8d 0/1 Completed 0 15m
26rook-ceph-osd-prepare-node5-xnvbv 0/1 Completed 0 15m
27rook-ceph-osd-prepare-node6-5xvdz 0/1 Completed 0 14m
osd pod的数量取决于集群中的节点数量和配置的设备数量。对于上述默认的cluster.yaml,将为每个节点上找到的每个可用设备创建一个OSD。
创建过程如果遇到问题可以查看rook-ceph-operator
的Pod的日志。
如需重新运行rook-ceph-osd-prepare-<nodename>
Job,扫描可用本地存储添加OSD,可以执行以下命令:
1# 删除旧的job
2kubectl get job -n rook-ceph | awk '{system("kubectl delete job "$1" -n rook-ceph")}'
3# 重启operator
4kubectl rollout restart deploy rook-ceph-operator -n rook-ceph
每个节点上的osd能否添加成功,要注意查看rook-ceph-osd-prepare-<nodename>
Job对应Pod的日志。
2.5 验证集群状态 #
为了验证集群处于健康状态, 需要Rook工具箱。
1kubectl apply -f https://raw.githubusercontent.com/rook/rook/release-1.11/deploy/examples/toolbox.yaml
2
3kubectl get po -n rook-ceph | grep rook-ceph-tools
4rook-ceph-tools-68b98695bb-gh76t 1/1 Running 0 23s
连接到工具箱,并运行ceph status
命令:
1kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- bash
以下是健康状态的验证要点:
- 所有的 monitor (mon) 节点应该处于 quorum(一致性)状态。
- 一个管理器 (mgr) 节点应该处于活动状态。
- 至少有三个 OSD 节点应该处于上线并可用状态。
如果健康状态不是 HEALTH_OK
,则应该调查警告或错误的原因。
1ceph status
2 cluster:
3 id: 919b1901-4943-4a88-88cc-d7bbb134a5f1
4 health: HEALTH_OK
5
6 services:
7 mon: 3 daemons, quorum a,b,c (age 116s)
8 mgr: a(active, since 41s), standbys: b
9 osd: 3 osds: 3 up (since 2m), 3 in (since 5m)
10
11 data:
12 pools: 1 pools, 1 pgs
13 objects: 2 objects, 449 KiB
14 usage: 62 MiB used, 180 GiB / 180 GiB avail
15 pgs: 1 active+clean
从输出可以看出集群状态一切正常,集群中部署了3个mon, 2个mgr, 3个osd。
查看一下当前集群中的存储池:
1ceph osd lspools
21 .mgr
可以看到当前集群中只有一个名称为.mgr
的存储池。这表示在这个Ceph集群中只创建了默认的管理池(mgr pool),这是一个特殊的池,用于存储管理和监控相关的数据。
3.使用存储 #
Ceph提供三种类型的存储接口: 块存储(Block)、共享文件系统(Shared Filesystem)、对象存储(Object)。
下面演示对于使用Rook部署和管理的Ceph集群,如何使用这三种存储。
通过Rook使用Ceph提供的三种存储类型以及它们的用途如下:
- 块存储(Block)适用于为单个 Pod 提供读写一致性(RWO)的存储
- CephFS 共享文件系统(Shared Filesystem)适用于多个Pod之间共享读写(RWX)的存储
- 对象存储(Object)提供了一个可通过内部或外部的Kubernetes集群的S3端点访问的存储
3.1 块存储(Block) #
块存储允许单个Pod挂载存储。本指南介绍了如何使用Rook启用的持久卷,在Kubernetes上创建一个简单的多层Web应用程序。
3.1.1 RBD存储供给 #
在Rook可以提供存储之前,需要创建StorageClass和CephBlockPool CR。这将使Kubernetes在提供持久卷时与Rook进行交互操作。
这个示例需要每个节点至少有1个 OSD,并且每个 OSD 需要位于3个不同的节点上。每个OSD必须位于不同的节点上,因为
failureDomain
被设置为host
,并且replicated.size
被设置为 3。
创建下面的storageclass.yaml
文件:
1apiVersion: ceph.rook.io/v1
2kind: CephBlockPool
3metadata:
4 name: replicapool
5 namespace: rook-ceph
6spec:
7 failureDomain: host
8 replicated:
9 size: 3
10---
11apiVersion: storage.k8s.io/v1
12kind: StorageClass
13metadata:
14 name: rook-ceph-block
15# Change "rook-ceph" provisioner prefix to match the operator namespace if needed
16provisioner: rook-ceph.rbd.csi.ceph.com
17parameters:
18 # clusterID is the namespace where the rook cluster is running
19 clusterID: rook-ceph
20 # Ceph pool into which the RBD image shall be created
21 pool: replicapool
22
23 # (optional) mapOptions is a comma-separated list of map options.
24 # For krbd options refer
25 # https://docs.ceph.com/docs/master/man/8/rbd/#kernel-rbd-krbd-options
26 # For nbd options refer
27 # https://docs.ceph.com/docs/master/man/8/rbd-nbd/#options
28 # mapOptions: lock_on_read,queue_depth=1024
29
30 # (optional) unmapOptions is a comma-separated list of unmap options.
31 # For krbd options refer
32 # https://docs.ceph.com/docs/master/man/8/rbd/#kernel-rbd-krbd-options
33 # For nbd options refer
34 # https://docs.ceph.com/docs/master/man/8/rbd-nbd/#options
35 # unmapOptions: force
36
37 # RBD image format. Defaults to "2".
38 imageFormat: "2"
39
40 # RBD image features
41 # Available for imageFormat: "2". Older releases of CSI RBD
42 # support only the `layering` feature. The Linux kernel (KRBD) supports the
43 # full complement of features as of 5.4
44 # `layering` alone corresponds to Ceph's bitfield value of "2" ;
45 # `layering` + `fast-diff` + `object-map` + `deep-flatten` + `exclusive-lock` together
46 # correspond to Ceph's OR'd bitfield value of "63". Here we use
47 # a symbolic, comma-separated format:
48 # For 5.4 or later kernels:
49 #imageFeatures: layering,fast-diff,object-map,deep-flatten,exclusive-lock
50 # For 5.3 or earlier kernels:
51 imageFeatures: layering
52
53 # The secrets contain Ceph admin credentials.
54 csi.storage.k8s.io/provisioner-secret-name: rook-csi-rbd-provisioner
55 csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph
56 csi.storage.k8s.io/controller-expand-secret-name: rook-csi-rbd-provisioner
57 csi.storage.k8s.io/controller-expand-secret-namespace: rook-ceph
58 csi.storage.k8s.io/node-stage-secret-name: rook-csi-rbd-node
59 csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph
60
61 # Specify the filesystem type of the volume. If not specified, csi-provisioner
62 # will set default as `ext4`. Note that `xfs` is not recommended due to potential deadlock
63 # in hyperconverged settings where the volume is mounted on the same node as the osds.
64 csi.storage.k8s.io/fstype: ext4
65
66# Delete the rbd volume when a PVC is deleted
67reclaimPolicy: Delete
68
69# Optional, if you want to add dynamic resize for PVC.
70# For now only ext3, ext4, xfs resize support provided, like in Kubernetes itself.
71allowVolumeExpansion: true
这个storageclass.yaml文件中包含了StorageClass rook-ceph-block
和CephBlockPool replicapool
的定义。
如果你在一个名为"rook-ceph"以外的命名空间中部署了Rook Operator,请将该文件中的provisioner
中的前缀更改为与你使用的命名空间匹配。例如,如果Rook Operator在命名空间"my-namespace"中运行,则provisioner的值应为my-namespace.rbd.csi.ceph.com
。
接下来创建这个StorageClass和CephBlockPool:
1kubectl create -f storageclass.yaml
2cephblockpool.ceph.rook.io/replicapool created
3storageclass.storage.k8s.io/rook-ceph-block created
根据Kubernetes的规定,在使用"Retain"回收策略时,任何由PersistentVolume支持的Ceph RBD 镜像将在PersistentVolume被删除后继续存在。这些Ceph RBD镜像需要使用
rbd rm
命令手动清理。
上面在创建名称为replicapool
的CephBlockPool资源时,会自动在Ceph集群中创建名称为replicapool
的存储池。这个操作是由Ceph Operator完成的,如果查看发现没有创建这个存储池,可以通过查看Ceph Operator的日志进行问题定位。
1ceph osd lspools
21 .mgr
32 replicapool
上面命令的输出说明已经创建了存储池replicapool
。
3.1.2 使用存储: WordPress示例 #
我们创建了一个示例应用程序,使用经由Rook提供的块存储,其中包括经由Rook提供的的WordPress和MySQL应用程序。这些应用程序都将使用Rook提供的块存储卷(block volumes)。
从rook源码的deploy/examples
文件夹启动MySQL和WordPress,因为这里部署的Ceph集群总容量只有180GB, 所以这里将mysql.yaml
和wordpress.yaml
中PVC中配置的容量都调整为5Gi后再执行下面的命令:
1kubectl create -f mysql.yaml
2kubectl create -f wordpress.yaml
这两个应用程序都会创建一个块存储卷并将其挂载到各自的Pod上。通过运行以下命令来查看Kubernetes的PVC(卷声明):
1kubectl get pvc
2NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
3mysql-pv-claim Bound pvc-ae507859-6367-447b-b8e0-cf9316780938 5Gi RWO rook-ceph-block 7s
4wp-pv-claim Bound pvc-32801000-6399-4422-bf49-11d22d0481da 5Gi RWO rook-ceph-block 5s
查看一下创建的持久卷:
1kubectl get pv
2NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
3pvc-32801000-6399-4422-bf49-11d22d0481da 5Gi RWO Delete Bound default/wp-pv-claim rook-ceph-block 7m53s
4pvc-ae507859-6367-447b-b8e0-cf9316780938 5Gi RWO Delete Bound default/mysql-pv-claim rook-ceph-block 7m54s
查看其中一个持久化卷的具体信息:
1kubectl describe pv pvc-32801000-6399-4422-bf49-11d22d0481da
2Name: pvc-32801000-6399-4422-bf49-11d22d0481da
3Labels: <none>
4Annotations: pv.kubernetes.io/provisioned-by: rook-ceph.rbd.csi.ceph.com
5 volume.kubernetes.io/provisioner-deletion-secret-name: rook-csi-rbd-provisioner
6 volume.kubernetes.io/provisioner-deletion-secret-namespace: rook-ceph
7Finalizers: [kubernetes.io/pv-protection]
8StorageClass: rook-ceph-block
9Status: Bound
10Claim: default/wp-pv-claim
11Reclaim Policy: Delete
12Access Modes: RWO
13VolumeMode: Filesystem
14Capacity: 5Gi
15Node Affinity: <none>
16Message:
17Source:
18 Type: CSI (a Container Storage Interface (CSI) volume source)
19 Driver: rook-ceph.rbd.csi.ceph.com
20 FSType: ext4
21 VolumeHandle: 0001-0009-rook-ceph-0000000000000002-f9915a86-312c-469a-835c-f03484c444dc
22 ReadOnly: false
23 VolumeAttributes: clusterID=rook-ceph
24 imageFeatures=layering
25 imageFormat=2
26 imageName=csi-vol-f9915a86-312c-469a-835c-f03484c444dc
27 journalPool=replicapool
28 pool=replicapool
29 storage.kubernetes.io/csiProvisionerIdentity=1687233028841-8081-rook-ceph.rbd.csi.ceph.com
30Events: <none>
查看一下存储池replicapool中的rbd镜像:
1rbd ls -p replicapool
2csi-vol-23a9cc04-abf1-4a64-a022-ba613c978b11
3csi-vol-f9915a86-312c-469a-835c-f03484c444dc
3.2 CephFS共享文件系统 #
CephFS文件系统存储(也称为共享文件系统)可以从多个Pod中以读/写权限挂载。这对于可以使用共享文件系统进行集群化的应用程序可能非常有用。
Ceph从自Pacific版本(Ceph 16)开始,支持多个文件系统。
3.2.1 创建CephFilesystem #
通过在CephFilesystem
CRD中指定元数据池(metadata pool)、数据池(data pools)和元数据服务(metadata server)的所需设置来创建文件系统。在这里,我们创建的是3个副本的元数据池和3个副本的单个数据池。有关更多选项,请参阅创建共享文件系统的文档。
创建下面的filesystem.yaml文件:
1apiVersion: ceph.rook.io/v1
2kind: CephFilesystem
3metadata:
4 name: myfs
5 namespace: rook-ceph
6spec:
7 metadataPool:
8 replicated:
9 size: 3
10 dataPools:
11 - name: replicated
12 replicated:
13 size: 3
14 preserveFilesystemOnDelete: true
15 metadataServer:
16 activeCount: 1
17 activeStandby: true
Rook Ceph Operator将创建启动服务所需的所有池和其他资源。这可能需要一些时间来完成。
1kubectl create -f filesystem.yaml
要确认文件系统已配置完成,请等待mds Pod 启动:
1kubectl -n rook-ceph get pod -l app=rook-ceph-mds
2NAME READY STATUS RESTARTS AGE
3rook-ceph-mds-myfs-a-b8c7dc4dd-72spj 2/2 Running 0 9m27s
4rook-ceph-mds-myfs-b-6f487b5c7c-m9sf2 2/2 Running 0 9m23s
要查看文件系统的详细状态,进入Rook toolbox中,使用ceph status
查看, 确认输出中包含MDS服务的状态。在这个示例中,有一个处于活动状态的MDS实例,并且还有一个处于备用MDS实例,以防发生故障切换。
1ceph -s
2 cluster:
3 id: 919b1901-4943-4a88-88cc-d7bbb134a5f1
4 health: HEALTH_OK
5 services:
6 ...
7 mds: 1/1 daemons up, 1 hot standby
8 ...
使用ceph osd lspools
查看,确认创建了myfs-metadata
和myfs-replicated
的存储池。
1ceph osd lspools
21 .mgr
32 replicapool
43 myfs-metadata
54 myfs-replicated
3.2.2 CephFS存储供给 #
在Rook开始提供CephFS存储之前,需要基于文件系统创建一个StorageClass。这对于Kubernetes与CSI驱动程序进行交互以创建持久卷是必需的。
将以下存储类定义保存为storageclass.yaml文件:
1apiVersion: storage.k8s.io/v1
2kind: StorageClass
3metadata:
4 name: rook-cephfs
5# Change "rook-ceph" provisioner prefix to match the operator namespace if needed
6provisioner: rook-ceph.cephfs.csi.ceph.com
7parameters:
8 # clusterID is the namespace where the rook cluster is running
9 # If you change this namespace, also change the namespace below where the secret namespaces are defined
10 clusterID: rook-ceph
11
12 # CephFS filesystem name into which the volume shall be created
13 fsName: myfs
14
15 # Ceph pool into which the volume shall be created
16 # Required for provisionVolume: "true"
17 pool: myfs-replicated
18
19 # The secrets contain Ceph admin credentials. These are generated automatically by the operator
20 # in the same namespace as the cluster.
21 csi.storage.k8s.io/provisioner-secret-name: rook-csi-cephfs-provisioner
22 csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph
23 csi.storage.k8s.io/controller-expand-secret-name: rook-csi-cephfs-provisioner
24 csi.storage.k8s.io/controller-expand-secret-namespace: rook-ceph
25 csi.storage.k8s.io/node-stage-secret-name: rook-csi-cephfs-node
26 csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph
27
28reclaimPolicy: Delete
如果你将Rook Operator部署在了一个与"rook-ceph"不同的命名空间中,请修改provisioner中的前缀以匹配你使用的命名空间。例如,如果Rook Operator运行在"rook-op"命名空间中,那么provisioner的值应该是rook-op.rbd.csi.ceph.com
。
创建存储类:
1kubectl create -f storageclass.yaml
3.2.3 关于配额 #
CephFS CSI驱动程序使用配额来强制执行所请求的PVC大小。只有较新的Linux内核支持CephFS配额,至少是4.17版本的内核。
3.2.4 使用存储: 多个Pod挂载 #
创建下面的busybox.yaml:
1apiVersion: v1
2kind: PersistentVolumeClaim
3metadata:
4 name: busybox-data-pvc
5spec:
6 accessModes:
7 - ReadWriteMany
8 resources:
9 requests:
10 storage: 2Gi
11 storageClassName: rook-cephfs
12
13---
14apiVersion: apps/v1
15kind: Deployment
16metadata:
17 name: busybox
18spec:
19 replicas: 2
20 selector:
21 matchLabels:
22 app: busybox
23 template:
24 metadata:
25 labels:
26 app: busybox
27 spec:
28 containers:
29 - name: busybox-container
30 image: busybox:stable-glibc
31 command: ["sleep", "3600"]
32 volumeMounts:
33 - name: data-volume
34 mountPath: /data
35 volumes:
36 - name: data-volume
37 persistentVolumeClaim:
38 claimName: busybox-data-pvc
创建这个busybox的deployment和pvc:
1kubectl apply -f busybox.yaml
2persistentvolumeclaim/busybox-data-pvc created
3deployment.apps/busybox created
查看创建的PVC和自动供给的PV:
1kubectl get pvc
2NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
3busybox-data-pvc Bound pvc-d212bea0-6c7f-45e6-979c-20108ba67b9e 2Gi RWX rook-cephfs 77s
4
5kubectl get pv
6NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
7pvc-d212bea0-6c7f-45e6-979c-20108ba67b9e 2Gi RWX Delete Bound default/busybox-data-pvc rook-cephfs 96s
查看PV的的具体信息:
1kubectl describe pv pvc-d212bea0-6c7f-45e6-979c-20108ba67b9e
2
3Name: pvc-d212bea0-6c7f-45e6-979c-20108ba67b9e
4Labels: <none>
5Annotations: pv.kubernetes.io/provisioned-by: rook-ceph.cephfs.csi.ceph.com
6 volume.kubernetes.io/provisioner-deletion-secret-name: rook-csi-cephfs-provisioner
7 volume.kubernetes.io/provisioner-deletion-secret-namespace: rook-ceph
8Finalizers: [kubernetes.io/pv-protection]
9StorageClass: rook-cephfs
10Status: Bound
11Claim: default/busybox-data-pvc
12Reclaim Policy: Delete
13Access Modes: RWX
14VolumeMode: Filesystem
15Capacity: 2Gi
16Node Affinity: <none>
17Message:
18Source:
19 Type: CSI (a Container Storage Interface (CSI) volume source)
20 Driver: rook-ceph.cephfs.csi.ceph.com
21 FSType:
22 VolumeHandle: 0001-0009-rook-ceph-0000000000000001-7ab26692-0138-4894-b7e1-17ec1a109466
23 ReadOnly: false
24 VolumeAttributes: clusterID=rook-ceph
25 fsName=myfs
26 pool=myfs-replicated
27 storage.kubernetes.io/csiProvisionerIdentity=1687233030423-8081-rook-ceph.cephfs.csi.ceph.com
28 subvolumeName=csi-vol-7ab26692-0138-4894-b7e1-17ec1a109466
29 subvolumePath=/volumes/csi/csi-vol-7ab26692-0138-4894-b7e1-17ec1a109466/74db7b35-9936-4cf9-b223-4c1f669c2009
30Events: <none>
可以看到持久化卷挂载是CephFS实例myfs中的/volumes/csi/csi-vol-7ab26692-0138-4894-b7e1-17ec1a109466/74db7b35-9936-4cf9-b223-4c1f669c2009
。
3.3 对象存储 #
对象存储为应用程序提供了一个使用S3 API存储和获取数据的接口。
3.3.1 配置一个Object Store #
Rook具有在Kubernetes中部署对象存储或连接到外部RGW服务的能力。通常情况下,对象存储将由Rook在本地进行配置。或者,如果你有一个现有的带有Rados Gateways的Ceph集群,请参阅external section文档以从Rook中使用它。
创建本地的Object Store
以下示例将创建一个CephObjectStore,该对象存储在集群中启动RGW服务,并提供S3 API。
注意: 这个示例至少需要3个bluestore OSD,每个OSD位于不同的节点上。OSDs必须位于不同的节点上,因为
failureDomain
设置为host,并且erasureCoded
块设置要求至少有3个不同的OSD(2个dataChunks
+ 1个codingChunks
)。
请参阅对象存储CRD文档,以获取有关CephObjectStore可用设置的更多详细信息。
创建如下的object.yaml:
1apiVersion: ceph.rook.io/v1
2kind: CephObjectStore
3metadata:
4 name: my-store
5 namespace: rook-ceph
6spec:
7 metadataPool:
8 failureDomain: host
9 replicated:
10 size: 3
11 dataPool:
12 failureDomain: host
13 erasureCoded:
14 dataChunks: 2
15 codingChunks: 1
16 preservePoolsOnDelete: true
17 gateway:
18 sslCertificateRef:
19 port: 80
20 # securePort: 443
21 instances: 1
创建这个CephObjectStore:
1kubectl create -f object.yaml
2cephobjectstore.ceph.rook.io/my-store created
创建CephObjectStore后,Rook Ceph Operator将创建所有必要的池和其他资源以启动服务。这可能需要几分钟来完成。
Rook Ceph Operator会在Ceph集群中创建名称为my-store.rgw.*
的多个存储池。
1ceph osd lspools
21 .mgr
32 replicapool
43 myfs-metadata
54 myfs-replicated
65 my-store.rgw.control
76 my-store.rgw.meta
87 my-store.rgw.log
98 my-store.rgw.buckets.index
109 my-store.rgw.buckets.non-ec
1110 my-store.rgw.otp
要确认对象存储已配置完成,请等待RGW pod启动:
1kubectl -n rook-ceph get pod -l app=rook-ceph-rgw
2NAME READY STATUS RESTARTS AGE
3rook-ceph-rgw-my-store-a-547dc8d7cb-lkbsd 2/2 Running 0 2m17s
最后再查看一下ceph集群的状态:
1ceph -s
2 cluster:
3 id: 919b1901-4943-4a88-88cc-d7bbb134a5f1
4 health: HEALTH_OK
5
6 services:
7 mon: 3 daemons, quorum a,b,c (age 3h)
8 mgr: a(active, since 3h), standbys: b
9 mds: 1/1 daemons up, 1 hot standby
10 osd: 3 osds: 3 up (since 3h), 3 in (since 3h)
11 rgw: 1 daemon active (1 hosts, 1 zones)
12
13 data:
14 volumes: 1/1 healthy
15 pools: 12 pools, 178 pgs
16 objects: 242 objects, 506 KiB
17 usage: 123 MiB used, 180 GiB / 180 GiB avail
18 pgs: 178 active+clean
19
20 io:
21 client: 639 B/s rd, 1 op/s rd, 0 op/s wr
22
23 progress:
3.3.2 创建一个Bucket #
现在对象存储已经配置好了,接下来我们需要创建一个存储桶,以便客户端可以读取和写入对象。可以通过定义存储类来创建存储桶,类似于块和文件存储的模式。首先,定义一个存储类,允许对象客户端创建存储桶。存储类定义了对象存储系统、存储桶保留策略和其他管理员所需的属性。将以下内容保存为storageclass-bucket-delete.yaml
(由于采用了DELETE的回收策略,示例被命名为 storageclass-bucket-delete.yaml)。
1apiVersion: storage.k8s.io/v1
2kind: StorageClass
3metadata:
4 name: rook-ceph-bucket
5# Change "rook-ceph" provisioner prefix to match the operator namespace if needed
6provisioner: rook-ceph.ceph.rook.io/bucket
7reclaimPolicy: Delete
8parameters:
9 objectStoreName: my-store
10 objectStoreNamespace: rook-ceph
如果Rook Operator部署在rook-ceph
之外的命名空间中,需要更改provisioner中的前缀以匹配使用的命名空间。例如,如果Rook Operator在my-namespace
命名空间中运行,则provisioner的值应为my-namespace.ceph.rook.io/bucket
。
1kubectl create -f storageclass-bucket-delete.yaml
2storageclass.storage.k8s.io/rook-ceph-bucket created
根据这个存储类,现在可以通过创建对象存储桶声明Object Bucket Claim(OBC)来请求一个存储桶。当创建OBC时,Rook bucket provisioner将创建一个新的存储桶。请注意,OBC引用了上面创建的存储类。将以下内容保存为object-bucket-claim-delete.yaml
(示例命名为 delete,因为使用了Delete的回收策略):
1apiVersion: objectbucket.io/v1alpha1
2kind: ObjectBucketClaim
3metadata:
4 name: ceph-bucket
5spec:
6 generateBucketName: ceph-bkt
7 storageClassName: rook-ceph-bucket
创建这个OBC:
1kubectl create -f object-bucket-claim-delete.yaml
OBC创建成功后,Rook Ceph Operator将创建存储桶,并生成其他文件以实现对存储桶的访问。将以与OBC相同的名称和在相同的命名空间中创建一个密钥和ConfigMap。密钥包含应用程序Pod用于访问存储桶的凭据。ConfigMap包含存储桶端点信息,也会被Pod使用。有关CephObjectBucketClaims的更多详细信息,请参阅对象存储桶声明文档。
1kubectl get cm
2NAME DATA AGE
3ceph-bucket 5 105s
4
5 kubectl get cm ceph-bucket -o yaml
6apiVersion: v1
7data:
8 BUCKET_HOST: rook-ceph-rgw-my-store.rook-ceph.svc
9 BUCKET_NAME: ceph-bkt-2752d0dc-7eee-4f6e-b133-b1b4acfa7109
10 BUCKET_PORT: "80"
11 BUCKET_REGION: ""
12 BUCKET_SUBREGION: ""
13kind: ConfigMap
14metadata:
15 name: ceph-bucket
16 namespace: default
17
18kubectl get secret
19NAME TYPE DATA AGE
20ceph-bucket Opaque 2 118s
21
22kubectl get secret ceph-bucket -o yaml
23apiVersion: v1
24data:
25 AWS_ACCESS_KEY_ID: OTc3NFo2QzBaVEFVM0xYTUQ0OFU=
26 AWS_SECRET_ACCESS_KEY: RVRlTDVORGE2RHRKdUxMYnh0YUlGUFBCbG5EclZodGhtbDZDVUhVNg==
27kind: Secret
28metadata:
29 name: ceph-bucket
30 namespace: default
31type: Opaque
3.3.3 客户端连接 #
以下命令从Secret和ConfigMap中提取关键信息:
1#config-map, secret, OBC will part of default if no specific name space mentioned
2export AWS_HOST=$(kubectl -n default get cm ceph-bucket -o jsonpath='{.data.BUCKET_HOST}')
3export PORT=$(kubectl -n default get cm ceph-bucket -o jsonpath='{.data.BUCKET_PORT}')
4export BUCKET_NAME=$(kubectl -n default get cm ceph-bucket -o jsonpath='{.data.BUCKET_NAME}')
5export AWS_ACCESS_KEY_ID=$(kubectl -n default get secret ceph-bucket -o jsonpath='{.data.AWS_ACCESS_KEY_ID}' | base64 --decode)
6export AWS_SECRET_ACCESS_KEY=$(kubectl -n default get secret ceph-bucket -o jsonpath='{.data.AWS_SECRET_ACCESS_KEY}' | base64 --decode)
7
8echo $AWS_HOST
9echo $PORT
10echo $BUCKET_NAME
11echo $AWS_ACCESS_KEY_ID
12echo $AWS_SECRET_ACCESS_KEY
3.3.4 使用s5cmd工具访问对象存储 #
Rook的文档中提到了在工具箱(toolbox)Pod中使用s5cmd工具测试CephObjectStore,但当前的toolbox中并不包含s5cmd,s5cmd不可用,在github上已经有一个ISSUE 12227提出了这个问题。
因为这里的k8s集群使用的calico网络,可以直接在Node节点上使用svc ip,这里简单起见直接在K8S集群的控制节点上安装s5cmd命令行工具。
接下来配置s5cmd工具访问对象存储凭据:
1export AWS_ACCESS_KEY_ID=$(kubectl -n default get secret ceph-bucket -o jsonpath='{.data.AWS_ACCESS_KEY_ID}' | base64 --decode)
2export AWS_SECRET_ACCESS_KEY=$(kubectl -n default get secret ceph-bucket -o jsonpath='{.data.AWS_SECRET_ACCESS_KEY}' | base64 --decode)
3
4mkdir ~/.aws
5cat > ~/.aws/credentials << EOF
6[default]
7aws_access_key_id = ${AWS_ACCESS_KEY_ID}
8aws_secret_access_key = ${AWS_SECRET_ACCESS_KEY}
9EOF
查看rook-ceph-rgw-my-store这个Service的IP:
1k get svc rook-ceph-rgw-my-store -n rook-ceph
2NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
3rook-ceph-rgw-my-store ClusterIP 10.98.136.218 <none> 80/TCP 54m
使用s5cmd访问存储桶,列出当前凭据可以访问的所有桶:
1s5cmd --endpoint-url http://10.98.136.218 ls
2s3://ceph-bkt-2752d0dc-7eee-4f6e-b133-b1b4acfa7109
上传下载文件:
1echo "Hello Rook" > /tmp/rookObj
2s5cmd --endpoint-url http://10.98.136.218 cp /tmp/rookObj s3://ceph-bkt-2752d0dc-7eee-4f6e-b133-b1b4acfa7109
3
4s5cmd --endpoint-url http://10.98.136.218 cp s3://ceph-bkt-2752d0dc-7eee-4f6e-b133-b1b4acfa7109/rookObj /tmp/rookObj-download
5cat /tmp/rookObj-download
注这里使用Service IP 访问rook-ceph-rgw-my-store只是为了测试。生产环境中如果从K8S集群内访问的话,使用Service的DNS名称,如果从集群外部访问推荐使用Ingress将其暴露到集群外部。
4.Ceph Dashboard #
通过使用Ceph Dashboard可以查看集群的状态。使用Rook部署的Ceph集群已经默认启用了Ceph Dashboard。
rook-ceph-mgr-dashboard是其在Kubernetes集群中的Service:
1kubectl get svc rook-ceph-mgr-dashboard -n rook-ceph
2NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
3rook-ceph-mgr-dashboard ClusterIP 10.96.238.32 <none> 7000/TCP 8h
可通过Ingress或创建一个NodePort的Service dashboard-external-http将其暴露的Kubernetes集群外部。
Ceph Dashboard admin用户的命名可以通过下面的命令查看:
1kubectl -n rook-ceph get secret rook-ceph-dashboard-password -o jsonpath="{['data']['password']}" | base64 --decode && echo
参考 #
- https://rook.io/docs/rook/v1.11/Getting-Started/intro/
- https://rook.io/docs/rook/v1.11/Getting-Started/quickstart
- https://rook.io/docs/rook/v1.11/Helm-Charts/operator-chart/
- https://rook.io/docs/rook/v1.11/Getting-Started/Prerequisites/authenticated-registry/
- https://docs.ceph.com/en/latest/ceph-volume/
- https://rook.io/docs/rook/v1.11/Storage-Configuration/Block-Storage-RBD/block-storage/
- https://rook.io/docs/rook/v1.11/CRDs/Block-Storage/ceph-block-pool-crd/
- https://rook.io/docs/rook/v1.11/Storage-Configuration/Shared-Filesystem-CephFS/filesystem-storage/
- https://rook.io/docs/rook/v1.11/CRDs/Shared-Filesystem/ceph-filesystem-crd/
- https://rook.io/docs/rook/v1.11/Storage-Configuration/Object-Storage-RGW/object-storage/