天天看點

Flexvolume 介紹及使用

Prior to CSI, k8s volume plugins have to be “In-tree”, compiled and shipped with core kubernetes binaries. This means, it will require the storage providers to check-in their into the core k8s codebase if they wish to add the support for a new storage system.

在 CSI 之前,k8s 卷插件必須是“In-tree”,編譯并随核心 kubernetes 二進制檔案一起提供。這意味着,如果他們希望添加對新存儲系統的支援,則需要存儲提供商将其簽入核心 k8s 代碼庫。

A plugin-based solution, flex-volume, tried to address this issue by exposing the exec based API for external  plugins. Although it also tried to work on the similar notion of being detached with k8s binary, there were several major problems with that approach. Firstly, it needed the root access to the host and master file system to deploy the driver files. 

基于插件的解決方案 flex-volume 試圖通過為外部插件公開基于 exec 的 API 來解決這個問題。盡管它也嘗試處理與 k8s 二進制分離的類似概念,但這種方法存在幾個主要問題。首先,它需要對主機和主檔案系統的 root 通路權限來部署驅動程式檔案。 

Secondly, it comes with the huge baggage of prerequisites and OS dependencies which are assumed to be available on the host. CSI implicitly solves all these issues by being containerized and using the k8s storage primitives.

其次,它帶來了大量的先決條件和作業系統依賴項,假設它們在主機上可用。CSI 通過容器化和使用 k8s 存儲原語隐式地解決了所有這些問題。

Flexvolume 是 Volume Plugins 的一個擴充,主要實作 Attach/Detach/Mount/Unmount 這些接口。

我們知道這些功能本是由 Volume Plugins 實作的,但是對于某些存儲類型,我們需要将其擴充到 Volume Plugins 以外,是以我們需要把接口的具體實作放到外面。

在下圖中我們可以看到,Volume Plugins 其實包含了一部分 Flexvolume 的實作代碼,但這部分代碼其實隻有一個 “Proxy”的功能。

比如當 AD Controller 調用插件的一個 Attach 時,它首先會調用 Volume Plugins 中 Flexvolume 的 Attach 接口,但這個接口隻是把調用轉到相應的 Flexvolume 的Out-Of-Tree實作上。

Flexvolume是可被 Kubelet 驅動的可執行檔案,每一次調用相當于執行一次 shell 的 ls 這樣的腳本,都是可執行檔案的指令行調用,是以它不是一個常駐記憶體的守護程序。

Flexvolume 的 Stdout 作為 Kubelet 調用的傳回結果,這個結果需要是 JSON 格式。

Flexvolume預設的存放位址為 "/usr/libexec/kubernetes/kubelet-plugins/volume/exec/alicloud~disk/disk"。

[root@master nodeagent~uds]# pwd
/usr/libexec/kubernetes/kubelet-plugins/volume/exec/nodeagent~uds
[root@master nodeagent~uds]# ls
uds      
Flexvolume 介紹及使用

下面是一個指令格式和調用的執行個體。

Flexvolume 介紹及使用

Flexvolume 的接口介紹

Flexvolum 包含以下接口:

  • init: 主要做一些初始化的操作,比如部署插件、更新插件的時候做 init 操作,傳回的時候會傳回剛才我們所說的 DriveCapabilities 類型的資料結構,用來說明我們的 Flexvolume 插件有哪些功能;
  • GetVolumeName: 傳回插件名;
  • Attach: 挂載功能的實作。根據 --enable-controller-attach-detach 标簽來決定是由 AD Controller 還是 Kubelet 來發起挂載操作;
  • WaitforAttach: Attach 經常是異步操作,是以需要等待挂載完成,才能需要進行下面的操作;
  • MountDevice:它是 mount 的一部分。這裡我們将 mount 分為 MountDevice 和 SetUp 兩部分,MountDevice 主要做一些簡單的預處理工作,比如将裝置格式化、挂載到 GlobalMount 目錄中等;
  • GetPath:擷取每個 Pod 對應的本地挂載目錄;
  • Setup:使用 Bind 方式将 GlobalPath 中的裝置挂載到 Pod 的本地目錄;
  • TearDown、UnmountDevice、Detach實作的是上面一些借口的逆過程;
  • ExpandVolumeDevice:擴容存儲卷,由 Expand Controller 發起調用;
  • NodeExpand: 擴容檔案系統,由 Kubelet 發起調用。

上面這些接口不一定需要全部實作,如果某個接口沒有實作的話,可以将傳回結果定義成:

{

"status": "Not supported",

"message": "error message"

}

告訴調用者沒有實作這個接口。此外,Volume Plugins 中的 Flexvolume 接口除了作為一個 Proxy 外,它也提供了一些預設實作,比如 Mount 操作。是以如果你的 Flexvolume 中沒有定義該接口,該預設實作就會被調用。

在定義 PV 時可以通過 secretRef 字段來定義一些 secret 的功能。比如挂載時所需的使用者名和密碼,就可以通過 secretRef 傳入。

Flexvolume 的挂載分析

從挂載流程和解除安裝流程兩個方向來分析 Flexvolume 的挂載過程。

Flexvolume 介紹及使用

我們首先看 Attach 操作,它調用了一個遠端的 API 把我們的 Storage 挂載到目标節點中的某個裝置上去。

然後通過 MountDevice 将本地裝置挂載到 GlobalPath 中,同時也會做一些格式化這樣的操作。

Mount 操作(SetUp),它會把 GlobalPath 挂載 PodPath 中,PodPath 就是 Pod 啟動時所映射的一個目錄。

下圖給出了一個例子,比如我們一個雲盤,其 Volume ID 為 d-8vb4fflsonz21h31cmss,在執行完 Attach 和 WaitForAttach 操作之後,就會将其挂載到目标節點上的 /dec/vdc 裝置中。執行 MountDevice 之後,就會把上述裝置格式化,挂載到一個本地的 GlobalPath 中。而執行完 Mount 之後,就會将 GlobalPath 映射到 Pod 相關的一個子目錄中。最後執行 Bind 操作,将我們的本地目錄映射到容器中。這樣完成一次挂載過程。

Flexvolume 介紹及使用

解除安裝流程就是一個逆過程。上述過程描述的是一個塊裝置的挂載過程,對于檔案存儲類型,就無需 Attach、MountDevice操作,隻需要 Mount 操作,是以檔案系統的 Flexvolume 實作較為簡單,隻需要 Mount 和 Unmount 過程即可。

Flexvolume 的代碼示例

Flexvolume 介紹及使用

其中主要實作的是 init()、doMount()、doUnmount() 方法。在執行該腳本的時候對傳入的參數進行判斷來決定執行哪一個指令。

在 Github 上還有很多 Flexvolume 的示例,大家可以自行參考查閱。阿裡雲提供了一個 Flexvolume 的實作,有興趣的可以參考一下。(https://github.com/AliyunContainerService/flexvolume)

Flexvolume 的使用

下圖給出了一個 Flexvolume 類型的 PV 模闆。它和其它模闆實際上沒有什麼差別,隻不過類型被定義為 flexVolume 類型。flexVolume 中定義了 driver、fsType、options。

  • driver 定義的是我們實作的某種驅動,比如圖中的是 aliclound/disk,也可以是 aliclound/nas 等;
  • fsType 定義的是檔案系統類型,比如 "ext4";
  • options 包含了一些具體的參數,比如定義雲盤的 id 等。

我們也可以像其它類型一樣,通過 selector 中的 matchLabels 定義一些篩選條件。同樣也可以定義一些相應的排程資訊,比如定義 zone 為 cn-shenzhen-a。