新四季網

kubernetes雲技術(Kubernetes雲原生開源分布式存儲)

2023-04-16 19:50:44 2

本文轉載自公眾號: 民生運維人

作者:付廣平

出處:https://mp.weixin.qq.com/s?__biz=MzIwNDkwMjc1OQ==&mid=2247483769&idx=1&sn=edb7f95ac7838ab32d91547cd4f294a3&scene=21

1 Kubernetes存儲介紹1.1 為何引入PV、PVC以及StorageClass?

熟悉Kubernetes的都對PV、PVC以及StorageClass不陌生,我們經常用到,因此這裡不再詳細介紹PV、PVC以及StorageClass的用法,僅簡單聊聊為什麼需要引入這三個概念。

我們看下最早期Pod使用volume的寫法:

apiVersion: v1kind: Podmetadata: name: test-podspec: containers: - image: ... name: test-pod volumeMounts: - mountPath: /data name: data volumes: - name: data capacity: storage: 10Gi cephfs: monitors: - 172.16.0.1:6789 - 172.16.0.2:6789 - 172.16.0.3:6789 path: /opt/eshop_dir/eshop user: admin secretRef: name: ceph-secret

這種方式至少存在兩個問題:

Pod聲明與底層存儲耦合在一起,每次聲明volume都需要配置存儲類型以及該存儲插件的一堆配置,如果是第三方存儲,配置會非常複雜。開發人員的需求可能只是需要一個20GB的卷,這種方式卻不得不強制要求開發人員了解底層存儲類型和配置。

比如前面的例子中每次聲明Pod都需要配置Ceph集群的mon地址以及secret,特別麻煩。

於是引入了PV(Persistent Volume),PV其實就是把Volume的配置聲明部分從Pod中分離出來:

apiVersion: v1kind: PersistentVolumemetadata: name: cephfsspec: capacity: storage: 10Gi accessModes: - ReadWriteMany cephfs: monitors: - 172.16.0.1:6789 - 172.16.0.2:6789 - 172.16.0.3:6789 path: /opt/eshop_dir/eshop user: admin secretRef: name: ceph-secret

我們發現PV的spec部分幾乎和前面Pod的volume定義部分是一樣的。

有了PV,在Pod中就可以不用再定義volume的配置了,直接引用即可,volume定義和Pod鬆耦合了。

但是這沒有解決volume定義的第二個問題,存儲系統通常由運維人員管理,開發人員並不知道底層存儲配置,也就很難去定義好PV。

為了解決這個問題,引入了PVC(Persistent Volume Claim),聲明與消費分離,開發與運維責任分離。

運維人員負責存儲管理,可以事先根據存儲配置定義好PV,而開發人員無需了解底層存儲配置,只需要通過PVC聲明需要的存儲類型、大小、訪問模式等需求即可,然後就可以在Pod中引用PVC,完全不用關心底層存儲細節。

kind: PersistentVolumeClaimapiVersion: v1metadata: name: cephfsspec: accessModes: - ReadWriteMany resources: requests: storage: 8Gi

PVC會根據聲明的大小、存儲類型(如storageClassName)、accessModes等關鍵字查找PV,如果找到了匹配的PV,則會與之關聯。

通過PV以及PVC,開發人員的問題是解決了,但沒有解決運維人員的問題。運維人員需要維護一堆PV列表和配置,如果PV不夠用需要手動創建新的PV,PV空閒了還需要手動去回收,管理效率太低了。

於是又引入了StorageClass,StorageClass類似聲明了一個非常大的存儲池,其中一個最重要的參數是provisioner,這個provisioner聲明了誰來提供存儲源,我們熟悉的OpenStack Cinder、Ceph、AWS EBS等都是provisioner。

kind: StorageClassapiVersion: storage.k8s.io/v1metadata: name: aws-gp2provisioner: kubernetes.io/aws-ebsparameters: type: gp2 fsType: ext4

有了StorageClass後,Kubernetes會根據開發人員定義的PVC中聲明的StorageClassName以及大小等需求自動創建PV,即Dynamic Provisioning。

而運維人員只需要聲明好StorageClass以及Quota配額,無需維護PV。

通過PV、PVC以及StorageClass,開發和運維的工作徹底解放了。

1.2 Kubernetes存儲方案發展過程概述

我們知道Kubernetes存儲最開始是通過Volume Plugin實現集成外部存儲系統,即不同的存儲系統對應不同的volume plugin。

Volume Plugin實現代碼全都放在了Kubernetes主幹代碼中(in-tree),也就是說這些插件與核心Kubernetes二進位文件一起連結、編譯、構建和發布。

這種方案至少存在如下幾個問題:

在Kubernetes中添加新存儲系統支持需要在核心Kubernetes增加插件代碼,隨著存儲插件越來越多,Kubernetes代碼也會變得越來越龐大。Kubernetes與具體的存儲plugin耦合在一起,一旦存儲接口發生任何變化都需要重新修改plugin代碼,也就是說不得不修改Kubernetes代碼,這會導致Kubernetes代碼維護越來越困難。如果plugin有bug或者存儲系統故障導致crash,可能導致整個Kubernetes集群整體crash。這些插件運行時無法做權限管控,具有Kubernetes所有組件的所有權限,存在一定的安全風險。插件的實現必須通過Golang語言編寫並與Kubernetes一起開源,可能對一些廠商不利。

因此從1.8開始,Kubernetes停止往Kubernetes代碼中增加新的存儲支持, 並推出了一種新的插件形式支持外部存儲系統,即FlexVolume,不過FlexVolume其實在1.2就提出了。

