k8s與存儲--flexvolume解讀

前言

k8s 非常厲害的地方就在於可擴展性,而存儲領域,支持flexvolume 和 csi 兩種方式來進行擴展。今天主要講下flexvolume。FlexVolume 是 Kubernetes v1.8+ 支持的一種存儲插件擴展方式。類似於 CNI 插件,它需要外部插件將二進制文件放到預先配置的路徑中(如 /usr/libexec/kubernetes/kubelet-plugins/volume/exec/),並需要在系統中安裝好所有需要的依賴。可以想到,這是一種out-tree的擴展方式,不需要新增加一種存儲插件,去更改k8s的源碼。

FlexVolume 接口

官方提供了一些接口,在我們實現自定義存儲插件的時候,需要實現部分接口,之所以說部分,主要是看自己的需求。比如我在實現動態hostpath(主機路徑包含podid)的時候,就只實現了init和mount和unmount三個接口而已。

FlexVolume 的接口包括

  • init:kubelet/kube-controller-manager 初始化存儲插件時調用,插件需要返回是否需要要 attach 和 detach 操作
  • attach:將存儲卷掛載到 Node 上
  • detach:將存儲卷從 Node 上卸載
  • waitforattach: 等待 attach 操作成功(超時時間爲 10 分鐘)
  • isattached:檢查存儲卷是否已經掛載
  • mountdevice:將設備掛載到指定目錄中以便後續 bind mount 使用
  • unmountdevice:將設備取消掛載
  • mount:將存儲卷掛載到指定目錄中
  • umount:將存儲卷取消掛載

Driver output

Flexvolume希望驅動程序以下列格式回覆操作狀態

{
    "status": "<Success/Failure/Not supported>",
    "message": "<Reason for success/failure>",
    "device": "<Path to the device attached. This field is valid only for attach & waitforattach call-outs>"
    "volumeName": "<Cluster wide unique name of the volume. Valid only for getvolumename call-out>"
    "attached": <True/False (Return true if volume is attached on the node. Valid only for isattached call-out)>
    "capabilities": <Only included as part of the Init response>
    {
        "attach": <True/False (Return true if the driver implements attach and detach)>
    }
}

與kubelet 的關係

前面講到自定義的存儲插件是放到/usr/libexec/kubernetes/kubelet-plugins/volume/exec/下,具體目錄是/usr/libexec/kubernetes/kubelet-plugins/volume/exec/<vendor~driver>/<driver>。
在pod的spec中申明用到了你自定義的插件後,格式爲 <vendor~driver>/<driver>,實際上是kubelet 按照接口規範去調用對應插件。
所以需要注意以下幾點:

  • 在debug的過程中,FlexVolume的日誌需要在kubelet.log中查看
  • 部署方式一般都是daemonset。這樣可以保證每臺node 都會存在自定義插件。

從k8s1.8 開始支持了動態插件發現,flexvolume支持動態檢測驅動程序的功能。系統運行時,可以安裝,升級/降級和卸載驅動程序,而不是在系統初始化時要求驅動程序存在或必須重新啓動kubelet或控制器管理器。

官方demo

官方提供一些demo,大家可以參考一下。

如何解決kubelet 經常發生找不到flexvolume 的bug

在實戰的過程中,我們的經常在使用自定義插件的時候,出現諸如一下報警:

Unable to mount volumes for pod "hermes-devices-push-myd-79f4577cc9-dqx9v_cbs(a0bc2b86-d140-11e9-9a8e-fa163e4660a0)": timeout expired waiting for volumes to attach or mount for pod "cbs"/"hermes-devices-push-myd-79f4577cc9-dqx9v". list of unmounted volumes=[log-dir]. list of unattached volumes=[log-dir default-token-kf6sr shareit-aksk-aws-conf shareit-aksk-huawei-conf]

其中的log-dir 正是用到了我們的自定義插件。

經過查看kubelet日誌,發現,kubelet出現了很多 no volume plugin matched 的錯誤信息。結合k8s的相關issue和分析kubelet代碼發現,這其實是kubelet的一個bug。可惜的是,這個bug一直沒有被解決。

當然可以每次發生找不到對應插件的時候,重啓kubelet即可。

但終究不是長久之計,通過研究代碼,其實動態發現插件的機制是通過inotify實現的,監聽了/usr/libexec/kubernetes/kubelet-plugins/volume/exec/目錄下的文件變化事件,做對應的處理。所以在有時候我們沒法去更改kubelet代碼的時候,我們可以在實現自定義插件的時候增加定時refresh的功能。比如我們更改一下對應驅動文件的最後訪問時間和修改時間。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章