Kubernetes卷插件從FlexVolume演變爲CSI

c-01.png

過去,當Kubernetes版本還很低(v1.0.0左右)時,就有了卷插件。他們須要將持久數據存儲卷鏈接到Kubernetes。當時數量還不多。 GCE PD,Ceph,AWS EBS和其餘一些存儲服務提供商都是最先的存儲提供商。json

一般,它們與Kubernetes綁定在一塊兒。所以,它們被稱爲「in-tree plugins」。可是,許多開發人員認爲可用插件是有侷限性的。所以,他們建立了本身的解決方案,經過補丁將它們集成到Kubernetes核心中,編譯了本身的Kubernetes版本並將其安裝在服務器上。可是隨着時間的流逝,Kubernetes開發人員已經意識到,您不能經過給「一我的一條魚」來解決問題-您必須教他「釣魚」。所以,他們決定在1.2.0版本中爲須要的人添加「釣魚竿」…bash

FlexVolume插件,或最小可行的「釣魚竿」

Kubernetes開發人員建立了FlexVolume插件,該插件是用於使用第三方FlexVolume驅動程序的變量和方法的邏輯封裝。 服務器

讓咱們仔細看看什麼是FlexVolume驅動程序。它是一個可執行文件(二進制文件,Python腳本,Bash腳本等),將命令行參數做爲輸入並以JSON格式返回包含預約義字段的消息。按照約定,第一個參數是方法,全部其餘參數是其參數。dom

c-02.png

FlexVolume驅動程序必須實現如下基本方法集:學習

flexvolume_driver mount # mounts volume to a directory in the pod  
# expected output:  
{  
  "status": "Success"/"Failure"/"Not supported",  
  "message": "<Reason for success/failure>",  
}

flexvolume_driver unmount # unmounts volume from a directory in the pod  
# expected output:  
{  
  "status": "Success"/"Failure"/"Not supported",  
  "message": "<Reason for success/failure>",  
}

flexvolume_driver init # initializes the plugin  
# expected output:  
{  
  "status": "Success"/"Failure"/"Not supported",  
  "message": "<Reason for success/failure>",  
  // defines if attach/detach methods are supported  
  "capabilities":{"attach": True/False}  
}

attachdetach方法肯定調用驅動程序時kubelet的行爲。一樣,有兩種特定的方法,expandvolumeexpandfs,它們容許動態調整卷大小。 您能夠在Rook Ceph運算符中使用咱們的pull請求,做爲expandvolume方法提供的更改的示例,以及動態調整卷大小的功能。flex

這是用於NFS的FlexVolume驅動程序的示例:google

usage() {  
    err "Invalid usage. Usage: "  
    err "\t$0 init"  
    err "\t$0 mount <mount dir> <json params>"  
    err "\t$0 unmount <mount dir>"  
    exit 1  
}

err() {  
    echo -ne $* 1>&2  
}

log() {  
    echo -ne $* >&1  
}

ismounted() {  
    MOUNT=`findmnt -n ${MNTPATH} 2>/dev/null | cut -d' ' -f1`  
    if [ "${MOUNT}" == "${MNTPATH}"]; then  
        echo "1"  
    else  
        echo "0"  
    fi  
}

domount() {  
    MNTPATH=$1
    
    NFS_SERVER=$(echo $2 | jq -r '.server')  
    SHARE=$(echo $2 | jq -r '.share')
    
    if[ $(ismounted) -eq 1] ; then  
        log '{"status": "Success"}'  
        exit 0  
    fi
    
    mkdir -p ${MNTPATH} &> /dev/nullmount -t nfs ${NFS_SERVER}:${SHARE} ${MNTPATH} &> /dev/null  
    if [ $? -ne 0]; then  
        err "{ \"status\": \"Failure\", \"message\": \"Failed to mount ${NFS_SERVER}:${SHARE} at ${MNTPATH}\"}"  
        exit 1  
    fi
    
    log '{"status": "Success"}'  
    exit 0  
}

unmount() {  
    MNTPATH=$1  
    if [ $(ismounted) -eq 0 ] ; then  
        log '{"status": "Success"}'  
        exit 0  
    fi
    
    umount ${MNTPATH} &> /dev/null  
    if [ $? -ne 0 ]; then  
        err "{ \"status\": \"Failed\", \"message\": \"Failed to unmount volume at ${MNTPATH}\"}"  
        exit 1  
    fi
    
    log '{"status": "Success"}'  
    exit 0  
}

op=$1

if [ "$op" = "init" ]; then  
    log '{"status": "Success", "capabilities": {"attach": false}}'  
    exit 0  
fi

if [ $# -lt 2 ]; then  
    usage  
fi

shift

case "$op" in  
    mount)  
        domount $*  
        ;;  
    unmount)  
        unmount $*  
        ;;  
    *)  
        log '{"status": "Not supported"}'  
        exit 0  
esac

exit 1

建立可執行文件後,必須將驅動程序部署到Kubernetes集羣。該驅動程序必須存在於每一個羣集節點上的預約義路徑中。默認路徑是
/usr/libexec/kubernetes/kubelet-plugins/volume/exec/vendor_name〜driver_name/spa

…可是,路徑可能在各類Kubernetes發行版(OpenShift,Rancher等)中有所不一樣。插件

FlexVolume規約

