在验证了ROOK Ceph的块存储后,撰写了此备忘录
ROOK是Kubernetes的存儲協調器。它負責分散存儲的系統管理、自動伸縮和自動修復。通過使用運營商,可以詳細了解它自動化存儲管理者的任務,包括部署、引導、配置、供應、伸縮、升級、遷移、災難恢復、監視和資源管理。
(Note: The provided translation is in Simplified Chinese)
ROOK 是一個提供多個儲存供應商的儲存編排器,並提供橫跨共同框架。它可以選擇所需的儲存供應商並在 Kubernetes 上以相同方式操作。儲存供應商有以下種類。
-
- Ceph
-
- EdgeFS
-
- CockroachDB
-
- Cassandra
-
- NFS
- Yugabyte DB
这个ROOK在本地环境中最有效的利用方式被认为是在Kubernetes集群中。也就是说,在云上的Kubernetes服务中,通过Kubernetes上的Persistent Volume Claim(PVC)的API,与云存储服务配合,为Pod提供持久卷。因此,在云环境中无需体验ROOK的便利性。然而,在本地环境中,由于可以在Kubernetes集群环境中构建存储服务,因此可以以低成本、短时间实现与云环境类似的存储服务使用。
这篇文章是关于在Vagrant上使用Kubernetes 1.17.2对ROOK Ceph的块存储进行验证的记录。ROOK Ceph是一种可与Kubernetes控制器协同工作并能够进行动态供应的软件定义存储系统(SDS)。过去,在部署Kubernetes集群时,通常会依赖外部存储设备,但通过使用ROOK Ceph,可以利用工作节点的本地磁盘来创建存储集群。这样做可以降低硬件基础设施成本。此外,预计通过运维自动化,操作员可以像使用云存储服务一样使用它。
然而,并不仅仅有好的一面。相反地,有一些挑战,比如被Kubernetes版本升级所影响等,因此在引入时需要采取谨慎的态度。
准备ROOK执行环境
我们将对我们之前使用的学习用Kubernetes进行以下改造,以使ROOK可以运行。由于它需要大量资源,所以在一般PC的规格下运行变得困难了。
Vagrantfileの編集
メモリとCPUの追加
ストレージサイズの変更
node2をコピーしてnode3を作成 マスターx1,ワーカーx3 へ
ansible-playbook の hostsファイルの編集
hosts へ node3 を追加、証明書パスの変更
nodesの変数範囲の追加
KubernetesノードのOSをUbuntu18.04へ変更
启动虚拟服务器
为了启动多个节点并添加虚拟机的内部磁盘,需先安装以下Vagrant插件。
vagrant plugin install vagrant-cachier
vagrant plugin install vagrant-disksize
在Vagrant上克隆启动Kubernetes的代码。在1.17-3node分支上,添加了一个增加了内存和核心数量的版本,采用了3节点结构。
git clone -b 1.17-3node https://github.com/takara9/vagrant-kubernetes k8s
cd k8s
用以下的命令启动虚拟服务器。
vagrant up
确认启动
export KUBECONFIG=`pwd`/kubeconfig/config
kubectl get node
NAME STATUS ROLES AGE VERSION
master Ready master 2m5s v1.17.2
node1 Ready <none> 92s v1.17.2
node2 Ready <none> 93s v1.17.2
node3 Ready <none> 93s v1.17.2
创建外部访问节点
实际上是不正确的,但可以将主节点变成NodePort中继节点以便从外部访问。
通过将主节点分配给主机侧的LAN IP地址和NodePort端口号,可以从K8s集群外部访问。
停止主节点,设定IP地址,然后重新启动。
vagrant halt master
编辑Vagrantfile文件,在计算机连接的局域网侧设置IP地址。
vi Vagrantfile
由于第154行被注释掉了,所以请去掉“#”使其成为有效的行。
153 machine.vm.network :private_network,ip: "172.16.20.11"
154 machine.vm.network :public_network, ip: "192.168.1.91", bridge: "en0: Ethernet"
再次启动主节点。在启动过程中可能会要求选择接口,因此在这里选择有线局域网接口。
vagrant up master
Bringing machine 'master' up with 'virtualbox' provider...
==> master: Checking if box 'ubuntu/xenial64' version '20200121.0.0' is up to date...
==> master: Clearing any previously set forwarded ports...
==> master: Fixed port collision for 22 => 2222. Now on port 2202.
==> master: Clearing any previously set network interfaces...
==> master: Specific bridge 'en0: Ethernet' not found. You may be asked to specify
==> master: which network to bridge to.
==> master: Available bridged network interfaces:
1) enp4s0
2) wlp3s0
3) docker0
==> master: When choosing an interface, it is usually the one that is
==> master: being used to connect to the internet.
master: Which interface should the network bridge to? 1
==> master: Preparing network interfaces based on configuration...
master: Adapter 1: nat
master: Adapter 2: hostonly
Rook Ceph 的部署
按照参考URL(https://rook.io/docs/rook/v1.2/ceph-quickstart.html)的指南,安装ROOK和Ceph,从而能够使用块、文件和对象这三种类型的存储。
git clone --single-branch --branch release-1.2 https://github.com/rook/rook.git
cd rook/cluster/examples/kubernetes/ceph
kubectl create -f common.yaml
kubectl create -f operator.yaml
在上述中,直到ROOK的Ceph操作员启动为止。作为启动确认,只需以下四个Pod启动完成即可。
kubectl get po -n rook-ceph
NAME READY STATUS RESTARTS AGE
rook-ceph-operator-6d74795f75-lhf65 1/1 Running 0 5m37s
rook-discover-949bg 1/1 Running 0 4m42s
rook-discover-m5sz7 1/1 Running 0 4m42s
rook-discover-zrdhd 1/1 Running 0 4m42s
在这种情况下,如果使用工作节点的操作系统存储,会因为受到Ceph的压力导致容器的文件系统空间不足,从而影响工作节点的正常运行。因此,需要向工作节点添加虚拟磁盘,并从Ceph中使用它。
以下是使用Ceph的CRD启动Ceph的清单文件。在其中,要将Ceph数据挂载到工作节点的路径/var/lib/rook,可以通过dataDirHostPath: /var/lib/rook进行配置。下面的cluster.yaml是经过编辑并除去注释的,以便清晰明了地表达要点。
apiVersion: ceph.rook.io/v1
kind: CephCluster
metadata:
name: rook-ceph
namespace: rook-ceph
spec:
cephVersion:
image: ceph/ceph:v14.2.6
allowUnsupported: false
dataDirHostPath: /var/lib/rook # <--- データディレクトリ
skipUpgradeChecks: false
continueUpgradeAfterChecksEvenIfNotHealthy: false
mon:
count: 3
allowMultiplePerNode: false # モニターはノードに一つ
dashboard:
enabled: true
ssl: true
monitoring:
enabled: false
rulesNamespace: rook-ceph
network:
hostNetwork: false # ポッドネットワークを使用、パフォーマンスを求める時は再考
rbdMirroring:
workers: 0
crashCollector:
disable: false
annotations:
resources:
mgr:
limits:
cpu: "500m"
memory: "1024Mi"
requests:
cpu: "500m"
memory: "1024Mi"
removeOSDsIfOutAndSafeToRemove: false
storage:
useAllNodes: true
useAllDevices: true
config:
databaseSizeMB: "1024" # uncomment if the disks are smaller than 100 GB
journalSizeMB: "1024" # uncomment if the disks are 20 GB or smaller
osdsPerDevice: "1" # this value can be overridden at the node or device level
directories:
- path: /ceph_data
disruptionManagement:
managePodBudgets: false
osdMaintenanceTimeout: 30
manageMachineDisruptionBudgets: false
machineDisruptionBudgetNamespace: openshift-machine-api
建立Worker节点时,需要从Ansible中挂载额外的虚拟磁盘到Worker节点。下面的文件node_storage.yml是用于挂载的playbook的一部分。
- hosts: nodes
become: yes
gather_facts: True
tasks:
- name: include k8s version
include_vars: /vagrant/ansible-playbook/versions.yml
- name: mkfs /dev/sdc
filesystem:
fstype: ext4
dev: /dev/sdc
- name: Creates directory
file:
path: /ceph_data
state: directory
owner: root
group: root
mode: 0775
- name: mount /ceph_data
mount:
path: /ceph_data
src: /dev/sdc
fstype: ext4
state: mounted
使用之前编辑过的cluster.yaml文件应用配置,启动Ceph。
kubectl create -f cluster.yaml
由于启动需要几分钟时间,建议加上“-w”选项以观察进展情况。最终将进入以下状态。
kubectl get po -n rook-ceph
NAME READY STATUS RESTARTS AGE
csi-cephfsplugin-9vzmd 3/3 Running 0 9m3s
csi-cephfsplugin-bzjmk 3/3 Running 0 9m3s
csi-cephfsplugin-provisioner-565ffd64f5-gjbhc 4/4 Running 0 9m3s
csi-cephfsplugin-provisioner-565ffd64f5-tj7h7 4/4 Running 0 9m3s
csi-cephfsplugin-pv5s9 3/3 Running 0 9m3s
csi-rbdplugin-cws6k 3/3 Running 0 9m3s
csi-rbdplugin-jpgjb 3/3 Running 0 9m3s
csi-rbdplugin-p6zxd 3/3 Running 0 9m3s
csi-rbdplugin-provisioner-7bb78d6c66-p49kw 5/5 Running 0 9m3s
csi-rbdplugin-provisioner-7bb78d6c66-r687q 5/5 Running 0 9m3s
rook-ceph-crashcollector-node1-7bbb758b85-lxnmj 1/1 Running 0 5m46s
rook-ceph-crashcollector-node2-6c58bddcdd-hc7ck 1/1 Running 0 5m28s
rook-ceph-crashcollector-node3-7c8c9dd5bc-9c5h8 1/1 Running 0 4m44s
rook-ceph-mgr-a-98554f488-8zjft 1/1 Running 0 5m8s
rook-ceph-mon-a-59c478755b-8tk8d 1/1 Running 0 5m54s
rook-ceph-mon-b-5d9d488947-4r5xh 1/1 Running 0 5m46s
rook-ceph-mon-c-6bfd478cc5-hkhx2 1/1 Running 0 5m28s
rook-ceph-operator-6d74795f75-95nnv 1/1 Running 0 23m
rook-ceph-osd-0-644d5c77d7-mqfwd 1/1 Running 0 4m45s
rook-ceph-osd-1-54964546d4-xfwwh 1/1 Running 0 4m44s
rook-ceph-osd-2-78b5c5f8b-nss7l 1/1 Running 0 4m44s
rook-ceph-osd-prepare-node1-jtk75 0/1 Completed 0 4m49s
rook-ceph-osd-prepare-node2-c5r2n 0/1 Completed 0 4m49s
rook-ceph-osd-prepare-node3-jzl2w 0/1 Completed 0 4m49s
rook-discover-dqm9l 1/1 Running 0 23m
rook-discover-hvgcf 1/1 Running 0 23m
rook-discover-mvd7s 1/1 Running 0 23m
使用工具箱进行测试
当您使用位于同一目录rook/cluster/examples/kubernetes/ceph下的toolbox.yaml时,您可以执行ceph命令。
kubectl create -f toolbox.yaml
deployment.apps/rook-ceph-tools created
kubectl -n rook-ceph get pod -l "app=rook-ceph-tools"
NAME READY STATUS RESTARTS AGE
rook-ceph-tools-78b599b6dd-47vdt 1/1 Running 0 11s
将终端连接到pod上,并以交互方式运行ceph命令。
kubectl -n rook-ceph exec -it $(kubectl -n rook-ceph get pod -l "app=rook-ceph-tools" -o jsonpath='{.items[0].metadata.name}') bash
[root@rook-ceph-tools-78b599b6dd-47vdt /]# ceph status
cluster:
id: 40b602cc-b666-458f-b3a5-25287d48d6d4
health: HEALTH_OK
services:
mon: 1 daemons, quorum a (age 25m)
mgr: a(active, since 25m)
osd: 3 osds: 3 up (since 24m), 3 in (since 24m)
data:
pools: 0 pools, 0 pgs
objects: 0 objects, 0 B
usage: 17 GiB used, 129 GiB / 145 GiB avail
pgs:
[root@rook-ceph-tools-78b599b6dd-47vdt /]# ceph osd status
+----+-------+-------+-------+--------+---------+--------+---------+-----------+
| id | host | used | avail | wr ops | wr data | rd ops | rd data | state |
+----+-------+-------+-------+--------+---------+--------+---------+-----------+
| 0 | node2 | 5718M | 42.8G | 0 | 0 | 0 | 0 | exists,up |
| 1 | node1 | 5684M | 42.8G | 0 | 0 | 0 | 0 | exists,up |
| 2 | node3 | 5684M | 42.8G | 0 | 0 | 0 | 0 | exists,up |
+----+-------+-------+-------+--------+---------+--------+---------+-----------+
[root@rook-ceph-tools-78b599b6dd-47vdt /]# ceph df
RAW STORAGE:
CLASS SIZE AVAIL USED RAW USED %RAW USED
hdd 145 GiB 129 GiB 17 GiB 17 GiB 11.49
TOTAL 145 GiB 129 GiB 17 GiB 17 GiB 11.49
POOLS:
POOL ID STORED OBJECTS USED %USED MAX AVAIL
[root@rook-ceph-tools-78b599b6dd-47vdt /]# rados df
POOL_NAME USED OBJECTS CLONES COPIES MISSING_ON_PRIMARY UNFOUND DEGRADED RD_OPS RD WR_OPS WR USED COMPR UNDER COMPR
total_objects 0
total_used 17 GiB
total_avail 129 GiB
total_space 145 GiB
Ceph的调整
如果虚拟机的操作系统是Ubuntu 16.04,为了避免由于内核问题而出现挂起,需要修改参数。然而,如果使用Ubuntu 18.04,则不需要进行这种调整。由于本文使用的是分支1.17-3node,它使用的是Ubuntu 18.04,所以不需要进行以下调整。
查看默认的可调参数。在Jewel中存在无法获得块存储的问题,需要进行以下更改。
[root@rook-ceph-tools-78b599b6dd-8srn5 /]# ceph osd crush show-tunables
{
"choose_local_tries": 0,
"choose_local_fallback_tries": 0,
"choose_total_tries": 50,
"chooseleaf_descend_once": 1,
"chooseleaf_vary_r": 1,
"chooseleaf_stable": 1,
"straw_calc_version": 1,
"allowed_bucket_algs": 54,
"profile": "jewel", <<--- 設定のプロファイルが jewel になっている
"optimal_tunables": 1,
"legacy_tunables": 0,
"minimum_required_version": "jewel",
"require_feature_tunables": 1,
"require_feature_tunables2": 1,
"has_v2_rules": 0,
"require_feature_tunables3": 1,
"has_v3_rules": 0,
"has_v4_buckets": 1,
"require_feature_tunables5": 1,
"has_v5_rules": 0
}
请将设置更改为”hammer”。
[root@rook-ceph-tools-78b599b6dd-8srn5 /]# ceph osd crush tunables hammer
adjusted tunables profile to hammer
确认更改。
[root@rook-ceph-tools-78b599b6dd-8srn5 /]# ceph osd crush show-tunables
<中略>
"profile": "hammer",
<以下省略>
现在,Ceph集群的设置已经完成,接下来进入客户端端进行配置。
设置存储类型
设置存储类别以执行动态配置。
cd csi/rbd
kubectl apply -f storageclass.yaml
cephblockpool.ceph.rook.io/replicapool created
storageclass.storage.k8s.io/rook-ceph-block created
确认已设置的内容。
kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
rook-ceph-block rook-ceph.rbd.csi.ceph.com Delete Immediate false 35s
现在,我们已经可以动态地为块存储进行配置了。
验证WordPress启动的操作
接下来,我们将进行动态配置功能的测试。测试中我们将启动WordPress,并确保内容和数据库的两个永久数据区域由ROOK Ceph进行分配。
前往包含样例清单的目录。
$ cd ../../..
部署数据库。
kubectl apply -f mysql.yaml
部署应用程序服务器。
kubectl apply -f wordpress.yaml
这样一来,将会产生两个PVC。
kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mysql-pv-claim Bound pvc-4af72998-cfcf-46a7-9fe4-624e34db85cd 20Gi RWO rook-ceph-block 11s
wp-pv-claim Bound pvc-2c7a1991-00dd-4309-9883-c9c69eb0e7db 20Gi RWO rook-ceph-block 5s
持久性存储申请中的容量要求
请在这里确认一下清单。在PVC的清单中,由于是块存储,accessModes被设置为不允许共享的ReadWriteOnce。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: wp-pv-claim
labels:
app: wordpress
spec:
storageClassName: rook-ceph-block
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2Gi
可以将块存储装载到文件系统中,也就是说,可能是由供应商动态地创建文件系统。
volumeMounts:
- name: wordpress-persistent-storage
mountPath: /var/www/html
volumes:
- name: wordpress-persistent-storage
persistentVolumeClaim:
claimName: wp-pv-claim
故障排除
解释一下在没有执行前述的ceph osd crush tunables hammer命令的情况下可能会遇到的问题。
如果Pod在’ContainerCreating’状态下无法进行下一步,则可能是由于Ceph引起的。
kubectl get po
NAME READY STATUS RESTARTS AGE
wordpress-5b886cf59b-6mdnv 0/1 ContainerCreating 0 2m44s
wordpress-mysql-b9ddd6d4c-s7dfc 0/1 ContainerCreating 0 2m50s
在这种情况下,通过显示Pod的详细信息并确认Events,可以判断出停滞的原因。可以看出无法挂载卷和发生超时错误。换句话说,可以推测出Ceph或ROOK存在问题。
kubectl describe po wordpress-mysql-b9ddd6d4c-s7dfc
<中略>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 3m9s (x2 over 3m9s) default-scheduler error while running "VolumeBinding" filter plugin for pod "wordpress-mysql-b9ddd6d4c-s7dfc": pod has unbound immediate PersistentVolumeClaims
Normal Scheduled 3m8s default-scheduler Successfully assigned default/wordpress-mysql-b9ddd6d4c-s7dfc to node1
Normal SuccessfulAttachVolume 3m8s attachdetach-controller AttachVolume.Attach succeeded for volume "pvc-4af72998-cfcf-46a7-9fe4-624e34db85cd"
Warning FailedMount 65s kubelet, node1 Unable to attach or mount volumes: unmounted volumes=[mysql-persistent-storage], unattached volumes=[mysql-persistent-storage default-token-8qr52]: timed out waiting for the condition
Warning FailedMount 58s (x2 over 119s) kubelet, node1 MountVolume.MountDevice failed for volume "pvc-4af72998-cfcf-46a7-9fe4-624e34db85cd" : rpc error: code = Internal desc = rbd: map failed exit status 110, rbd output: rbd: sysfs write failed
In some cases useful info is found in syslog - try "dmesg | tail".
rbd: map failed: (110) Connection timed out
根据https://github.com/ceph/ceph-helm/issues/60,这种情况的原因如下。
重要的Kubernetes使用RBD内核模块将RBD映射到主机。Luminous要求CRUSH_TUNABLES 5(Jewel)。这些可调参数的最低内核版本是4.5。如果您的内核不支持这些可调参数,请运行ceph osd crush tunables hammer。
当通过检查使用Ubuntu 16.04的工作节点的内核版本时,我们发现它是4.4。因此,由于它与上述有关,因此需要进行更改。
vagrant@node1:~$ uname -a
Linux node1 4.4.0-171-generic #200-Ubuntu SMP Tue Dec 3 11:04:55 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
由于使用了Ubuntu 18.04内核,因此不需要进行适配,具体内核如下所示。
vagrant ssh node3
Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.15.0-76-generic x86_64)
ROOK Ceph 仪表板
修改设置以从浏览器中访问Ceph仪表盘。
在初始设置中,服务类型被设定为ClusterIP,这将导致无法从集群外部进行访问。
kubectl -n rook-ceph get service rook-ceph-mgr-dashboard
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
rook-ceph-mgr-dashboard ClusterIP 10.32.0.200 <none> 8443:31930/TCP 5h49m
使用 edit 子命令,在运行中的清单上进行更改,使其可以从 Kubernetes 集群外部进行访问。
kubectl -n rook-ceph edit service rook-ceph-mgr-dashboard
下面是上述命令的执行结果。将第35行的type: ClusterIP更改为type: NodePort。
23 spec:
24 clusterIP: 10.32.0.252
25 ports:
26 - name: https-dashboard
27 port: 8443
28 protocol: TCP
29 targetPort: 8443
30 nodePort: 30443
31 selector:
32 app: rook-ceph-mgr
33 rook_cluster: rook-ceph
34 sessionAffinity: None
35 type: ClusterIP
通过上述更改,节点端口将被打开,可以访问Ceph的仪表板。通过在清单文件的”ports:”处加入”nodePort: 30443″的配置,如果端口开放,可以保持仪表板地址的稳定。
kubectl get svc -n rook-ceph rook-ceph-mgr-dashboard
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
rook-ceph-mgr-dashboard NodePort 10.32.0.252 <none> 8443:30443/TCP 17h
要访问Ceph仪表板,需要提供密码。可以通过执行以下命令获得该密码。
kubectl -n rook-ceph get secret rook-ceph-dashboard-password -o jsonpath="{['data']['password']}" | base64 --decode && echo
xZVbe1aVOL
将此端口号添加到添加到主节点虚拟机主机的IP地址上,通过 https://192.168.1.91:30443 并使用用户ID admin 可以访问。
总结
ROOK可以使用Kubernetes集群中的工作节点内置磁盘构建SDS。通过将持久化数据存储在工作节点上,通过集群化实现分布和冗余来确保数据的可靠性,尽管如此,人们仍然有一些抵触情绪。越简单的东西越不容易损坏,因此保存重要数据的设备最好是满足需求的简单设备。通过这种方式,可以保护重要数据免受软件的复杂协作、脆弱性和版本升级等带来的挑战。
然而,如果要构建SDS集群,除了Kubernetes集群之外,就需要相应的成本。但是,如果能够使用ROOK在同一个Kubernetes集群中持久保存数据,就可以减少工作和成本。而且,还想验证一下是否可以获取快照并将其保存到远程对象存储中。
这次我们发现,ROOK Ceph的设置非常简单且可以快速进行。然而,这并不意味着不需要了解Ceph知识。可以说在使用ROOK之前,应该了解Ceph。而且,要使用最新版本的Ceph,工作节点的Linux内核版本必须为4.5以上。如果无法满足该条件,则需要降低配置级别。
Rook在OpenShift中被作为OpenShift容器存储(OCS)提供,从OpenShift 4.3版本开始可使用。若在本地环境使用OpenShift,Rook应被视为一个不可或缺的组件。