FlexVolume類似於CNI插件,通過外部腳本集成外部存儲接口,這些腳本默認放在 /usr/libexec/kubernetes/kubelet-plugins/volume/exec/ ,需要安裝到所有Node節點上。

這樣每個存儲插件只需要通過外部腳本(out-of-tree)實現 attach 、 detach 、 mount 、 umount 等接口即可集成第三方存儲,不需要動Kubernetes源碼,可以參考官方的一個 LVM FlexVolume Demo [1] 。

但是這種方法也有問題:

腳本文件放在host主機上,因此驅動不得不通過訪問宿主機的根文件系統去運行腳本。這些插件如果還有第三方程序依賴或者OS兼容性要求,還需要在所有的Node節點安裝這些依賴並解決兼容問題。

因此這種方式雖然解決了in-tree的問題,但顯然這種方式用起來不太優雅,不太原生。

因此Kubernetes從1.9開始又引入了Container Storage Interface (CSI)容器存儲接口,並於1.13版本正式GA。

CSI的實現方案和CRI類似通過gRPC與volume driver進行通信,存儲廠商需要實現三個服務接口Identity Service、Controller Service、Node Service,

Identity Service用於返回一些插件信息;Controller Service實現Volume的CURD操作,Node Service運行在所有的Node節點,用於實現把volume掛載在當前Node節點的指定目錄,該服務會監聽一個Socket,controller通過這個Socket進行通信,可以參考官方提供的樣例 CSI Hostpath driver Sample [2] 。

更多有關CSI介紹可以參考官方的設計文檔 CSI Volume Plugins in Kubernetes Design Doc [3] 。

通過CSI基本解決了如上in-tree以及FlexVolume的大多數問題,未來Kubernetes會把in-tree的存儲插件都遷移到CSI。

當然Flex Volume Plugin也會與新的CSI Volume Plugin並存以便兼容現有的第三方FlexVolume存儲插件。

1.3 為什麼需要雲原生分布式存儲

通過CSI接口或者Flex Volume Plugin解決了Kubernetes集成外部存儲的問題,目前Kubernetes已經能夠支持非常多的外部存儲系統了,如NFS、GlusterFS、Ceph、OpenStack Cinder等,這些存儲系統目前主流的部署方式還是運行在Kubernetes集群之外單獨部署和維護,這不符合All In Kubernetes的原則。

如果已經有分布式存儲系統還好,可以直接對接。但如果沒有現成分布式存儲,則不得不單獨部署一套分布式存儲。

很多分布式存儲部署相對還是比較複雜的,比如Ceph。而Kubernetes天生就具有快速部署和編排應用的能力,如果能把分布式存儲的部署也通過Kubernetes編排管理起來,則顯然能夠大大降低分布式存儲的部署和維護成本,甚至可以使用一條apply命令就可以輕鬆部署一個Ceph集群。

這主要有兩種實現思路:

第一種思路就是重新針對雲原生平臺設計一個分布式存儲,這個分布式存儲系統組件是微服務化的,能夠復用Kubernetes的調度、故障恢復和編排等能力,如後面要介紹的Longhorn、OpenEBS。另一種思路就是設計微服務組件把已有的分布式存儲系統包裝管理起來,使原來的分布式存儲可以適配運行在Kubernetes平臺上,實現通過Kubernetes管理原有的分布式存儲系統,如後面要介紹的Rook。1.4 Container Attached Storage,容器存儲的未來?

我們知道組成雲計算的三大基石為計算、存儲和網絡,Kubernetes計算(Runtime)、存儲(PV/PVC)和網絡(Subnet/DNS/Service/Ingress)的設計都是開放的,可以集成不同的方案,比如網絡通過CNI接口支持集成Flannel、Calico等網絡方案,運行時(Runtime)通過CRI支持Docker、Rkt、Kata等運行時方案,存儲通過volume plugin支持集成如AWS EBS、Ceph、OpenStack Cinder等存儲系統。

但是我們發現目前主流的方案中存儲與計算、網絡稍有不同,計算和網絡都是以微服務的形式通過Kubernetes統一編排管理的,即Kubernetes既是計算和網絡的消費者,同時也是計算和網絡的編排者和管理者。

而存儲則不一樣,雖然Kubernetes已經設計了PV/PVC機制來管理外部存儲,但只是弄了一個標準接口集成,存儲本身還是通過獨立的存儲系統來管理,Kubernetes根本不知道底層存儲是如何編排和調度的。

社區認為既然計算和網絡都由我Kubernetes統一編排了,是不是存儲也考慮下?

於是社區提出了Container Attached Storage(CAS)理念,這個理念的目標就是利用Kubernetes來編排存儲,從而實現我Kubernetes編排一切,這裡的一切包括計算、存儲、網絡,當然更高一層的還包括應用、服務、軟體等。

這個方案如何實現呢?CAS提出如下方案:

每個volume都由一個輕量級的Controller來管理,這個Controller可以是一個單獨的Pod。這個Controller與使用該volume的應用Pod在同一個Node(sidecar模式)。不同的Volume的數據使用多個獨立的Controller Pod進行管理。

CAS

由於Pod是通過Kubernetes編排與調度的,因此毫無疑問通過這種形式其實就實現了Kubernetes編排和調度存儲: )

Kubernetes畢竟是目前主流趨勢,通過Kubernetes編排和管理存儲也必然是一種發展趨勢,目前OpenEBS就是CAS的一種開源實現,商業存儲如PortWorx、StorageOS也是基於CAS模式的。