將FlexVolume驅動程序部署到羣集節點是一項艱鉅的任務。您能夠手動執行此操做,可是,因爲添加新節點,自動水平縮放,或者因爲節點故障而替換節點時,羣集中出現新節點的可能性很高。在這種狀況下,除非在此處手動複製FlexVolume驅動程序,不然根本不可能在這些節點上使用永久性存儲。命令行

可是,Kubernetes的資源之一DaemonSet能夠解決此問題。在集羣中建立新節點時,它將自動獲取DaemonSet中定義的新容器。而後,將本地卷安裝到與FlexVolume驅動程序的路徑匹配的本地目錄中。成功建立後,Pod將驅動程序所需的文件複製到磁盤。

這是用於部署FlexVolume插件的DaemonSet的示例:

c-03.jpg

以及用於複製FlexVolume驅動程序的Bash腳本示例:

c-04.jpg

請注意,複製操做不是原子操做。在kubelet的準備過程完成以前,確實存在kubelet開始使用該驅動程序的風險,從而致使錯誤。正確的方法是使用不一樣的名稱複製驅動程序文件,而後重命名它們(由於重命名操做是原子的)。

c-05.png

使用FlexVolume驅動程序時的下一個問題是,您必須爲大多數類型的卷安裝一些先決條件(例如,用於Ceph的ceph-common軟件包)。最初,FlexVolume插件並非爲如此複雜的系統設計的。

針對Rook運算符的FlexVolume驅動程序實現了針對此問題的創新解決方案。驅動程序自己是RPC客戶端。用於通訊的IPC套接字位於驅動程序的目錄中。如上所述,DaemonSet是交付驅動程序文件的理想選擇,由於它會自動將Rook驅動程序做爲卷掛載目錄。複製完成後,此Pod經過已安裝的卷做爲功能齊全的RPC服務器鏈接到IPC套接字。 ceph-common軟件包已經安裝在pod的容器中。 IPC套接字確保kubelet將與同一節點中的相應pod通訊。很棒的主意,不是嗎?

in-tree 插件的問題

在某個時候,Kubernetes開發人員發現有20個用於存儲卷的in-tree插件。它們中的每一個(甚至很小)更改都必須通過整個Kubernetes發行週期。

事實證實,您必須更新整個集羣才能使用新的插件版本!此外,您可能會遇到不愉快的驚喜:新的Kubernetes版本可能與當前的Linux內核不兼容!所以,您擦乾眼淚,懇求老闆和客戶得到更新Linux內核和Kubernetes集羣的許可(可能會致使停機)…

這不是很奇怪又有趣嗎?隨着時間的流逝,對於整個社區來講,現有的方法已經行不通了。所以,Kubernetes開發人員已決定中止在覈心中包含新的卷插件。

CSI是核心中包含的最後一個插件,旨在完全解決持久性存儲的問題。 Kubernetes 1.9中宣佈了其alpha版本,簡稱爲Out-of-Tree CSI卷插件。

容器存儲接口(CSI)

首先,咱們要強調的是,CSI不是一個卷插件,它是用於建立自定義組件以與數據存儲一塊兒使用的成熟標準。容器編排系統(例如Kubernetes和Mesos)應該「學習」如何使用根據此標準實現組件。好吧,Kubernetes已經成功作到了。

Kubernetes CSI插件如何工做? CSI插件使用由第三方開發人員建立的自定義驅動程序(CSI驅動程序)。 Kubernetes的CSI驅動程序必須至少包含如下兩個組件(pod):

  • Controller。管理持久性外部卷的控制器。它使用StatefulSet部署形式實現爲gRPC服務器。
  • Node。將持久性外部卷安裝到羣集節點的節點。它還基於DaemonSet部署形式實現爲gRPC服務器。

c-07.png

您能夠在本文中得到有關其工做原理的更多詳細信息:瞭解CSI。

這種方法的優勢

  • 對於基本活動-例如在節點中註冊驅動程序-Kubernetes開發人員實現了一組容器。您再也不須要手動生成具備功能的JSON響應(就像FlexVolume插件同樣)。
  • 咱們沒有將Pod部署到節點上,而是將Pod部署到了集羣上。這就是咱們對Kubernetes的指望:一切都發生在經過Kubernetes部署的容器內部。
  • 要建立複雜的驅動程序,您再也不須要開發RPC服務器和RPC客戶端。該客戶端已經由K8s開發人員實現。
  • 經過gRPC協議傳遞參數比經過命令行參數傳遞參數更加方便,靈活和可靠。若是您想學習如何經過添加標準化的gRPC方法將容量指標支持添加到CSI,能夠以咱們對vsphere-csi驅動程序的拉取請求爲例。
  • 通訊經過IPC套接字進行,以確保kubelet請求的正確性。

您以爲這個清單熟悉嗎?正確,CSI的優點彌補了FlexVolume插件的不足。

結論

做爲建立用於數據存儲的自定義插件的標準,CSI受到了社區的熱烈歡迎。此外,因爲其優點和多功能性,甚至對於Ceph或AWS EBS也已經實現了CSI驅動程序,而Ceph或AWS EBS以前已經擁有本身的插件(從一開始就集成到Kubernetes中)。

在2019年初,in-tree插件被宣佈棄用。 Kubernetes開發人員將維護FlexVolume插件,可是新功能只會添加到CSI,而不會添加到FlexVolume。

相關文章
相關標籤/搜索