天天看點

kubernetes/k8s CSI分析-容器存儲接口分析

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對象,接下來會一一進行分析。

kubernetes/k8s CSI分析-容器存儲接口分析

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
           

涉及元件與作用

kubernetes/k8s CSI分析-容器存儲接口分析

下面來介紹下涉及的元件與作用。

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的流程

kubernetes/k8s CSI分析-容器存儲接口分析

(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為例。

kubernetes/k8s CSI分析-容器存儲接口分析

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. 存儲建立

流程圖

kubernetes/k8s CSI分析-容器存儲接口分析

流程分析

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. 存儲擴容

kubernetes/k8s CSI分析-容器存儲接口分析

(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

kubernetes/k8s CSI分析-容器存儲接口分析

kubelet

--enable-controller-attach-detach=false

kubelet

volume manager

Attach/Detach

kubernetes/k8s CSI分析-容器存儲接口分析

(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

kubernetes/k8s CSI分析-容器存儲接口分析

kubelet

--enable-controller-attach-detach=false

kubelet

volume manager

Attach/Detach

kubernetes/k8s CSI分析-容器存儲接口分析

(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. 删除存儲

kubernetes/k8s CSI分析-容器存儲接口分析

(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 CSI分析-容器存儲接口分析

關聯部落格:kubernetes/k8s CRI分析-容器運作時接口分析

繼續閱讀