更多關於CAS的可以參考CNCF官宣文章 Container Attached Storage: A Primer [4] 。

2 簡單好用的Longhorn2.1 Longhorn簡介

Longhorn [5] 在我之前的文章 輕量級Kubernetes k3s初探 已經簡單介紹過,最初由Rancher公司開發並貢獻給社區,專門針對Kubernetes設計開發的雲原生分布式塊存儲系統,因此和Kubernetes契合度很高,主要體現在兩個方面,一是它本身就直接運行在Kubernetes平臺上,通過容器和微服務的形式運行;其二是能很好的與PV/PVC結合。

與其他分布式存儲系統最大的不同點是,Longhorn並沒有設計一個非常複雜的控制器來管理海量的volume數據卷,而是將控制器拆分成一個個非常輕量級的微控制器,這些微控制器能夠通過Kubernetes、Mesos等平臺進行編排與調度。

每個微控制器只管理一個volume,換句話說,一個volume一個控制器,每個volume都有自己的控制器,這種基於微服務的設計使每個volume相對獨立,控制器升級時可以先選擇一部分卷進行操作,如果升級出現問題,可以快速選擇回滾到舊版本,升級過程中只可能會影響正在升級的volume,而不會導致其他volume IO中斷。

Longhorn的實現和CAS的設計理念基本是一致的,相比Ceph來說會簡單很多,而又具備分布式塊存儲系統的一些基本功能:

支持多副本,不存在單點故障;支持增量快照;支持備份到其他外部存儲系統中,比如S3;精簡配置(thin provisioning);...

我覺得Longhorn還有一個特別好的功能是內置了一個Web UI,通過UI能夠很方便的管理Node、Volume以及Backup,不得不說 Longhorn真是麻雀雖小五臟俱全

根據官方的說法,Longhorn並不是為了取代其他分布式塊存儲系統,而是為了設計一個更簡單的適合容器環境的塊存儲系統,其他分布式存儲有的一些高級功能Longhorn並沒有實現,比如去重(deduplication)、壓縮、分塊、多路徑等。

Longhorn存儲管理機制比較簡單,當在Longhorn中Node節點增加物理存儲時,其本質就是把Node對應的路徑通過HostPath掛載到Pod中,我們可以查看該路徑的目錄結構,在 replicas 目錄中一個volume一個子目錄,文件內容如下:

# find replicas/int32bit-volume-3-ab6717d6/replicas/int32bit-volume-3-ab6717d6/replicas/int32bit-volume-3-ab6717d6/volume.metareplicas/int32bit-volume-3-ab6717d6/volume-head-000.imgreplicas/int32bit-volume-3-ab6717d6/revision.counterreplicas/int32bit-volume-3-ab6717d6/volume-head-000.img.meta

其中 int32bibt-volume-3 是volume名稱, ab6717d6 對應副本名稱,子目錄中包含一些volume的metadata以及img文件,而img文件其實就是一個raw格式文件:

# qemu-img info volume-head-000.imgimage: volume-head-000.imgfile format: rawvirtual size: 20G (21474836480 bytes)disk size: 383M

raw格式其實就是Linux Sparse稀疏文件,由於單個文件大小受文件系統和分區限制,因此Longhorn volume會受單個磁碟的大小和性能的限制,不過我覺得Kubernetes Pod其實也很少需要用到特別大的volume。

更多關於Longhorn的技術實現原理可以參考官宣文章 Announcing Longhorn: an open source project for microservices-based distributed block storage [6] 。

2.2 Longhorn部署

Longhorn部署也非常簡單,只需要一個 kubectl apply 命令:

kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/master/deploy/longhorn.yaml

創建完後就可以通過Service或者Ingress訪問它的UI了:

longhorn webui

在Node頁面可以管理節點以及物理存儲,Volume頁面可以管理所有的volumes,Backup可以查看備份等。

volume詳情頁面可以查看volume的掛載情況、副本位置、對應的PV/PVC以及快照鏈等:

longhorn volume

除此之外,Longhorn還支持創建備份計劃,可以通過cron指定時間點或者定時對volume進行快照或者備份到S3中。

longhorn backup

2.3 Kubernetes集成Longhorn存儲

Longhorn既支持FlexVolume也支持CSI接口,安裝時會自動根據Kubernetes版本選擇FlexVolume或者CSI。

Kubernetes集成Longhorn,根據前面對StorageClass的介紹,我們需要先安裝Longhorn StorageClass:

kubectl create -f \https://raw.githubusercontent.com/longhorn/longhorn/master/examples/storageclass.yaml

聲明一個20Gi的PVC:

# kubectl apply -f -apiVersion: v1kind: PersistentVolumeClaimmetadata: name: longhorn-volv-pvcspec: accessModes: - ReadWriteOnce storageClassName: longhorn resources: requests: storage: 2Gi

創建Pod並使用新創建的PVC:

# kubectl apply -f -apiVersion: v1kind: Podmetadata: name: test-volume-longhornspec: containers: - name: test-volume-longhorn image: jocatalin/kubernetes-bootcamp:v1 volumeMounts: - name: volv mountPath: /data volumes: - name: volv persistentVolumeClaim: claimName: longhorn-volv-pvc

通過Longhorn Dashboard查看volume狀態已經掛載到Pod中:

longhorn pvc

Longhorn volume不僅可以通過PV形式掛載到Kubernetes容器,還可以直接通過ISCSI接口掛載到Node節點上:

longhorn_attach_to_host

此時可以通過 lsblk 在OS查看到塊存儲設備,通過 iscsiadm 命令可以查看Node節點連接的設備會話:

