為K8S叢集準備Ceph儲存

歲月已走遠發表於2023-02-15

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

  Rook Ceph叢集搭建好併成功執行後,我們就可以開始基於Rook Ceph叢集建立可供K8S內的應用消費的塊儲存(Block Devices)、共享檔案系統(Shared Filesystem)和物件儲存(Object Storage)了。這些型別的儲存資源在Rook Ceph中分別被定義為CephBlockPool、CephFilesystem 和 CephObjectStore。

  首先,來建立Ceph塊儲存(Block Devices):Ceph能為Pod提供裸塊裝置儲存卷(volumn)。只需要將Rook官方提供的示例部署元件清單專案中 /rook/deploy/examples/csi/rbd 目錄下的storageclass.yaml檔案或storageclass-ec.yaml檔案應用到K8S裡即可(這兩個檔案的主要區別是保障資料高可用的方式不一樣,前者是透過多副本的方式,後者是透過擦除演算法的方式保障節點故障時資料不丟失,後者不需要三倍的儲存空間,但需要更多的CPU資源進行計算),它們都需要三個節點進行部署。我們這裡選用storageclass.yaml檔案,因為我們的核心版本已升級至5.4+,所以可以開啟前面說的特別有用的 fast-diff 和 object-map 特性,開啟storageclass.yaml檔案修改以下內容(紅色為新開啟的功能特性):

  # RBD image features
  # Available for imageFormat: "2". Older releases of CSI RBD
  # support only the `layering` feature. The Linux kernel (KRBD) supports the
  # full complement of features as of 5.4
  # `layering` alone corresponds to Ceph's bitfield value of "2" ;
  # `layering` + `fast-diff` + `object-map` + `deep-flatten` + `exclusive-lock` together
  # correspond to Ceph's OR'd bitfield value of "63". Here we use
  # a symbolic, comma-separated format:
  # For 5.4 or later kernels:
  #imageFeatures: layering,fast-diff,object-map,deep-flatten,exclusive-lock
  # For 5.3 or earlier kernels:
  imageFeatures: layering,fast-diff,object-map,deep-flatten,exclusive-lock

  修改好後執行以下命令應用一下即可:

kubectl create -f /root/rook/deploy/examples/csi/rbd/storageclass.yaml 

  可以檢視一下當前叢集中的儲存資源:

kubectl get sc
NAME              PROVISIONER                  RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
rook-ceph-block   rook-ceph.rbd.csi.ceph.com   Delete          Immediate           true                   5m5s

  然後,來建立Ceph共享檔案系統(Shared Filesystem):Ceph檔案系統(CephFS)允許使用者將符合posix的共享資料夾“mount”到一個或多個主機中((對於K8S來說就是pod),在K8S中建立CephFS只需要將Rook官方提供的示例部署元件清單專案中 rook/deploy/examples/csi/cephfs 目錄下的storageclass.yaml檔案或storageclass-ec.yaml檔案應用一下即可:

kubectl create -f /root/rook/deploy/examples/csi/cephfs/storageclass.yaml 

  可以檢視一下當前叢集中的儲存資源:

kubectl get sc
NAME              PROVISIONER                     RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
rook-ceph-block   rook-ceph.rbd.csi.ceph.com      Delete          Immediate           true                   24m
rook-cephfs       rook-ceph.cephfs.csi.ceph.com   Delete          Immediate           true                   6s
[root@master1 rbd]# 

  最後,來建立Ceph物件儲存(Object Storage):Ceph物件儲存支援使用HTTP的get、put、post以及delete語義操作的稱為物件資料塊的儲存。在K8S中建立Ceph物件儲存只需要將Rook官方提供的示例部署元件清單專案中 rook/deploy/examples 目錄下的object.yaml檔案或object-ec.yaml檔案應用一下即可(如果檔案內預設的gateway.port:80埠已經被佔用的話,需要更換一個未佔用的埠,比如我這邊80埠已經分配置Ingress Nginx Controller了,將Ceph物件儲存API服務的閘道器埠換成8088):

  # The gateway service configuration
  gateway:
    # A reference to the secret in the rook namespace where the ssl certificate is stored
    # sslCertificateRef:
    # A reference to the secret in the rook namespace where the ca bundle is stored
    # caBundleRef:
    # The port that RGW pods will listen on (http)
    port: 8088
    # The port that RGW pods will listen on (https). An ssl certificate is required.
    # securePort: 443
    # The number of pods in the rgw deployment
    instances: 1

  修改好後執行以下命令應用一下即可:

kubectl create -f rook/deploy/examples/object.yaml 

  可以檢視一下當前叢集中的儲存資源:

 

相關文章