kubernetes CSI分析-k8s CSI分析。kubernetes中有3個功能接口,分别是容器網絡接口CNI、容器運作時接口CRI和容器存儲接口CSI。本文會對CSI是什麼、為什麼要有CSI、CSI系統架構做介紹,對CSI所涉及的k8s對象與元件進行介紹,以及k8s對CSI存儲進行相關操作分析
更多 k8s CSI 的分析,可以檢視這篇部落格kubernetes ceph-csi分析,以 ceph-csi 為例,做了詳細的源碼分析。
其他關聯部落格:kubernetes/k8s CRI分析-容器運作時接口分析
kubernetes/k8s CNI分析-容器網絡接口分析
概述
kubernetes的設計初衷是支援可插拔架構,進而利于擴充
kubernetes
的功能。在此架構思想下,
kubernetes
提供了3個特定功能的接口,分别是容器網絡接口
CNI
、容器運作時接口
CRI
和容器存儲接口
CSI
。
kubernetes
通過調用這幾個接口,來完成相應的功能。
下面我們來對容器存儲接口
CSI
來做一下介紹與分析。
在本文中,會對
CSI
是什麼、為什麼要有
CSI
、
CSI
系統架構做一下介紹,然後對
CSI
所涉及的
k8s
對象與元件進行了簡單的介紹,以及
k8s
對
CSI
存儲進行相關操作的流程分析,存儲相關操作包括了存儲建立、存儲擴容、存儲挂載、解除存儲挂載以及存儲删除操作。
CSI是什麼
CSI是
Container Storage Interface
(容器存儲接口)的簡寫。
CSI的目的是定義行業标準“容器存儲接口”,使存儲供應商(SP)能夠開發一個符合CSI标準的插件并使其可以在多個容器編排(CO)系統中工作。CO包括
Cloud Foundry
,
Kubernetes
Mesos
等。
kubernetes将通過
CSI
接口來跟第三方存儲廠商進行通信,來操作存儲,進而提供容器存儲服務。
為什麼要有CSI
其實在沒有
CSI
之前
kubernetes
就已經提供了強大的存儲卷插件系統,但是這些插件系統實作是
kubernetes
代碼的一部分,需要随
kubernetes
元件二進制檔案一起釋出,這樣就會存在一些問題。
(1)如果第三方存儲廠商發現有問題需要修複或者優化,即使修複後也不能單獨釋出,需要與
kubernetes
一起釋出,對于
k8s
本身而言,不僅要考慮自身的正常疊代發版,還需要考慮到第三方存儲廠商的疊代發版,這裡就存在雙方互相依賴、制約的問題,不利于雙方快速疊代;
(2)另外第三方廠商的代碼跟
kubernetes
代碼耦合在一起,還會引起安全性、可靠性問題,還增加了
kubernetes
代碼的複雜度以及後期的維護成本等等。
基于以上問題,
kubernetes
将存儲體系抽象出了外部存儲元件接口即
CSI
,
kubernetes
通過
grpc
接口與第三方存儲廠商的存儲卷插件系統進行通信。
這樣一來,對于第三方存儲廠商來說,既可以單獨釋出和部署自己的存儲插件,進行正常疊代,而又無需接觸
kubernetes
核心代碼,降低了開發的複雜度。同時,對于
kubernetes
來說,這樣不僅降低了自身的維護成本,還能為使用者提供更多的存儲選項。
CSI系統架構
這是一張k8s csi的系統架構圖,圖中所畫的元件以及k8s對象,接下來會一一進行分析。
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIn5GcuQzM5EzN5EjMz0yN4gTOwEzM2EDNycDMxIDMy0yNwAzM5MjMvw1NwEjMwIzLcdDMwMTOzIzLcd2bsJ2Lc12bj5ycn9Gbi52YuAjMwIzZtl2Lc9CX6MHc0RHaiojIsJye.png)
CSI相關元件一般采用容器化部署,減少環境依賴。
涉及k8s對象
1. PersistentVolume
持久存儲卷,叢集級别資源,代表了存儲卷資源,記錄了該存儲卷資源的相關資訊。
回收政策
(1)retain:保留政策,當删除pvc的時候,保留pv與外部存儲資源。
(2)delete:删除政策,當與pv綁定的pvc被删除的時候,會從k8s叢集中删除pv對象,并執行外部存儲資源的删除操作。
(3)resycle(已廢棄)
pv狀态遷移
available --> bound --> released
2. PersistentVolumeClaim
持久存儲卷聲明,namespace級别資源,代表了使用者對于存儲卷的使用需求聲明。
示例:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: test
namespace: test
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 10Gi
storageClassName: csi-cephfs-sc
volumeMode: Filesystem
pvc狀态遷移
pending --> bound
3. StorageClass
定義了建立pv的模闆資訊,叢集級别資源,用于動态建立pv。
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: csi-rbd-sc
parameters:
clusterID: ceph01
imageFeatures: layering
imageFormat: "2"
mounter: rbd
pool: kubernetes
provisioner: rbd.csi.ceph.com
reclaimPolicy: Delete
volumeBindingMode: Immediate
4. VolumeAttachment
VolumeAttachment 記錄了pv的相關挂載資訊,如挂載到哪個node節點,由哪個volume plugin來挂載等。
AD Controller 建立一個 VolumeAttachment,而 External-attacher 則通過觀察該 VolumeAttachment,根據其狀态屬性來進行存儲的挂載和解除安裝操作。
apiVersion: storage.k8s.io/v1
kind: VolumeAttachment
metadata:
name: csi-123456
spec:
attacher: cephfs.csi.ceph.com
nodeName: 192.168.1.10
source:
persistentVolumeName: pvc-123456
status:
attached: true
5. CSINode
CSINode 記錄了csi plugin的相關資訊(如nodeId、driverName、拓撲資訊等)。
當Node Driver Registrar向kubelet注冊一個csi plugin後,會建立(或更新)一個CSINode對象,記錄csi plugin的相關資訊。
apiVersion: storage.k8s.io/v1
kind: CSINode
metadata:
name: 192.168.1.10
spec:
drivers:
- name: cephfs.csi.ceph.com
nodeID: 192.168.1.10
topologyKeys: null
- name: rbd.csi.ceph.com
nodeID: 192.168.1.10
topologyKeys: null
涉及元件與作用
下面來介紹下涉及的元件與作用。
1. volume plugin
擴充各種存儲類型的卷的管理能力,實作第三方存儲的各種操作能力與k8s存儲系統的結合。調用第三方存儲的接口或指令,進而提供資料卷的建立/删除、attach/detach、mount/umount的具體操作實作,可以認為是第三方存儲的代理人。前面分析元件中的對于資料卷的建立/删除、attach/detach、mount/umount操作,全是調用volume plugin來完成。
根據源碼所在位置,volume plugin分為in-tree與out-of-tree。
in-tree
在k8s源碼内部實作,和k8s一起釋出、管理,更新疊代慢、靈活性差。
out-of-tree
代碼獨立于k8s,由存儲廠商實作,有csi、flexvolume兩種實作。
csi plugin
csi plugin分為ControllerServer與NodeServer,各負責不同的存儲操作。
external plugin
external plugin包括了external-provisioner、external-attacher、external-resizer、external-snapshotter等,external plugin輔助csi plugin元件,共同完成了存儲相關操作。external plugin負責watch pvc、volumeAttachment等對象,然後調用volume plugin來完成存儲的相關操作。如external-provisioner watch pvc對象,然後調用csi plugin來建立存儲,最後建立pv對象;external-attacher watch volumeAttachment對象,然後調用csi plugin來做attach/dettach操作;external-resizer watch pvc對象,然後調用csi plugin來做存儲的擴容操作等。
Node-Driver-Registrar
Node-Driver-Registrar元件負責實作csi plugin(NodeServer)的注冊,讓kubelet感覺csi plugin的存在。
元件部署方式
csi plugin controllerServer與external plugin作為容器,使用deployment部署,多副本可實作高可用;而csi plugin NodeServer與Node-Driver-Registrar作為容器,使用daemonset部署,即每個node節點都有。
2. kube-controller-manager
PV controller
負責pv、pvc的綁定與生命周期管理(如建立/删除底層存儲,建立/删除pv對象,pv與pvc對象的狀态變更)。
(1)in-tree:建立/删除底層存儲、建立/删除pv對象的操作,由PV controller調用volume plugin(in-tree)來完成。
(2)out-tree CSI:建立/删除底層存儲、建立/删除pv對象的操作由external-provisioner與csi plugin共同來完成。
AD controller
AD Cotroller全稱Attachment/Detachment 控制器,主要負責建立、删除VolumeAttachment對象,并調用volume plugin來做儲存設備的Attach/Detach操作(将資料卷挂載到特定node節點上/從特定node節點上解除挂載),以及更新node.Status.VolumesAttached等。
不同的volume plugin的Attach/Detach操作邏輯有所不同,對于csi plugin(out-tree volume plugin)來說,AD controller的Attach/Detach操作隻是修改VolumeAttachment對象的狀态,而不會真正的将資料卷挂載到節點/從節點上解除挂載,真正的節點存儲挂載/解除挂載操作由kubelet中volume manager調用csi plugin來完成。
3. kubelet
volume manager
主要是管理卷的Attach/Detach(與AD controller作用相同,通過kubelet啟動參數控制哪個元件來做該操作)、mount/umount等操作。
對于csi來說,volume manager的Attach/Detach操作隻建立/删除VolumeAttachment對象,而不會真正的将資料卷挂載到節點/從節點上解除挂載;csi-attacer元件也不會做挂載/解除挂載操作,隻是更新VolumeAttachment對象,真正的節點存儲挂載/解除挂載操作由kubelet中volume manager調用調用csi plugin來完成。
kubernetes建立與挂載volume(in-tree volume plugin)
先來看下kubernetes通過in-tree volume plugin來建立與挂載volume的流程
(1)使用者建立
pvc
;
(2)
PV controller
watch到
pvc
的建立,尋找合适的
pv
與之綁定。
(3)(4)當找不到合适的
pv
時,将調用
volume plugin
來建立volume,并建立
pv
對象,之後該
pv
對象與
pvc
對象綁定。
(5)使用者建立挂載
pvc
的
pod
(6)
kube-scheduler
pod
的建立,為其尋找合适的node排程。
(7)(8)
pod
排程完成後,
AD controller
/
volume manager
pod
聲明的volume沒有進行
attach
操作,将調用
volume plugin
來做
attach
操作。
(9)
volume plugin
進行
attach
操作,将volume挂載到
pod
所在node節點,成為如
/dev/vdb
的裝置。
(10)(11)
attach
操作完成後,
volume manager
pod
mount
volume plugin
mount
(12)
volume plugin
mount
操作,将node節點上的第(9)步得到的
/dev/vdb
裝置挂載到指定目錄。
kubernetes建立與挂載volume(out-of-tree volume plugin)
再來看下kubernetes通過out-of-tree volume plugin來建立與挂載volume的流程,以csi-plugin為例。
pvc
PV controller
pvc
pv
與之綁定。當尋找不到合适的
pv
時,将更新
pvc
對象,添加
annotation
:
volume.beta.kubernetes.io/storage-provisioner
,讓
external-provisioner
元件開始開始建立存儲與
pv
對象的操作。
(3)
external-provisioner
元件watch到
pvc
的建立/更新事件,判斷
annotation
volume.beta.kubernetes.io/storage-provisioner
的值,即判斷是否是自己來負責做建立操作,是則調用
csi-plugin ControllerServer
來建立存儲,并建立
pv
對象(這裡的
pv
對象使用了提前綁定特性,将
pvc
資訊填入了
pv
對象的
spec.claimRef
屬性)。
(4)
PV controller
将上一步建立的
pv
與
pvc
綁定。
pvc
pod
kube-scheduler
pod
的建立,為其尋找合适的
node
排程。
pod
AD controller
volume manager
pod
attach
csi-attacher
attach
操作(實際上隻是建立
volumeAttachement
對象)。
external-attacher
volumeAttachment
對象的建立,調用
csi-plugin
attach
操作(如果
volume plugin
是
ceph-csi
external-attacher
volumeAttachment
對象的建立後,隻是修改該對象的狀态屬性,不會做
attach
操作,真正的
attach
操作由
kubelet
中的
volume manager
調用
volume plugin
ceph-csi
來完成)。
(10)
csi-plugin ControllerServer
attach
pod
所在
node
節點,成為如
/dev/vdb
(11)(12)
attach
volume manager
pod
mount
csi-mounter
mount
(13)
csi-mounter
csi-plugin NodeServer
mount
操作,将node節點上的第(10)步得到的
/dev/vdb
kubernetes存儲相關操作流程具體分析(out-of-tree volume plugin,以csi plugin:ceph-csi為例)
下面來看下
kubernetes
ceph-csi volume plugin
來建立/删除、挂載/解除挂載ceph存儲的流程。
1. 存儲建立
流程圖
流程分析
pvc
對象;
pv controller
監聽
pvc
對象,尋找現存的合适的
pv
對象,與
pvc
對象綁定。當找不到現存合适的
pv
對象時,将更新
pvc
annotation
volume.beta.kubernetes.io/storage-provisioner
external-provisioner
pv
對象的操作;當找到時,将
pvc
pv
綁定,結束操作。
external-provisioner
元件監聽到
pvc
的新增事件,判斷
pvc
annotation
volume.beta.kubernetes.io/storage-provisioner
ceph-csi
元件進行存儲的建立;
ceph-csi
元件調用ceph建立底層存儲;
(5)底層存儲建立完成後,
external-provisioner
根據存儲資訊,拼接
pv
對象,建立
pv
pv
pvc
pv
spec.claimRef
屬性);
pv controller
pvc
對象,将第(5)步建立的
pv
pvc
2. 存儲擴容
(1)修改
pvc
對象,修改申請存儲大小(
pvc.spec.resources.requests.storage
);
(2)修改成功後,
external-resizer
監聽到該
pvc
update
事件,發現
pvc.Spec.Resources.Requests.storgage
比
pvc.Status.Capacity.storgage
大,于是調
ceph-csi
元件進行 controller端擴容;
ceph-csi
元件調用ceph存儲,進行底層存儲擴容;
(4)底層存儲擴容完成後,
ceph-csi
元件更新
pv
.Spec.Capacity.storgage
的值為擴容後的存儲大小;
(5)
kubelet
volume manager
在
reconcile()
調諧過程中發現
pv.Spec.Capacity.storage
大于
pvc.Status.Capacity.storage
,于是調
ceph-csi
元件進行 node端擴容;
ceph-csi
元件對node上存儲對應的檔案系統擴容;
(7)擴容完成後,
kubelet
更新
pvc.Status.Capacity.storage
的值為擴容後的存儲大小。
3. 存儲挂載
kubelet啟動參數
--enable-controller-attach-detach
,該啟動參數設定為
true
表示啟用
Attach/Detach controller
Attach/Detach
操作,同時禁用
kubelet
執行
Attach/Detach
操作(預設值為
true
)。實際上
Attach/Detach
操作就是建立/删除
VolumeAttachment
對象。
(1)
kubelet
啟動參數
--enable-controller-attach-detach=true
Attach/Detach controller
Attach/Detach
kubelet
--enable-controller-attach-detach=false
kubelet
端
volume manager
Attach/Detach
(1)使用者建立一個挂載了
pvc
pod
AD controller
或
volume manager
reconcile()
發現有
volume
未執行
attach
操作,于是進行
attach
操作,即建立
VolumeAttachment
external-attacher
元件
list/watch
VolumeAttachement
對象,更新
VolumeAttachment.status.attached=true
AD controller
node
.Status.VolumesAttached
屬性值,将該
volume
記為
attached
kubelet
volume manager
擷取
node.Status.VolumesAttached
屬性值,發現
volume
已被标記為
attached
(6)于是
volume manager
reconcile()
ceph-csi
元件的
NodeStageVolume
NodePublishVolume
完成存儲的挂載。
4. 解除存儲挂載
kubelet
--enable-controller-attach-detach=true
Attach/Detach controller
Attach/Detach
kubelet
--enable-controller-attach-detach=false
kubelet
volume manager
Attach/Detach
(1)使用者删除聲明了
pvc
pod
AD controller
volume manager
reconcile()
volume
dettach
dettach
操作,即删除
VolumeAttachment
AD controller
volume manager
等待
VolumeAttachment
對象删除成功;
AD controller
node
.Status.VolumesAttached
屬性值,将标記為
attached
的該
volume
從屬性值中去除;
kubelet
volume manager
node.Status.VolumesAttached
屬性值,找不到相關的
volume
資訊;
volume manager
reconcile()
ceph-csi
NodeUnpublishVolume
NodeUnstageVolume
完成存儲的解除挂載操作。
5. 删除存儲
(1)使用者删除
pvc
pv controller
發現與
pv
綁定的
pvc
對象被删除,于是更新
pv
的狀态為
released
external-provisioner
pv
更新事件,并檢查
pv
的狀态是否為
released
,以及回收政策是否為
delete
(4)确認了
pv
對象的狀态以及回收政策之後,接下來
external-provisioner
元件會調用
ceph-csi
DeleteVolume
來删除存儲;
ceph-csi
DeleteVolume
方法,調用ceph叢集指令,删除底層存儲;
(6)删除底層存儲後,
external-provisioner
元件删除
pv
總結
CSI即
Container Storage Interface
(容器存儲接口)。
為了解決第三方存儲廠商的存儲卷插件代碼內建到kubernetes代碼中所帶來的各種問題,
kubernetes
CSI
kubernetes
grpc
接口與第三方存儲廠商的存儲卷插件系統進行通信,來操作存儲,進而提供容器存儲服務。
kubernetes
kubernetes
最後,再來回顧一下kubernetes CSI的架構。
關聯部落格:kubernetes/k8s CRI分析-容器運作時接口分析