為K8S叢集準備Ceph儲存

2023-02-16 06:00:53

  隨著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

  未完待續...