# lsblk -SNAME HCTL TYPE VENDOR MODEL REV TRANsda 0:0:0:1 disk IET VIRTUAL-DISK 0001 iscsi# iscsiadm -m sessiontcp: [3] 10.244.0.50:3260,1 iqn.2019-10.io.longhorn:int32bit-volume-1 (non-flash)

3 CAS開源實現OpenEBS3.1 OpenEBS簡介

OpenEBS [7] 是 MayaData [8] (之前叫CloudByte)公司開源的雲原生容器存儲項目,命名上可能參考了AWS EBS(Elastic Block Storage)。

OpenEBS也是目前Container Attached Storage的一種開源實現方案,因此它直接運行在Kubernetes平臺上,通過Kubernetes平臺進行編排與調度。

OpenEBS支持如下三種存儲類型,分別為cStore、Jiva以及LocalPV。

Jiva

後端實現其實就是前面介紹的Longhorn,也就是使用了raw格式sparse稀疏文件作為虛擬磁碟實現容器volume,這個和虛擬機的本地虛擬磁碟實現類似,可以通過 qemu-img info 查看volume分配的虛擬大小以及實際使用的空間,稀疏文件默認路徑為 /var/openebs ,所以volume的容量總大小取決於這個路徑掛載的文件系統大小。

實現上使用了Longhorn早期版本設計,即一個3副本的volume會有4個Pod控制器管理,一個是主控制器,三個副本控制器,其中主控制器運行了iSCSI Target服務,通過Service暴露ISCSI 3260埠,主控制器會把IO複製到所有副本的控制器。

openebs jiva

cStore

這是OpenEBS最推薦的存儲類型,測試最完備,經過了生產部署考驗,支持多副本、快照、克隆、精簡配置(thin provisioning)、數據強一致性等高級特性。

和Jiva不一樣的是,cStore使用了類似ZFS或者LVM的Pool的概念,blockdevices就相當於LVM的PV,而Pool則類似LVM的VG概念,volume類似LVM的LV,其中blockdevice對應物理上的一塊磁碟或者一個分區,多個blockdevices組成Pool,這些blockdevices如何存儲落盤取決於Pool策略,cStore支持的Pool策略包括striped、mirrored、raidz、raidz2,這些概念都不陌生。

cstore pool

Pool是一個單Node節點層面的概念而不是分布式的,創建一個cStor Pool實際上會在每個Node節點創建相同策略的Pool實例,因此即使使用striped策略,數據打散後也只是存儲在本地的多塊磁碟,不會跨節點存儲,當然volume副本是跨節點的。

OpenEBS通過ISCSI接口實現volume的掛載,每當創建一個cStor Volume,OpenEBS就會創建一個新的cStor target Pod,cStor target會創建對應的LUN設備。

cStor target除了負責LUN設備管理,還負責副本之間的數據同步,每當用戶有數據寫入時,cStor target會把數據拷貝到其他所有副本中去。

比如假設創建了一個三副本的cStore PV,當用戶寫入數據時,cStor target會同時往三個副本寫入數據,只有等三個副本都寫成功後,才會響應用戶,因此顯然OpenEBS是一個強一致性分布式存儲系統。

cstor-for-deployment

不過這也是cStor性能比較差的原因之一,它不像Ceph一樣一個RBD image會分塊存儲在多個節點多個硬碟的多個OSD上,可以避免單節點的IO性能瓶頸問題。

LocalPV

LocalPV就是直接把本地磁碟(local disk)掛載到容器,這個其實就是Kubernetes LocalPV的增強版,因為直接讀取本地磁碟,相對iSCSI需要走網絡IO來說性能肯定是最好的,不過缺點是沒有多副本、快照、克隆等高級特性。

3.2 OpenEBS部署

直接使用kubectl安裝:

kubectl apply -f \ https://openebs.github.io/charts/openebs-operator-1.8.0.yaml

如上會把所有的/dev下的塊設備都當作OpenEBS的block devices,建議修改下 openebs-ndm-config Configmap,通過 path-filter 指定分給OpenEBS的物理設備。

正如LVM有了PV還需要創建VG一樣,cStor需要手動創建一個Pool:

apiVersion: openebs.io/v1alpha1kind: StoragePoolClaimmetadata: name: cstor-disk-pool annotations: cas.openebs.io/config: | - name: PoolResourceRequests value: |- memory: 2Gi - name: PoolResourceLimits value: |- memory: 4Gispec: name: cstor-disk-pool type: disk poolSpec: poolType: striped blockDevices: blockDeviceList: - blockdevice-ad96d141bd7804554d431cb13e7e61bc - blockdevice-b14cd44f3bfcbd94d3e0bda065f6e2bd - blockdevice-e3a5cf960033d7a96fdee46a5baee9d2

其中poolType選擇pool策略,如果使用mirror需要注意每個Node的磁碟數量必須是偶數,這裡我們選擇 striped ,即數據會打散分布存儲在Node Pool的所有磁碟。

blockDevices選擇要放入該Pool的物理設備,這裡作為測試每個Node節點只有一塊盤,實際生產時應該至少使用3塊盤以上,使用mirror則至少兩塊盤以上.

可以通過如下命令查看可用的blockDevices:

