
容器儲存介面(Container Storage Interface, CSI)是 Kubernetes 在 1.9 版時為了解決以下議題所提出來的機制。
K8s 既有的 Volume plugin 是 in-tree 的,代表 plugin 的原始碼位於於 K8s 的 repository 中,這讓 plugin 除了在開發時需要對 K8s 的專案發出 pull request 才能將 commits 合併外,plugin 也會隨著 K8s repository 一起編譯成執行檔,這不只需要讓第三方 volume plugin 開發人員需要參與進 K8s 的開發過程,更讓 plugin 的更新。
特定的 volume plugin 需要在 K8s 的節點上安裝套件,如欲使用 Ceph 的 Block Device 作為 K8s 上的 volume 時,必須在 node 上使用套件管理工具安裝 ceph-common 才能正常掛載 RBD image,這使得我們在必須建立 K8s 叢集前就先將安裝套件的 script 寫入部署工具或著在需要前再連線至 node 中安裝, 而理想的狀況是 plugin 的依賴可以整合進容器中,隨著 Pod 建立即擁有掛載 volume 的能力而不必處理依賴關係。
單節點的 hostPath CSI driver

在開始使用 CSI 前,必須確認 kubelet 和 api-server 在啟動時加入 –allow-privileged=true 的 flag,讓 Pod 可以運行在 privileged 模式。
1.建立 Pod
$ kubectl create -f https://raw.githubusercontent.com/kubernetes-csi/docs/master/book/src/example/csi-setup.yaml
storageclass "csi-hostpath-sc" created
serviceaccount "csi-service-account" created
clusterrole "csi-cluster-role" created
clusterrolebinding "csi-role-binding" created
pod "csi-pod" created
我們可以看到 YMAL 檔中除了 hostPath 的 CSI driver 外,還有三個由 K8s 官方所提供 sidecar 容器:external-attacher、external-provisioner 和 driver-registrar,它們的作用分別是:
- external-attacher
關注 K8s 叢集的 VolumeAttachment 物件,當有物件產生時在 Pod 中透過 unix domain socket 對 CSI driver 進行 gRPC 呼叫 ControllerPublish 和 ControllerUnpublish。在 hostPath 的 CSI driver 中並未實作以上函數。
- external-provisioner
關注 K8s 叢集的 PersistentVolumeClaim 物件,當有物件產生時在 Pod 中透過 unix domain socket 對 hostPath CSI driver 進行 gRPC 呼叫 CreateVolume 和 DeleteVolume。在 hostPath 的 CSI driver 中 CreateVolume 在 driver 所在的 node 上建立了所需的資料夾;DeleteVolume 則在 刪除了指定的資料夾。
- driver-registrar
將 CSI driver 自訂的 NodeID 到增加到所屬 K8s 節點的 annotation 中。
$ kubectl describe no/k8s-01
...
Annotations: csi.volume.kubernetes.io/nodeid={"csi-hostpath":"k8s-01"}
...
2.建立 PersistentVolumeClaim
$ kubectl create -f https://raw.githubusercontent.com/kubernetes-csi/docs/master/book/src/example/csi-pvc.yaml
persistentvolumeclaim "csi-pvc" created
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
csi-pvc Bound pvc-c84b83e188d711e8 1Gi RWO csi-hostpath-sc 6s
建立了 PVC 後,動態建立了 PV。
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-c84b83e188d711e8 1Gi RWO Delete Bound default/csi-pvc csi-hostpath-sc 4s
發現 PVC 物件的建立後,external provisioner 便在 hostpath-driver 容器中的 /tmp 目錄下建立了資料夾
$ kubectl exec -it csi-pod -c hostpath-driver -- /bin/sh
$ ls -l /tmp
total 4
drwxr-xr-x 2 root root 4096 Jul 16 09:08 c85f4370-88d7-11e8-b7ad-0a580ae94006
3.建立 Pod 掛載 PVC
$ kubectl create -f https://raw.githubusercontent.com/kubernetes-csi/docs/master/book/src/example/csi-app.yaml
pod "my-csi-app" created
4.寫入檔案至 volume 中並檢查是否寫入至 hostpath-driver 容器中
$ kubectl exec -it my-csi-app /bin/sh
/ # touch /data/test.txt
$ kubectl exec -it csi-pod -c hostpath-driver -- /bin/sh
/ # cd /tmp/c85f4370-88d7-11e8-b7ad-0a580ae94006/
/tmp/c85f4370-88d7-11e8-b7ad-0a580ae94006 # ls
test.txt
參考資料
- Introducing Container Storage Interface (CSI) Alpha for Kubernetes – Kubernetes
- Introduction – Kubernetes CSI Documentation
撰文: 杜永鴻 迎棧科技工程師