隨著K8S儲存介面逐漸成熟並順勢推出CSI介面規範後,原來“in-tree”(樹內)模式的很多儲存外掛也逐步遷移到了“out-of-tree”(樹外)模式的CSI外掛上,甚至有些原來支援的儲存卷型別都被直接移除了(例如在K8S v1.26上直接移除了 glusterfs 卷型別),查閱了一下K8S官方最新版本的儲存相關(Storage/Volumes)的說明,綜合最新儲存支援情況,我們選擇Ceph作為K8S叢集的儲存提供者。
首先,進入Ceph官網文件檢視其安裝部署方法,主要看下是否有基於K8S的安裝方法,最後在官網“Installing ceph>Recommended methods”(推薦的Ceph安裝方法)果然發現了基於K8S的安裝方法:
Ceph官方推薦在K8S叢集上使用Rook來部署和管理Ceph叢集!
我們進入Rook官網看看,從官網可以看出Rook是為K8S量身定製的,那就它了:
Ceph是一個在大規模生產叢集中提供檔案、塊和物件儲存的分散式儲存系統,而Rook是一個專門支援Ceph與雲原生環境整合的開源雲原生儲存協調器。Rook利用K8S的Operator機制推出了自己的Rook operator,實現自動化的Ceph部署和管理。Rook作為雲原生儲存平臺已經從CNCF順利畢業!
以上是對Rook簡要說明,接下來藉助Rook在K8S叢集上部署和管理Ceph。
Rook支援K8S v1.19+的版本,CPU架構為amd64、x86_64或arm64均可,除此之外部署Ceph儲存叢集還必須至少滿足以下先決條件之一:
- 每個節點至少有一塊裸裝置(Raw devices,未分割槽未進行檔案系統格式化)
- 裸分割槽(Raw partitions,未進行檔案系統格式化)
- LVM邏輯卷(LVM Logical Volumes,未進行檔案系統格式化)
- block模式下儲存類(storage class)中可用的持久卷(PV)
這裡我們選擇為K8S叢集的每個工作節點新增一塊額外的未格式化磁碟(裸裝置),步驟見以下截圖:
將新增的磁碟設定成獨立模式(模擬公有云廠商提供的獨立磁碟),然後啟動K8S叢集虛擬機器,在工作節點上使用以下命令檢查一下磁碟條件是否符合Ceph部署要求:
[root@node1 ~]# lsblk -f NAME FSTYPE LABEL UUID MOUNTPOINT sdb sr0 iso9660 CentOS 7 x86_64 2020-11-04-11-36-43-00 sda ├─sda2 LVM2_member 45inUD-qJ4O-Fq9E-L6KD-8eJV-mofD-BuJDq6 │ └─centos_node1-root xfs 704f37f0-ae59-4995-80ec-58cba66e023b / └─sda1 xfs 67243cc8-c3fb-490f-b0da-cc439371d5e1 /boot
上述命令輸出中 sdb 磁碟就是我們為工作節點新新增的裸裝置(它的FSTYPE為空),我們可以把它分配給Ceph使用。
需要在K8S叢集中啟用Rook准入控制器,用於驗證使用自定義資源(CR)正確地配置了Rook。該准入控制器在身份認證和授權之後並在持久化物件之前,攔截髮往K8S API Server的請求以進行驗證。我們在安裝Rook之前,使用以下命令在K8S叢集中安裝Rook準備入控制器:
#在master1節點直接應用線上yaml檔案 kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.7.1/cert-manager.yaml #在master1將cert-manager.yaml下載到本地的方式(推薦) kubectl apply -f /etc/kubernetes/rook/cert-manager.yaml
...... service/cert-manager created service/cert-manager-webhook created deployment.apps/cert-manager-cainjector created deployment.apps/cert-manager created deployment.apps/cert-manager-webhook created mutatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created validatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created
另外,Ceph OSD在以下情況下需要依賴於LVM(邏輯卷,OSD是Ceph用於在各個儲存節點實現儲存功能的元件):
- 在裸裝置或裸分割槽上建立OSD
- 如果啟用了加密(在叢集CR中設定了encryptedDevice: "true")
- 指定了後設資料裝置(metadata device)
在以下情況下OSD不需要LVM
- 在使用 storageClassDeviceSets 的PVC上建立OSD
目前大多數Linux發生版的LVM由lvm2包提供,在K8S叢集中執行Ceph OSD的所有儲存節點上都需要有這個包。雖然沒有這個包Rook也能夠成功建立Ceph OSD,但是當相應的節點(node)重啟之後,其上執行的OSD pod將會啟動失敗。所以需要確保作為儲存節點的作業系統上安裝了LVM(從上面磁碟條件查驗的結果中看到我們是有LVM卷的),CentOS可以使用以下命令安裝LVM:
sudo yum install -y lvm2
Ceph需要一個帶有RBD模組的Linux核心。大多數Linux發行版都有這個模組,但不是所有,你可以在K8S叢集的儲存節點上執行 lsmod|grep rbd 命令檢測一下,如果該命令返回空,那說明當前系統核心沒有載入RBD模組,可以使用以下命令嘗試載入RBD模組:
#將RBD模組載入命令放入開機載入項裡 cat > /etc/sysconfig/modules/rbd.modules << EOF #!/bin/bash modprobe rbd EOF #為上述為指令碼新增執行許可權 chmod +x /etc/sysconfig/modules/rbd.modules #執行上述指令碼(如果返回'not found',你可能需要安裝一個新的核心、或重新編譯一個帶有RBD模組的核心、或換一個帶有RBD的Linux 發行版) /bin/bash /etc/sysconfig/modules/rbd.modules #檢視RBD模組是否載入成功 lsmod|grep rbd
Rook預設的RBD配置只指定了分層特性,以便與較舊的核心廣泛相容。如果K8S節點執行在5.4+的系統核心上,則可以啟用其他功能特性。例如特別有用的 fast-diff 和 object-map 特性,主要的功能特性如下(在進行塊儲存的StorageClass定義時指定):
imageFeatures: layering,fast-diff,object-map,deep-flatten,exclusive-lock
如果你將來會從Ceph共享檔案系統(CephFS)建立卷(volume),那麼需要使用4.17+的系統核心,PVC請求的儲存配額只在高於該版本的核心上生效。
------------------------------- 以上為使用Rook在K8S叢集部署Ceph儲存的前提條件 -------------------------------
接下來正式使用Rook在K8S叢集部署Ceph儲存叢集!
首先在K8S所有叢集節點上安裝Git客戶端(用於拉取Rook部署元件清單):
#安裝Git yum install -y git #檢視Git版本 git --version git version 1.8.3.1
使用Rook官方提供的示例部署元件清單(manifests)部署一個簡單的Ceph叢集(測試環境夠用了):
#使用git將部署元件清單示例下載到本地(慢或無法接通的話自己想法辦FQ) git clone --single-branch --branch v1.10.11 https://github.com/rook/rook.git #進入到本地部署元件清單示例目錄 cd rook/deploy/examples #執行以下命令將Rook和Ceph相關CRD資源和通用資源建立到K8S叢集(其中psp.yaml是K8S叢集受Pod安全策略保護的情況下的可選資原檔案) kubectl create -f crds.yaml -f common.yaml -f psp.yaml
接下來部署Rook Operator元件,該元件為Rook與Kubernetes互動的元件,整個叢集只需要一個副本,特別注意 Rook Operator 的配置在Ceph叢集安裝後不能修改,否則Rook會刪除Ceph叢集並重建,所以部署之前一定要做好規劃,修改好operator.yaml的相關配置:
修改 rook/deploy/examples/operator.yaml檔案中的以下內容:
#修改映象地址為華中科技大學和阿里雲的(可以使用docker pull <url>驗證一下,原來的地址很難下載) ROOK_CSI_CEPH_IMAGE: "quay.mirrors.ustc.edu.cn/cephcsi/cephcsi:v3.7.2" ROOK_CSI_REGISTRAR_IMAGE: "registry.aliyuncs.com/google_containers/csi-node-driver-registrar:v2.7.0" ROOK_CSI_RESIZER_IMAGE: "registry.aliyuncs.com/google_containers/csi-resizer:v1.7.0" ROOK_CSI_PROVISIONER_IMAGE: "registry.aliyuncs.com/google_containers/csi-provisioner:v3.4.0" ROOK_CSI_SNAPSHOTTER_IMAGE: "registry.aliyuncs.com/google_containers/csi-snapshotter:v6.2.1" ROOK_CSI_ATTACHER_IMAGE: "registry.aliyuncs.com/google_containers/csi-attacher:v4.1.0" #生產環境一般都會將裸裝置自動發現開關設為true(方便後面追加裝置) ROOK_ENABLE_DISCOVERY_DAEMON: "true" #開啟CephCSI 提供者的節點(node)親和性(去掉前面的註釋即可,會同時作用於CephFS和RBD提供者,如果要分開這兩者的排程,可以繼續開啟後面專用的節點親和性) CSI_PROVISIONER_NODE_AFFINITY: "role=storage-node; storage=rook-ceph" #如果CephFS和RBD提供者的排程親各性要分開,則在上面的基礎上繼開啟它們專用的開關(去除下面兩行前端的#即可) # CSI_RBD_PROVISIONER_NODE_AFFINITY: "role=rbd-node" # CSI_CEPHFS_PROVISIONER_NODE_AFFINITY: "role=cephfs-node" #開啟CephCSI 外掛的節點(node)親和性(去掉前面的註釋即可,會同時作用於CephFS和RBD外掛,如果要分開這兩者的排程,可以繼續開啟後面專用的節點親和性) CSI_PLUGIN_NODE_AFFINITY: "role=storage-node; storage=rook-ceph" #如果CephFS和RBD提供者的排程親各性要分開,則在上面的基礎上繼開啟它們專用的開關(去除下面兩行前端的#即可) # CSI_RBD_PLUGIN_NODE_AFFINITY: "role=rbd-node" # CSI_CEPHFS_PLUGIN_NODE_AFFINITY: "role=cephfs-node" #rook-ceph-operator的Deployment中的容器映象地址rook/ceph:v1.10.11 可以不用換,下載還是很快的! #生產環境一般還會開啟裸裝置自動發現守護程式(方便後期增加裝置) ROOK_ENABLE_DISCOVERY_DAEMON: "true" #同時開打發現代理的節點親和性環境變數 - name: DISCOVER_AGENT_NODE_AFFINITY value: "role=storage-node; storage=rook-ceph"
確認修改完成後,在master1節點上執行以下命令進行Rook Ceph Operator的部署:
#執行以下命令在K8S叢集中部署Rook Ceph Operator(映象拉取可能需要一定時間,耐心等待,可用後一條命令監控相關Pod部署情況) kubectl create -f operator.yaml #使用以下命令監控Rook Ceph Operator相關Pod的部署情況(rook-ceph為預設Rook Ceph Operator部署名稱空間) watch kubectl get pods -n rook-ceph
確保rook-ceph-operator相關Pod都執行正常的情況下,修改 rook/deploy/examples/cluster.yaml檔案中的以下內容:
# enable prometheus alerting for cluster(為叢集開啟prometheus告警) monitoring: # requires Prometheus to be pre-installed enabled: true #開啟節點親和性排程和汙點容忍 # To control where various services will be scheduled by kubernetes, use the placement configuration sections below. # The example under 'all' would have all services scheduled on kubernetes nodes labeled with 'role=storage-node' and # tolerate taints with a key of 'storage-node'. placement: all: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: role operator: In values: - storage-node # podAffinity: # podAntiAffinity: # topologySpreadConstraints: # tolerations: # - key: storage-node # operator: Exists #將儲存設定為我們三個工作節點新加的sdb裸盤 storage: # cluster level storage configuration and selection useAllNodes: false useAllDevices: false #deviceFilter: config: # crushRoot: "custom-root" # specify a non-default root label for the CRUSH map # metadataDevice: "md0" # specify a non-rotational storage so ceph-volume will use it as block db device of bluestore. # 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 # encryptedDevice: "true" # the default value for this option is "false" # Individual nodes and their config can be specified as well, but 'useAllNodes' above must be set to false. Then, only the named # nodes below will be used as storage resources. Each node's 'name' field should match their 'kubernetes.io/hostname' label. nodes: - name: "node1" devices: # specific devices to use for storage can be specified for each node - name: "sdb" - name: "node2" devices: # specific devices to use for storage can be specified for each node - name: "sdb" - name: "node3" devices: # specific devices to use for storage can be specified for each node - name: "sdb" # - name: "nvme01" # multiple osds can be created on high performance devices # config: # osdsPerDevice: "5" # - name: "/dev/disk/by-id/ata-ST4000DM004-XXXX" # devices can be specified using full udev paths # config: # configuration can be specified at the node level which overrides the cluster level config # - name: "172.17.4.301" # deviceFilter: "^sd." # when onlyApplyOSDPlacement is false, will merge both placement.All() and placement.osd onlyApplyOSDPlacement: false
修改完後,根據我們在operator.yaml和cluster.yaml上的節點標籤親和性設定,為三個工作節點打上對應的標籤:
kubectl label nodes node1 node2 node3 role=storage-node kubectl label nodes node1 node2 node3 storage=rook-ceph
#確保工作節點打上對應標籤,並且cluster檔案修改好後,就可以使用cluster.yaml部署Ceph儲存叢集了(部署需要一定的時間,可用後一條命令監控)
kubectl create -f cluster.yaml
#使用以下命令監控Ceph Cluster相關Pod的部署情況(rook-ceph為預設部署名稱空間)
watch kubectl get pods -n rook-ceph
未完待續...