# kubectl get blockdevices --all-namespaces -o wideNAMESPACE NAME NODENAME PATH SIZE CLAIMSTATE STATUS AGEopenebs blockdevice-ad96d141bd7804554d431cb13e7e61bc ip-192-168-193-6.cn-northwest-1.compute.internal /dev/nvme0n1 107374182400 Claimed Active 4d17hopenebs blockdevice-b14cd44f3bfcbd94d3e0bda065f6e2bd ip-192-168-193-172.cn-northwest-1.compute.internal /dev/nvme0n1 107374182400 Claimed Active 4d17hopenebs blockdevice-e3a5cf960033d7a96fdee46a5baee9d2 ip-192-168-193-194.cn-northwest-1.compute.internal /dev/nvme0n1 107374182400 Claimed Active 4d17h

其中Claimed表示已分配, PATH 對應物理設備路徑。

使用CR cstorpools 可以查看Pool:

# kubectl get cstorpools.openebs.io --all-namespacesNAME ALLOCATED FREE CAPACITY STATUS READONLY TYPE AGEcstor-disk-pool-9tey 272K 99.5G 99.5G Healthy false striped 4m50scstor-disk-pool-lzg4 272K 99.5G 99.5G Healthy false striped 4m50scstor-disk-pool-yme1 272K 99.5G 99.5G Healthy false striped 4m50s

可見OpenEBS會在所有的Node節點創建Pool實例,與前面的解釋一致。

3.3 Kubernetes集成OpenEBS塊存儲

本小節主要以cStor為例演示下如何使用OpenEBS,前面已經創建了cStor Pool,接下來只需要再創建對應的StorageClass即可:

apiVersion: storage.k8s.io/v1kind: StorageClassmetadata: name: cstor-disk-pool annotations: openebs.io/cas-type: cstor cas.openebs.io/config: | - name: StoragePoolClaim value: "cstor-disk-pool" - name: ReplicaCount value: "3"provisioner: openebs.io/provisioner-iscsi

其中StoragePoolClaim指定使用的Pool名稱,ReplicaCount指定volume的副本數。

創建完StorageClass後就可以創建PVC了:

kind: PersistentVolumeClaimapiVersion: v1metadata: name: test-openebs-cstor namespace: defaultspec: storageClassName: cstor-disk-pool accessModes: - ReadWriteOnce resources: requests: storage: 50Gi---apiVersion: v1kind: Podmetadata: name: test-openebs-cstor namespace: defaultspec: containers: - name: test-openebs-cstor image: jocatalin/kubernetes-bootcamp:v1 volumeMounts: - name: test-openebs-cstor mountPath: /data volumes: - name: test-openebs-cstor persistentVolumeClaim: claimName: test-openebs-cstor

每創建一個PV,OpenEBS就會創建一個Target Pod,這個Pod通過一個單副本的Deployment管理,這個Pod會創建一個LUN並export,通過Service暴露iSCSI埠:

# kubectl get pvc --all-namespacesNAMESPACE NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGEdefault test-openebs-cstor Bound pvc-6673e311-0db1-4f15-b480-aafb16a72d46 50Gi RWO cstor-disk-pool 31m# kubectl get pod -n openebs | grep pvc-6673e311-0db1-4f15-b480-aafb16a72d46pvc-6673e311-0db1-4f15-b480-aafb16a72d46-target-55bb467574mf7hf 3/3 Running 1 31m# kubectl get deployments.apps -n openebs | grep pvc-6673e311-0db1-4f15-b480-aafb16a72d46pvc-6673e311-0db1-4f15-b480-aafb16a72d46-target 1/1 1 1 32m# kubectl get svc -n openebs | grep pvc-6673e311-0db1-4f15-b480-aafb16a72d46pvc-6673e311-0db1-4f15-b480-aafb16a72d46 ClusterIP 10.96.24.35 3260/TCP,7777/TCP,6060/TCP,9500/TCP 32m

毫無疑問,OpenEBS的所有服務運行、存儲調度、服務之間通信以及存儲的管理都是通過Kubernetes完成的,它就像集成到Kubernetes的一個內嵌功能一樣,一旦配置完成,基本不需要額外的運維和管理。

一個Volume對應一個Target Pod,這完全遵循了CAS的設計理念。

4 讓分布式存儲簡化管理的Rook4.1 Rook簡介

Rook [9] 也是目前開源中比較流行的雲原生存儲編排系統,它和之前介紹的LongHorn和OpenEBS不一樣,它的目標並不是重新造輪子實現一個全新的存儲系統,最開始Rook項目僅僅專注於如何實現把Ceph運行在Kubernetes平臺上。

隨著項目的發展,格局也慢慢變大,僅僅把Ceph搞定是不夠的,項目當前的目標是將外部已有的分布式存儲系統在雲原生平臺託管運行起來,藉助雲原生平臺具有的自動化調度、故障恢復、彈性擴展等能力實現外部存儲系統的自動管理、自動彈性擴展以及自動故障修復。

按照官方的說法,Rook要把原來需要對分布式存儲系統手動做的一些運維工作藉助雲原生平臺能力(如Kubernetes)實現自動化,這些運維工作包括部署、初始化、配置、擴展、升級、遷移、災難恢復、監控以及資源管理等,這種自動化甚至不需要人去手動觸發,而是雲原生平臺自動觸發的,因此叫做self-managing,真正實現NoOpts。

比如集群增加一塊磁碟,Rook能自動初始化為一個OSD,並自動加入到合適的故障域中,這個OSD在Kubernetes中是以Pod的形式運行的。

目前除了能支持編排管理Ceph集群,還支持:

EdgeFSCockroachDBCassandraNFSYugabyte DB

不同的存儲通過不同的Operator實現,但使用起來基本一致,Rook屏蔽了底層存儲系統的差異。

4.2 Rook部署

