毋庸置疑,容器與容器編排已經成為目前IT人員最為關注的技術之一併得到快速的普及。根據Gartner的調查,截止到2022年,僅有10%的CIO對容器使用沒有任何的計劃,而27%的CIO已經計劃將容器應用與生產環境。
Gartner IOCS 2018 Conference polling results
最初的容器主要應用於無狀態應用,並不需要持久化的存儲,但隨著容器被原來越多的採用,以及其配合Kubernetes帶來的強大的自動化管理能力,MongoDB、MySQL和PostgreSQL等有狀態應用被越來多的運行於容器之上,對持久化存儲提出更多需求和更高的要求。
SmartX分布式塊存儲(內部代號:SMTX ZBS)由SmartX自主開發,作為SmartX超融合的核心引擎,ZBS已經被大量應用於金融、製造業、通信、地產等行業的私有雲建設、虛擬化整合等場景,承載用戶生產以及開發業務。其穩定性、易用性和豐富的存儲特性已經經過長時間檢驗,並獲得大量行業頭部認可。
日前,SMTX ZBS的CSI驅動已正式加入到K8s官方的驅動列表,企業客戶不僅可以繼續使用SMTX ZBS構建私有雲和超融合系統,亦可使用其為K8s提供持久化存儲,支持資料庫等有狀態應用,進一步加速K8s在企業內部更多場景落地。
Kubernetes官網截圖
以下部分概述了CSI的機制以及SMTX ZBS與CSI的接口實現。
概念與定義
1 K8s的持久化存儲支持
在支持持久化存儲方面,K8s提供了內嵌原生Driver的方式連接外部的常見存儲系統例如NFS、iSCSI、CephFS、RBD等來滿足不同業務的需求。但由於存儲生態本身也在不斷演進,使用K8s內嵌的方式來支持不斷變化的存儲系統在成本和時效上都會對K8s項目自身帶來巨大的挑戰。
所以和其他服務管理系統一樣,K8s逐漸的將存儲系統的具體實現從主項目中分離出來,通過定義接口的方式允許第三方廠商自行接入存儲服務。在這個道路上也經歷了兩個階段:
1. Flex Volume,自1.2版本引入。
第三方存儲服務提供商直接在K8s Server上部署符合Flex Volume規範的Driver,利用K8s暴露出的mount/unmount/attach/detach等關鍵API實現存儲系統的接入。這個模式主要的問題是,在這個形態下第三方廠商的Driver有權限接入物理節點的根文件系統,這會帶來安全上的隱患。
2. Container Storage Interface (CSI),自1.9版本引入,目前已經進入GA階段(1.13)。
CSI定義了容器場景所需要的存儲控制原語和完整的控制流程,並且在K8s的CSI實現中,所有的第三方Driver和K8s的其他服務擴展一樣,以服務容器的形態的運行,不會直接影響到K8s的核心系統穩定性。
2存儲對象
CSI定義的存儲對象為持久化卷,稱之為Volume。包括兩種類型:
Mounted File Volume,Node將會把Volume以指定的文件格式Mount到Container上,從Container的角度看到的是一個目錄;
Raw Block Volume,直接將Volume以Block Device(磁碟)的形態暴露給Container,對於某些可以直接操作磁碟的服務,這個形態可以省去文件系統的開銷獲得更好的性能。
Raw Block Volume目前還處於Beta階段,所以下文的過程描述和SMTX的CSI Driver目前的實現方式均針對Mounted File Volume。
3 Plugin
CSI將一個實現了CSI服務的Driver稱之為Plugin。根據提供的功能不同將它分為兩種類型:
·Controller Plugin,負責存儲對象(Volume)的生命周期管理,在集群中僅需要有一個即可;
·Node Plugin,在必要時與使用Volume的容器所在的節點交互,提供諸如節點上的Volume掛載/卸載等動作支持,如有需要則在每個服務節點上均部署。
存儲服務商可以根據自身需求實現不同的的Plugin組合。例如對於以NFS形式提供的存儲服務,可以僅實現Controller Plugin實現資源的創建和訪問權限控制,每個節點均可以通過標準的NFS方式獲得服務,無需通過Node Plugin來實現掛載/卸載等操作。而以iSCSI形式提供的存儲服務,就需要Node Plugin在指定節點上,通過掛載LUN,格式化,掛載文件系統等一系列動作完成iSCSI LUN至容器可見的目錄形式的轉化。
4 Volume生命周期
一個典型的CSI Volume生命周期如下圖(來自CSI SPEC)所示:
1.Volume被創建後進入CREATED狀態,此時Volume僅在存儲系統中存在,對於所有的Node或者Container都是不可感知的;
2.對CREATED狀態的Volume進行Controlller Publish動作後在指定的Node上進入NODE_READY的狀態,此時Node可以感知到Volume,但是Container依然不可見;
3.在Node對Volume進行Stage操作,進入VOL_READY的狀態,此時Node已經與Volume建立連接。Volume在Node上以某種形式存在;
4.在Node上對Volume進行Publish操作,此時Volume將轉化為Node上Container可見的形態被Container利用,進入正式服務的狀態;
5.當Container的生命周期結束或其他不再需要Volume情況發生時,Node執行Unpublish Volume動作,將Volume與Container之間的連接關係解除,回退至VOL_READY狀態;
6.Node Unstage操作將會把Volume與Node的連接斷開,回退至NODE_READY狀態;
7.Controller Unpublish操作則會取消Node對Volume的訪問權限;
8.Delete則從存儲系統中銷毀Volume。
9.CSI要求狀態轉化操作是冪等的,並在原則上保證Volume的狀態轉化是有序進行的。
根據存儲使用方式和內部實現的不同,狀態機可以略有區別,但對應操作必須是成對出現的。例如在不需要額外建立Node與Volume之間連接的Stage/Unstage階段時,狀態機就可以直接通過Controller Publish/Unpublish在NODE_READY與PUBISHED之間轉化,而無需經過VOL_READY階段。Plugin向CSI註冊時必須聲明自身支持哪些語義。
5 RPC
CSI要求Plugin支持的RPC包括:
Identity Service:認證服務,Controller和Node Plugin均需要支持
GetPluginInfo,獲取Plugin基本信息
GetPluginCapabilities,獲取Plugin支持的能力
Probe,探測Plugin的健康狀態
Controller Service:控制服務
Volume CRUD,包括了擴容和容量探測等Volume狀態檢查與操作接口
Controller Publish/Unpublish Volume,Node對Volume的訪問權限管理
Snapshot CRD,快照的創建和刪除操作,目前CSI定義的Snapshot僅用於創建Volume,未提供回滾的語義
Node Service:節點服務
Node Stage/Unstage/Publish/Unpublish/GetStats Volume,節點上Volume的連接狀態管理
Node Expand Volume,節點上的Volume擴容操作,在volume邏輯大小擴容之後,可能還需要同步的擴容Volume之上的文件系統並讓使用Volume的Container感知到,所以在Node Plugin上需要有對應的接口
Node Get Capabilities/Info,Plugin的基礎屬性與Node的屬性查詢
部署形態
CSI使用Sidecar的方式實現CSI Plugin與K8s核心邏輯的解耦。Sidecar代表監聽了CSI指定API的標準容器,它與CSI Plugin共同組成一個Pod對外提供服務,它們之間通過Socket連接。在這個模式下,Sidecar成為CSI Plugin與K8s之間連接的中介和隔離帶。理想狀態下二者可以在不直接交互和影響的情況下共同工作,解決了安全問題。
CSI定義了如下幾種Sidecar:
external-provisioner:監聽Volume CRUD API,完成Volume的生命周期管理
external-attacher:監聽Controller[Publish|Unpublish]Volume API,實現Node和Volume的可見性控制
external-snapshotter:監聽Snapshot CRD API,完成Snapshot的生命周期管理
node-driver-register:監聽Node基本信息查詢API,註冊Node Plugin,每個節點Node Plugin均需要通過driver-register註冊自身才可以與K8s之間建立連接獲取Node Volume相關請求
cluster-driver-register:用於向K8s註冊Plugin整體支持的模式,包括是否跳過Attach階段/是否在Node Publish Volume階段時需要K8s提供Pod信息
livenessprobe:心跳檢測,用於探測Plugin的存活狀態
適用場景
在容器化發展的早期階段,Container多用於承擔輕量型的無狀態服務,對數據存儲的需求大多通過本地的臨時共享文件,或者用網絡訪問的方式將數據置於遠端的日誌收集或者DB等外部存儲上。這種模式業務和數據之間從程序管理的角度看是鬆耦合的,互相獨立,沒有嚴格的依賴。
但是另一方面,這個模式下數據本身無法成為服務的一部分,並不能通過K8s統一管理。並且需要為每個應用打開通往遠端存儲服務的網絡通道,這在安全性上有時並不是一個好的選擇。
而基於持久化卷,將數據服務提供方也放入K8s Pod中(例如掛載持久化卷作為磁碟,上面部署容器運行DB)作為完整應用的一部分,數據即可以做到與應用無縫的統一管理,所有應用內部Pod間的業務數據請求均可以在K8s提供的虛擬網絡中進行。而基於K8s本身的高可用特性和CSI Driver的靈活配置能力也可以獲得不遜色於外部存儲的可靠性與性能。
SMTX ZBS x CSI
1 SMTX ZBS
SMTX ZBS通過iSCSI的方式為K8s提供持久化存儲。它的內部結構如下圖所示:
SMTX ZBS內部結構
在每個節點上部署有Chunk Server用於管理本地的SSD/HDD提供統一的高性能混合存儲服務,在部分節點上部署Meta作為元數據管理服務,將Chunk Server組成高可靠集群。每個Chunk Server提供如iSCSI Target這樣的協議接入服務,他們在接入上是邏輯等價的,即可以從任一一個Chunk Server訪問到集群中所有的Target和LUN。
2 ZBS CSI Driver
ZBS CSI Driver的部署形態如下圖所示:
ZBS CSI Driver部署形態
每個CSI Volume與ZBS iSCSI LUN一一對應,它的生命周期如下:
1.Create Volume:Controller Plugin收到創建請求之後會在ZBS中創建一個iSCSI LUN,如有必要則會自動再創建需要的Target,ZBS的實現中,iSCSI LUN以及所屬的Target均為邏輯對象,不與物理磁碟綁定。一個集群中允許創建4096個Target,每個Target中最多允許創建255個LUN,多個CSI Volume會處在相同的Target內;
2.Controller Publish Volume:目前Kubernetes使用Open iSCSI作為節點上的數據接入服務,Open iSCSI在掛載Target時,會將所有Target內的LUN均掛載到主機上作為一個Block Device(例如/dev/sdx這樣的磁碟)。為了避免讓主機察覺到不需要也不應該訪問的LUN,ZBS採用了近似LUN Masking的機制來達到這個目標。在初始Volume對應的LUN在創建時,不會允許任何iSCSI initiator (iSCSI的協議客戶端)發現LUN。在Controller Publish Volume階段,ZBS Controller Plugin會將指定Node上的initiator註冊到LUN上,在這之後,關聯Node的iSCSI discovery機制才可以在Target內發現並訪問LUN;
3.Node Stage Volume:ZBS Node Plugin會將LUN通過Open iSCSI命令掛載至主機,呈現為一個磁碟;
4.Node Publish Volume:ZBS Node Plugin對磁碟進行格式化(如果磁碟之前尚未被格式化,如已經格式化則為跳過對應步驟),將磁碟Mount到主機上提供給Container使用;
5.Node Unpublish Volume:ZBS Node Plugin將磁碟上的文件系統Unmount;
6.Node Stage Volume:ZBS Node Plugin在主機上將斷開磁碟的iSCSI連結;
7.Controller Unpublish Volume:ZBS Controller Plugin向ZBS後端註銷指定Node在LUN上的訪問權限;
8.Delete Volume:ZBS Controller Plugin請求ZBS刪除對應的LUN,LUN所佔用的數據空間將會在存儲系統中被回收。
ZBS CSI Driver支持Snapshot CRD操作,Snapshot的方式為COW,相關請求僅涉及簡單的元數據操作,所以關聯接口會以同步模式快速響應。Snapshot自身或者基於Snapshot創建的Volume都會立刻處於Volume Ready的狀態。
3數據鏈路
K8s和ZBS之間的iSCSI數據鏈路如下圖所示:
K8s和ZBS之間的iSCSI數據鏈路
ZBS使用iSCSI Redirector模式提供iSCSI接入服務,CSI Plugin給Driver提供的iSCSI服務端地址為iSCSI Redirector地址,initiator嘗試連接iSCSI Server(Target端,ZBS中由Chunk提供Target服務)時,Redirector將會採用的hash的方式引導initiator重新連接向一個可用的Chunk Server。
在重定向之後,所有的數據請求僅在initiator與Chunk之間進行,無需經過Redirectord。ZBS集群中所有Chunk Server在處理iSCSI接入請求時是邏輯等價的,即任一Chunk均可以提供集群中的任一個Target LUN的數據訪問服務。重定向的方式可以有效的分散數據接入壓力,充分利用集群性能。
4可靠與可用性
SMTX ZBS在設計之初就以高可靠、高可用、高性能為目標,在集群內部採用多副本,靜默數據檢查自動平衡和恢復等機制來保證數據的安全可靠。在這個基礎之上,K8s CSI模式獲得比使用本地存儲更高的安全性。
異常處理
K8s計算節點異常
Node A上的pod將會被自動在其他節點(Node B)上拉起,會重新經歷Node B上Publish Volume至掛載的動作。Node B會接入Chunk server提供Pod關聯的Volume的IO服務,之前在Node A上已經寫入Volume中的數據不會受到損失。
Chunk節點異常
如果是計算節點當前連接的Chunk異常,則與Chunk節點間的鏈路將中斷,計算節點會重新向iSCSI Redirector服務尋求一個新的接入節點迅速恢復服務。通常情況下這個影響的時間為秒級。
如果非當前連接的Chunk異常,可能會因為IO副本損失而產生短暫的延遲,iSCSI鏈路本身不會受到影響,影響時間也為秒級。
iSCSI Redirector節點異常
SMTX ZBS提供VIP(虛擬IP)服務,可以保證集群中有且僅有一個節點會持有該VIP。iSCSI Redirector運行在VIP節點上,當它異常時。自然會替換到新的VIP節點提供iSCSI Redirector服務。ZBS保證所有的節點提供的Redirector服務是等價的。
雙活與異地備份
ZBS在基本存儲功能的基礎上,還提供雙活集群和異地備份的功能。藉助這兩個功能,K8s CSI Volume可以獲得同城跨數據中心的數據強一致安全性保證或者是自動的跨城市/數據中心的定期備份能力。
5整體部署形式
目前SMTX對CSI支持兩種形態的部署形式,基於VM的融合模式與分離模式,後續將提供SMTX K8s原生融合模式的部署支持。
分離模式
K8s和SMTX ZBS分別是獨立的物理集群,他們之間通過接入網絡互相關聯。接入網絡需要獨立於K8s中的業務網絡和ZBS使用的存儲網絡。
融合模式
融合模式下,K8s運行在SMTX OS提供的虛擬機上。通過接入網絡接入SMTX OS上的ZBS服務。這個部署方式可以更高效的利用物理資源。