1. 程式人生 > >Kubernetes中分散式儲存Rook-Ceph部署快速演練

Kubernetes中分散式儲存Rook-Ceph部署快速演練

最近在專案中有涉及到Kubernetes的分散式儲存部分的內容,也抽空多瞭解了一些。專案主要基於Rook-Ceph執行,考慮到Rook-Ceph部署也不那麼簡單,[官方文件](https://rook.io/docs/rook/v1.5/)的步驟起點也不算低,因此,在整合官方文件的某些步驟的基礎上,寫篇文章簡單總結一下。 Rook-Ceph是Kubernetes中分散式儲存的一種解決方案,Rook作為一種開源的、雲原生的儲存編排器,為各種儲存服務在雲原生的環境中實現無縫整合,提供了所必須的平臺、框架和服務;而Ceph則是Rook所支援的眾多儲存方案的一種,在Kubernetes環境裡,Ceph基於Rook能夠為應用程式提供塊儲存(Block Storage),物件儲存(Object Storage)以及共享檔案系統(SFS)服務。此處就不對Rook Ceph進行太多的介紹,直接步入正題,一步一步地演練Rook-Ceph從安裝部署到使用的整個過程。 > 注意:本文所有的yaml檔案都是為了配合整個演練過程而設計的,理論上不能直接用在生產環境。如有需要,在用在生產環境之前,請確保所需的引數都已正確配置。 # 安裝Kubernetes 安裝Kubernetes。安裝方法有很多,不怕麻煩可以徒手安裝,也可以直接使用雲供應商的託管服務,比如Azure AKS,也可以使用Rancher RKE,在此就不贅述了。 # 安裝Rook Ceph Operator 這裡我們基於Ceph來討論。事實上Rook支援Ceph、Cassandra、CockroachDB、EdgeFS、NFS以及YugabyteDB等多種儲存供應商(Storage Provider),針對不同的儲存供應商,Rook提供不同的Operator來進行資源的部署和管理。使用下面的命令來安裝Rook Ceph Operator: ```shell helm repo add rook-release https://charts.rook.io/release kubectl create namespace rook-ceph helm install --namespace rook-ceph rook-ceph rook-release/rook-ceph ``` # 安裝Ceph叢集(Ceph Cluster) 可以使用下面的yaml檔案: ```yaml # ceph-cluster-deploy.yaml apiVersion: ceph.rook.io/v1 kind: CephCluster metadata: name: rook-ceph namespace: rook-ceph spec: cephVersion: image: ceph/ceph:v15.2.7 allowUnsupported: false dataDirHostPath: /var/lib/rook skipUpgradeChecks: false continueUpgradeAfterChecksEvenIfNotHealthy: false mon: count: 3 allowMultiplePerNode: false mgr: modules: - name: pg_autoscaler enabled: true dashboard: enabled: true ssl: true monitoring: enabled: false rulesNamespace: rook-ceph network: crashCollector: disable: false cleanupPolicy: confirmation: "" sanitizeDisks: method: quick dataSource: zero iteration: 1 allowUninstallWithVolumes: false annotations: labels: resources: removeOSDsIfOutAndSafeToRemove: false useAllNodes: true useAllDevices: false deviceFilter: nvme1n1 config: osdsPerDevice: "1" disruptionManagement: managePodBudgets: false osdMaintenanceTimeout: 30 pgHealthCheckTimeout: 0 manageMachineDisruptionBudgets: false machineDisruptionBudgetNamespace: openshift-machine-api healthCheck: daemonHealth: mon: disabled: false interval: 45s osd: disabled: false interval: 60s status: disabled: false interval: 60s livenessProbe: mon: disabled: false mgr: disabled: false osd: disabled: false ``` 然後使用以下命令建立Ceph叢集: ```shell kubectl create -f ceph-cluster-deploy.yaml ``` 命令執行成功之後,需要等待幾分鐘,以便OSD能夠成功啟動。執行下面的命令可以檢視所有容器的狀態: ```shell kubectl -n rook-ceph get pod ``` 正常情況下,應該可以看到類似以下的結果: ```shell NAME READY STATUS RESTARTS AGE csi-cephfsplugin-provisioner-d77bb49c6-n5tgs 5/5 Running 0 140s csi-cephfsplugin-provisioner-d77bb49c6-v9rvn 5/5 Running 0 140s csi-cephfsplugin-rthrp 3/3 Running 0 140s csi-rbdplugin-hbsm7 3/3 Running 0 140s csi-rbdplugin-provisioner-5b5cd64fd-nvk6c 6/6 Running 0 140s csi-rbdplugin-provisioner-5b5cd64fd-q7bxl 6/6 Running 0 140s rook-ceph-crashcollector-minikube-5b57b7c5d4-hfldl 1/1 Running 0 105s rook-ceph-mgr-a-64cd7cdf54-j8b5p 1/1 Running 0 77s rook-ceph-mon-a-694bb7987d-fp9w7 1/1 Running 0 105s rook-ceph-mon-b-856fdd5cb9-5h2qk 1/1 Running 0 94s rook-ceph-mon-c-57545897fc-j576h 1/1 Running 0 85s rook-ceph-operator-85f5b946bd-s8grz 1/1 Running 0 92m rook-ceph-osd-0-6bb747b6c5-lnvb6 1/1 Running 0 23s rook-ceph-osd-1-7f67f9646d-44p7v 1/1 Running 0 24s rook-ceph-osd-2-6cd4b776ff-v4d68 1/1 Running 0 25s rook-ceph-osd-prepare-node1-vx2rz 0/2 Completed 0 60s rook-ceph-osd-prepare-node2-ab3fd 0/2 Completed 0 60s rook-ceph-osd-prepare-node3-w4xyz 0/2 Completed 0 60s ``` 需要注意幾點: - `ceph-cluster-deploy.yaml`並沒有包括所有的Ceph叢集建立的引數,可以參考https://rook.io/docs/rook/v1.5/ceph-cluster-crd.html 來了解所有的配置資訊 - 這裡的`deviceFilter: nvme1n1`是用來指定在每個Kubernetes節點上應該使用的卷(Volume)的名稱。這個Volume不能格式化成任何檔案系統,否則Ceph將不會使用它作為儲存卷。我在AWS上建立了獨立的EBS卷,然後直接Attach到Kubernetes節點的機器上,通過`lsblk`命令即可獲得卷的名稱,將這個名稱填入`deviceFilter`設定即可 # 安裝Rook Toolbox Rook Toolbox是一個執行在rook-ceph名稱空間下的容器,通過它可以執行一些Ceph的管理任務,建議安裝,還是挺實用的。建立一個yaml檔案: ```yaml # rook-toolbox.yaml apiVersion: apps/v1 kind: Deployment metadata: name: rook-ceph-tools namespace: rook-ceph labels: app: rook-ceph-tools spec: replicas: 1 selector: matchLabels: app: rook-ceph-tools template: metadata: labels: app: rook-ceph-tools spec: dnsPolicy: ClusterFirstWithHostNet containers: - name: rook-ceph-tools image: rook/ceph:v1.5.3 command: ["/tini"] args: ["-g", "--", "/usr/local/bin/toolbox.sh"] imagePullPolicy: IfNotPresent env: - name: ROOK_CEPH_USERNAME valueFrom: secretKeyRef: name: rook-ceph-mon key: ceph-username - name: ROOK_CEPH_SECRET valueFrom: secretKeyRef: name: rook-ceph-mon key: ceph-secret volumeMounts: - mountPath: /etc/ceph name: ceph-config - name: mon-endpoint-volume mountPath: /etc/rook volumes: - name: mon-endpoint-volume configMap: name: rook-ceph-mon-endpoints items: - key: data path: mon-endpoints - name: ceph-config emptyDir: {} tolerations: - key: "node.kubernetes.io/unreachable" operator: "Exists" effect: "NoExecute" tolerationSeconds: 5 ``` 然後: ```shell kubectl create -f rook-toolbox.yaml ``` 接著可以執行下面的命令,進入Rook Toolbox容器: ```shell kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- bash ``` 然後使用`ceph status`命令來檢視叢集的狀態。正常的話應該可以看到類似下面的結果: ```shell $ ceph status cluster: id: a0452c76-30d9-4c1a-a948-5d8405f19a7c health: HEALTH_OK services: mon: 3 daemons, quorum a,b,c (age 3m) mgr: a(active, since 2m) osd: 3 osds: 3 up (since 1m), 3 in (since 1m) ``` 一定要確保`health`的狀態為`HEALTH_OK`,如果不是`HEALTH_OK`,則需要排查原因並解決。問題排查指南:https://rook.io/docs/rook/v1.5/ceph-common-issues.html。 # 部署塊儲存(Provisioning Block Storage) 使用下面的yaml: ```yaml # ceph-block-deploy.yaml apiVersion: ceph.rook.io/v1 kind: CephBlockPool metadata: name: replicapool namespace: rook-ceph spec: failureDomain: host replicated: size: 3 --- apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: rook-ceph-block annotations: storageclass.kubernetes.io/is-default-class: "true" provisioner: rook-ceph.rbd.csi.ceph.com parameters: clusterID: rook-ceph pool: replicapool imageFormat: "2" imageFeatures: layering csi.storage.k8s.io/provisioner-secret-name: rook-csi-rbd-provisioner csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph csi.storage.k8s.io/controller-expand-secret-name: rook-csi-rbd-provisioner csi.storage.k8s.io/controller-expand-secret-namespace: rook-ceph csi.storage.k8s.io/node-stage-secret-name: rook-csi-rbd-node csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph csi.storage.k8s.io/fstype: ext4 reclaimPolicy: Retain ``` 然後: ```shell Kubectl create -f ceph-block-deploy.yaml ``` 在這個yaml中,同時定義了名為`rook-ceph-block`的`StorageClass`,用以在pods啟動的時候能夠動態建立基於Ceph的塊儲存(通過`pool: replicapool`的設定指定)。此外,在這個StorageClass中,設定了`storageclass.kubernetes.io/is-default-class: "true"`。因此,在`PersistentVolumeClaim`中即使沒有指定`storageClassName`,Kubernetes也會預設使用Ceph塊儲存來儲存app的資料。 > 部署塊儲存的詳細內容可以參考:https://rook.io/docs/rook/v1.5/ceph-block.html。 # 部署物件儲存(Provisioning Object Storage) 使用下面的yaml: ```yaml # ceph-s3-deploy.yaml apiVersion: ceph.rook.io/v1 kind: CephObjectStore metadata: name: my-store namespace: rook-ceph spec: metadataPool: failureDomain: host replicated: size: 3 dataPool: failureDomain: host erasureCoded: dataChunks: 2 codingChunks: 1 preservePoolsOnDelete: true gateway: type: s3 sslCertificateRef: port: 80 # securePort: 443 instances: 3 healthCheck: bucket: disabled: false interval: 60s ``` 然後: ```shell kubectl create -f ceph-s3-deploy.yaml ``` 等待幾分鐘後,執行下面的命令: ``` kubectl -n rook-ceph get pod -l app=rook-ceph-rgw ``` 此時應該可以在pod的列表中看到名字包含有rgw的pod處於`Running`狀態。 接下來就是要在物件儲存上建立Bucket。官方提供了[基於StorageClass的建立方式](https://rook.io/docs/rook/v1.5/ceph-object.html#create-a-bucket)。這裡介紹另一種方式,就是借用MINIO的管理工具來建立。使用下面的shell指令碼: ```bash # setup-s3-storage.sh #! /bin/bash echo "Creating Ceph User" CREATE_USER_OUTPUT=`kubectl -n rook-ceph exec -it $(kubectl -n rook-ceph get pod -l "app=rook-ceph-tools" -o jsonpath='{.items[0].metadata.name}') -- radosgw-admin user create --uid=system-user --display-name=system-user --system` ACCESS_KEY=$(echo $CREATE_USER_OUTPUT | jq -r ".keys[0].access_key") SECRET_KEY=$(echo $CREATE_USER_OUTPUT | jq -r ".keys[0].secret_key") echo "User was created successfully" echo "S3 ACCESS KEY = $ACCESS_KEY" echo "S3 SECRET KEY = $SECRET_KEY" echo "Creating Ceph S3 Bucket" kubectl -n rook-ceph exec -it $(kubectl -n rook-ceph get pod -l "app=rook-ceph-tools" -o jsonpath='{.items[0].metadata.name}') -- curl https://dl.min.io/client/mc/release/linux-amd64/mc --output mc kubectl -n rook-ceph exec -it $(kubectl -n rook-ceph get pod -l "app=rook-ceph-tools" -o jsonpath='{.items[0].metadata.name}') -- chmod +x mc kubectl -n rook-ceph exec -it $(kubectl -n rook-ceph get pod -l "app=rook-ceph-tools" -o jsonpath='{.items[0].metadata.name}') -- ./mc config host add mys3 http://rook-ceph-rgw-signals-store/ "$ACCESS_KEY" "$SECRET_KEY" kubectl -n rook-ceph exec -it $(kubectl -n rook-ceph get pod -l "app=rook-ceph-tools" -o jsonpath='{.items[0].metadata.name}') -- ./mc mb mys3/data echo "Ceph S3 Bucket created successfully" echo "S3 ACCESS KEY = $ACCESS_KEY" echo "S3 SECRET KEY = $SECRET_KEY" ``` 在確保了當前機器上安裝了`jq`後,執行: ```shell chmod +x setup-s3-storage.sh ./setup-s3-storage.sh ``` 此時會輸出S3的Access Key和Secret Key。建立的Bucket名為data。 驗證Object Storage是否部署成功,首先執行下面的命令進入Rook Toolbox: ```shell kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- bash ``` 然後執行: ```shell export AWS_HOST= export AWS_ENDPOINT= export AWS_ACCESS_KEY_ID= export AWS_SECRET_ACCESS_KEY= ``` - 為rgw Service的DNS主機名。如果你的Object Storage名為my-store,那麼主機名就是`rook-ceph-rgw-my-store.rook-ceph` - 為rgw Service的端點。執行`kubectl -n rook-ceph get svc rook-ceph-rgw-my-store`,然後將ClusterIP和埠號拼接起來作為endpoint的值 - accessKey:上一步獲得的Access Key - secretKey:上一步獲得的Secret Key 以下是一個例子: ```shell export AWS_HOST=rook-ceph-rgw-my-store.rook-ceph export AWS_ENDPOINT=10.104.35.31:80 export AWS_ACCESS_KEY_ID=XEZDB3UJ6X7HVBE7X7MA export AWS_SECRET_ACCESS_KEY=7yGIZON7EhFORz0I40BFniML36D2rl8CQQ5kXU6l ``` 接下來,安裝一個s3cmd的工具: ```shell yum --assumeyes install s3cmd ``` 然後隨便寫一些內容到rookObj檔案: ```shell echo "Hello Rook" > /tmp/rookObj ``` 然後通過s3cmd,將這個檔案儲存到S3: ```shell s3cmd put /tmp/rookObj --no-ssl --host=${AWS_HOST} --host-bucket= s3://data ``` 注意`--host-bucket=`後的空格。 然後,使用s3cmd從Bucket將檔案下載並另存為另一個檔案: ```shell s3cmd get s3://data/rookObj /tmp/rookObj-download --no-ssl --host=${AWS_HOST} --host-bucket= ``` 最後,通過`cat`命令,檢視下載下來的檔案的內容是否正確: ```shell cat /tmp/rookObj-download ``` 如果能夠看到`Hello Rook`的輸出字樣,表示一切正常。接下來就可以在app中使用Ceph Block Storage和Ceph Object Storage了。 > 部署物件儲存的詳細內容可以參考:[https://rook.io/docs/rook/v1.5/ceph-object.html](https://rook.io/docs/rook/v1.5/ceph-object.html)。 # 下一步 之後我會使用Microsoft .NET 5,編寫一個Web API應用程式並部署到Kubernetes環境,演示如何在app中使用本文所部署的Ceph Block Storage和Ceph Object Sto