安裝部署Rook非常簡單,以Ceph為例,只需要安裝對應的Operator即可:

git clone --single-branch --branch release-1.3 \ https://github.com/rook/rook.gitcd rook/cluster/examples/kubernetes/cephkubectl create -f common.yamlkubectl create -f operator.yamlkubectl create -f cluster.yaml

通過Rook管理Ceph,理論上不需要直接通過Ceph Client命令行接口與Ceph集群直接交互。不過如果有需要,可以通過如下方式進行簡單配置:

kubectl create -f toolbox.yaml # 安裝Ceph client工具export CEPH_TOOL_POD=$(kubectl -n rook-ceph \ get pod -l "app=rook-ceph-tools" \ -o jsonpath='{.items[0].metadata.name}')aliasalias

使用 ceph 命令查看集群狀態:

# ceph osd dfID CLASS WEIGHT REWEIGHT SIZE RAW USE DATA OMAP META AVAIL %USE VAR PGS STATUS TOTAL 0 B 0 B 0 B 0 B 0 B 0 B 0MIN/MAX VAR: -/- STDDEV: 0

我們發現Ceph集群是空的,沒有任何OSD,這是因為我的機器沒有裸磁碟(即沒有安裝任何文件系統的分區)。

DeamonSet rook-discover 會定時監視Node節點是否有新的磁碟,一旦有新的磁碟,就會自動啟動一個Job進行OSD初始化。如下是Node節點增加磁碟的結果:

ceph osd prepare

如果運行在公有雲上,rook還會根據節點的Region以及AZ自動放到不同的故障域,不需要手動調整crushmap:

ceph osd tree

如圖,由於我的測試集群部署在AWS上,並且三個節點都放在了一個AZ上,因此三個OSD都在 zone cn-northwest-1b 中,實際生產環境不推薦這麼做。

我們發現整個磁碟以及OSD初始化過程,無需人工幹預,這就是所謂的 self-manage 。

想想我們平時在做Ceph集群擴容,從準備磁碟到crushmap配置,沒有半個小時是搞不定的,而通過Rook我們幾乎不用操心OSD是如何加到集群的。

Rook默認還會安裝Ceph Dashboard,可以通過Kubernetes Service rook-ceph-mgr-dashboard 進行訪問, admin 的密碼保存在secret rook-ceph-dashboard-password 中,可通過如下命令獲取:

kubectl -n rook-ceph get secret rook-ceph-dashboard-password \-o \| base64 --decode && echo

ceph dashboard

Rook會把Ceph集群的監控導出,便於與Prometheus集成。

4.3 Kubernetes集成Rook Ceph存儲

Longhorn、OpenEBS都只提供了塊存儲接口,意味著一個Volume只能掛載到一個Pod,而Rook Ceph則同時提供了塊存儲、共享文件系統存儲以及對象存儲接口,其中共享文件系統存儲以及對象存儲都能實現跨節點的多個Pod共享。

接下來我們通過例子演示下如何使用。

4.3.1 塊存儲

Ceph通過RBD實現塊存儲,首先我們在Kubernetes上安裝StorageClass:

kubectl create -f \cluster/examples/kubernetes/ceph/csi/rbd/storageclass.yaml

我們首先需要創建一個Ceph Pool,當然我們可以通過 ceph osd pool create 命令手動創建,但這樣體現不了 self-managing ,我們應該屏蔽Ceph集群接口,直接使用Kubernetes CRD進行聲明:

# kubectl apply -f -apiVersion: ceph.rook.io/v1kind: CephBlockPoolmetadata: name: replicapool namespace: rook-cephspec: failureDomain: host replicated: size: 3

通過如上方式,我們基本不需要使用 ceph 命令,即創建了一個3副本的rbd pool。

可以通過 kubectl get cephblockpools 查看pool列表:

# kubectl get cephblockpoolsNAME AGEreplicapool 107s

創建一個Pod使用 CephBlockPool 新建Volume:

# kubectl apply -f ----apiVersion: v1kind: PersistentVolumeClaimmetadata: name: test-ceph-blockstorage-pvcspec: storageClassName: rook-ceph-block accessModes: - ReadWriteOnce resources: requests: storage: 20Gi---apiVersion: v1kind: Podmetadata: name: test-ceph-blockstoragespec: containers: - name: test-ceph-blockstorage image: jocatalin/kubernetes-bootcamp:v1 volumeMounts: - name: volv mountPath: /data volumes: - name: volv persistentVolumeClaim: claimName: test-ceph-blockstorage-pvc

輸出結果如下:

# kubectl get pod test-ceph-blockstorageNAME READY STATUS RESTARTS AGEtest-ceph-blockstorage 1/1 Running 0 5m4s# kubectl get pvcNAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGEtest-ceph-blockstorage-pvc Bound pvc-6ff56a06-86a1-437c-b04f-62bb18e76375 20Gi RWO rook-ceph-block 5m8s# rbd -p replicapool lscsi-vol-e65ec8ef-7cc1-11ea-b6f8-ce60d5fc8330

從輸出結果可見PV volume對應Ceph的一個RBD image。

4.3.2 共享文件系統存儲

共享文件系統存儲即提供文件系統存儲接口,我們最常用的共享文件系統存儲如NFS、CIFS、GlusterFS等,Ceph通過CephFS實現共享文件系統存儲。

和創建Ceph Pool一樣,同樣使用Kubernetes即可聲明一個共享文件系統實例,完全不需要調用 ceph 接口:

apiVersion: ceph.rook.io/v1kind: CephFilesystemmetadata: name: myfs namespace: rook-cephspec: metadataPool: replicated: size: 3 dataPools: - replicated: size: 3 preservePoolsOnDelete: true metadataServer: activeCount: 1 activeStandby: true

可以通過如下命令查看mds服務是否就緒:

# kubectl -n rook-ceph get pod -l app=rook-ceph-mdsNAME READY STATUS RESTARTS AGErook-ceph-mds-myfs-a-f87d59467-xwj84 1/1 Running 0 32srook-ceph-mds-myfs-b-c96645f59-h7ffr 1/1 Running 0 32s# kubectl get cephfilesystems.ceph.rook.ioNAME ACTIVEMDS AGEmyfs 1 111s

創建cephfs StorageClass:

apiVersion: storage.k8s.io/v1kind: StorageClassmetadata: name: rook-cephfsprovisioner: rook-ceph.cephfs.csi.ceph.comparameters: clusterID: rook-ceph fsName: myfs pool: myfs-data0 csi.storage.k8s.io/provisioner-secret-name: rook-csi-cephfs-provisioner csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph csi.storage.k8s.io/controller-expand-secret-name: rook-csi-cephfs-provisioner csi.storage.k8s.io/controller-expand-secret-namespace: rook-ceph csi.storage.k8s.io/node-stage-secret-name: rook-csi-cephfs-node csi.storage.k8s.io/node-stage-secret-namespace: rook-cephreclaimPolicy: DeleteallowVolumeExpansion: truemountOptions:

我們知道CephFS是共享文件系統存儲,支持多個Pod共享,首先我們創建一個 ReadWriteMany 的PVC:

apiVersion: v1kind: PersistentVolumeClaimmetadata: name: cephfs-pvcspec: accessModes: - ReadWriteMany resources: requests: storage: 1Gi storageClassName: rook-cephfs

通過Deployment創建三個Pod共享這個PVC:

---apiVersion: apps/v1kind: Deploymentmetadata: name: cephfs-demo labels: k8s-app: cephfs-demo kubernetes.io/cluster-service: "true"spec: replicas: 3 selector: matchLabels: k8s-app: cephfs-demo template: metadata: labels: k8s-app: cephfs-demo spec: containers: - name: cephfs-demo image: jocatalin/kubernetes-bootcamp:v1 volumeMounts: - name: volv mountPath: /data volumes: - name: volv persistentVolumeClaim: claimName: cephfs-pvc readOnly: false

等待Pod初始完成後,我們從其中一個Pod寫入數據,看另一個Pod能否看到寫入的數據:

cephfs demo

如上圖,我們往Pod cephfs-demo-5799fcbf58-2sm4b 寫入數據,從 cephfs-demo-5799fcbf58-bkw9f 可以讀取數據,符合我們預期。

在Ceph Dashboard中我們也可以看到myfs實例一共有3個 clients:

cephfs dashboard

4.3.3 對象存儲

Ceph通過RGW實現對象存儲接口,RGW兼容AWS S3 API,因此Pod可以和使用S3一樣使用Ceph RGW,比如Python可以使用boto3 SDK對桶和對象進行操作。

首先我們需要創建RGW網關:

apiVersion: ceph.rook.io/v1kind: CephObjectStoremetadata: name: my-store namespace: rook-cephspec: metadataPool: failureDomain: host replicated: size: 3 dataPool: failureDomain: host erasureCoded: dataChunks: 2 codingChunks: 1 preservePoolsOnDelete: true gateway: type: s3 sslCertificateRef: port: 80 securePort: instances: 1

網關就緒後,我們就可以創建bucket了,雖然bucket不是Volume,但Rook也把bucket抽象封裝為StorageClass:

apiVersion: storage.k8s.io/v1kind: StorageClassmetadata: name: rook-ceph-bucketprovisioner: ceph.rook.io/bucketreclaimPolicy: Deleteparameters: objectStoreName: my-store objectStoreNamespace: rook-ceph region: us-east-1

接下來就像聲明PVC一樣創建bucket了,不過不叫PVC,而是叫OBC(Object Bucket Claim),

apiVersion: objectbucket.io/v1alpha1kind: ObjectBucketClaimmetadata: name: ceph-bucketspec: generateBucketName: ceph-bkt storageClassName: rook-ceph-bucket

其中AK(access key)以及SK(secret key)保存在Secret ceph-bucket 中,我們可以通過如下命令獲取:

export AWS_ACCESS_KEY_ID=$(kubectl -n default \ get secret ceph-bucket -o yaml \ | grep AWS_ACCESS_KEY_ID \ | awk '{print $2}' | base64 --decode)export AWS_SECRET_ACCESS_KEY=$(kubectl -n default \ get secret ceph-bucket -o yaml \ | grep AWS_SECRET_ACCESS_KEY \ | awk '{print $2}' | base64 --decode)# S3 Endpoint為Service rook-ceph-rgw-my-store地址export AWS_ENDPOINT=http://$(kubectl get svc \ -n rook-ceph \ -l app=rook-ceph-rgw \ -o jsonpath='{.items[0].spec.clusterIP}')

此時就可以使用s3命令進行操作了:

aws_s3_ls

如上我們通過 aws s3 cp 命令上傳了一個文本文件,通過 aws s3 ls 命令我們發現文件已經上傳成功。

4.4 總結

通過Rook,我們幾乎不需要直接對Ceph進行任何操作,Rook實現了Ceph對象對應的CRD,集群部署、配置、資源供給等操作都能通過Kubernetes CR進行聲明,藉助Kubernetes的能力實現了Ceph集群的self-managing、self-scaling以及self-healing。

5 總結

本文首先介紹了PV/PVC/Storageclass、Kubernetes存儲發展過程以及CAS存儲方案,然後分別介紹了目前比較主流的開源雲原生分布式存儲Longhorn、OpenEBS以及Rook,其中Longhorn比較簡單,並且提供了原生的WebUI,麻雀雖小五臟俱全。OpenEBS是CAS的開源實現方案,支持Jiva、cStor以及LocalPV存儲後端,Rook Ceph則實現通過Kubernetes管理和運行Ceph集群。

網上有一篇文章 Storage on Kubernetes: OpenEBS vs Rook (Ceph) vs Rancher Longhorn [10] 針對如上開源雲原生存儲方案以及部分商業產品的性能使用fio進行了測試,供參考。

如下表格中綠色表示性能表現最好,紅色表示性能最差:

性能對比

參考資料

[1]

LVM FlexVolume Demo: https://github.com/kubernetes/examples/blob/master/staging/volumes/flexvolume/lvm

[2]

CSI Hostpath driver Sample: https://github.com/kubernetes-csi/csi-driver-host-path

[3]

CSI Volume Plugins in Kubernetes Design Doc: https://github.com/kubernetes/community/blob/master/contributors/design-proposals/storage/container-storage-interface.md

[4]

Container Attached Storage: A Primer: https://www.cncf.io/blog/2018/04/19/container-attached-storage-a-primer/

[5]

Longhorn: https://longhorn.io/

[6]

Announcing Longhorn: an open source project for microservices-based distributed block storage: https://rancher.com/blog/2017/announcing-longhorn-microservices-block-storage/

[7]

OpenEBS: https://openebs.io/

[8]

MayaData: https://mayadata.io/

[9]

Rook: https://rook.io/docs/rook/v1.3/

[10]

Storage on Kubernetes: OpenEBS vs Rook (Ceph) vs Rancher Longhorn: https://vitobotta.com/2019/08/06/kubernetes-storage-openebs-rook-longhorn-storageos-robin-portworx/

作者介紹

付廣平:任職民生銀行雲技術管理中心,負責雲基礎架構、運維以及雲計算相關技術研究。畢業於北京郵電大學,從2013開始從事OpenStack相關工作,參與了OpenStack Nova、Cinder、Cloud Custodian等項目社區開發,微信公眾號int32ibt以及知乎專欄《OpenStack》作者。對Ceph、Docker、Kubernetes等技術也有一定的了解。

本文轉載自公眾號: 民生運維人

作者:付廣平

出處:https://mp.weixin.qq.com/s?__biz=MzIwNDkwMjc1OQ==&mid=2247483769&idx=1&sn=edb7f95ac7838ab32d91547cd4f294a3&scene=21

,
同类文章
葬禮的夢想

葬禮的夢想

夢見葬禮,我得到了這個夢想,五個要素的五個要素,水火只好,主要名字在外面,職業生涯良好,一切都應該對待他人治療誠意,由於小,吉利的冬天夢想,秋天的夢是不吉利的
找到手機是什麼意思?

找到手機是什麼意思?

找到手機是什麼意思?五次選舉的五個要素是兩名士兵的跡象。與他溝通很好。這是非常財富,它擅長運作,職業是仙人的標誌。單身男人有這個夢想,主要生活可以有人幫忙
我不怎麼想?

我不怎麼想?

我做了什麼意味著看到米飯烹飪?我得到了這個夢想,五線的主要土壤,但是Tu Ke水是錢的跡象,職業生涯更加真誠。他真誠地誠實。這是豐富的,這是夏瑞的巨星
夢想你的意思是什麼?

夢想你的意思是什麼?

你是什​​麼意思夢想的夢想?夢想,主要木材的五個要素,水的跡象,主營業務,主營業務,案子應該抓住魅力,不能疏忽,春天夢想的吉利夢想夏天的夢想不幸。詢問學者夢想
拯救夢想

拯救夢想

拯救夢想什麼意思?你夢想著拯救人嗎?拯救人們的夢想有一個現實,也有夢想的主觀想像力,請參閱週宮官方網站拯救人民夢想的詳細解釋。夢想著敵人被拯救出來
2022愛方向和生日是在[質量個性]中

2022愛方向和生日是在[質量個性]中

[救生員]有人說,在出生88天之前,胎兒已經知道哪天的出生,如何有優質的個性,將走在什麼樣的愛情之旅,將與生活生活有什么生活。今天
夢想切割剪裁

夢想切割剪裁

夢想切割剪裁什麼意思?你夢想切你的手是好的嗎?夢想切割手工切割手有一個真正的影響和反應,也有夢想的主觀想像力。請參閱官方網站夢想的細節,以削減手
夢想著親人死了

夢想著親人死了

夢想著親人死了什麼意思?你夢想夢想你的親人死嗎?夢想有一個現實的影響和反應,還有夢想的主觀想像力,請參閱夢想世界夢想死亡的親屬的詳細解釋
夢想搶劫

夢想搶劫

夢想搶劫什麼意思?你夢想搶劫嗎?夢想著搶劫有一個現實的影響和反應,也有夢想的主觀想像力,請參閱週恭吉夢官方網站的詳細解釋。夢想搶劫
夢想缺乏缺乏紊亂

夢想缺乏缺乏紊亂

夢想缺乏缺乏紊亂什麼意思?你夢想缺乏異常藥物嗎?夢想缺乏現實世界的影響和現實,還有夢想的主觀想像,請看官方網站的夢想組織缺乏異常藥物。我覺得有些東西缺失了