2019-05-06 更新
目前在 NFS storage 的部份,已經變成 NFS Provisioner
& NFS-Client Provisioner
兩種了:
若有 NFS external storage 的需求,可以參考上面新的連結來設定,新的方法已經改用 Helm 來管理,佈署安裝的流程變得相當簡單
前言
之前有介紹過 StorageClass 搭配 GlusterFS + Heketi 作為後端的 storage,但 GlusterFS 可能對很多人來說還是有點複雜,因此想說介紹一個比較容易入門的 storage,學習 k8s 的過程才不會覺得很艱難。
只要用過 Linux,大概 NFS 幾乎就會是個必學的服務,因此這邊要介紹以 NFS 作為 StorageClass 後端 storage 的設定方式,讓 k8s 可以動態的在 NFS share 上產生所需要 volume 來使用。
運作原理說明
基本上要正確設定 StorageClass + NFS,大概要準備以下幾個東西:
一個可用的 NFS share
NFS provisioner
:主要有兩個工作,一個是實際在 NFS share 中建立 volume(其實就是一般的 directory),另一個則是建立 PV,並與 NFS volume 作繫結
Service Account
:這是用來管控 NFS provisioner 在 k8s 中可以運行的權限
StorageClass
:負責建立 PVC 並呼叫 NFS provisioner 進行設定工作,並讓 PVC 與 PV 繫結
詳細的運作流程可以參考下圖:
設定過程
設定 NFS share
這個部份就留給大家自己去作了,網路上有非常多的教學可以查。
假設這裡使用以下的 NFS share:
設定 Service Account & 對應權限
如果要精準的管理權限,那就必須要自訂一個 service account 並搭配 k8s 中的 RBAC 機制來進行設定。
在以下的範例中會完成兩件事情:
新增 service account nfs-client-provisioner
,作為 NFS provisioner 的權限來源
在 k8s 中有賦予 service account 足夠的權限處理跟 StorageClass & PersistentVolumeClaim 相關的工作 (透過 Role + RoleBinding + ClusterRole + ClusterRoleBinding)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| --- apiVersion: v1 kind: ServiceAccount metadata: name: nfs-client-provisioner
--- kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: nfs-client-provisioner-runner rules: - apiGroups: [""] resources: ["persistentvolumes"] verbs: ["get", "list", "watch", "create", "delete"] - apiGroups: [""] resources: ["persistentvolumeclaims"] verbs: ["get", "list", "watch", "update"] - apiGroups: ["storage.k8s.io"] resources: ["storageclasses"] verbs: ["get", "list", "watch"] - apiGroups: [""] resources: ["events"] verbs: ["create", "update", "patch"]
--- kind: ClusterRoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: run-nfs-client-provisioner subjects: - kind: ServiceAccount name: nfs-client-provisioner roleRef: kind: ClusterRole name: nfs-client-provisioner-runner apiGroup: rbac.authorization.k8s.io
--- kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: leader-locking-nfs-client-provisioner rules: - apiGroups: [""] resources: ["endpoints"] verbs: ["get", "list", "watch", "create", "update", "patch"]
--- kind: RoleBinding apiVersion: rbac.authorization.k8s.io/v1 metadata: name: leader-locking-nfs-client-provisioner subjects: - kind: ServiceAccount name: nfs-client-provisioner roleRef: kind: Role name: leader-locking-nfs-client-provisioner apiGroup: rbac.authorization.k8s.io
|
安裝 NFS provisioner
NFS provisioner 負責以下工作:
在 NFS share 中產生 volume(directory)
新增 PV
告知 PVC 已經完成 PV 的設定,讓 PVC 與 PV 繫結
使用以下的設定檔佈署 NFS provisioner
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| kind: Deployment apiVersion: extensions/v1beta1 metadata: name: nfs-client-provisioner spec: replicas: 1 strategy: type: Recreate template: metadata: labels: app: nfs-client-provisioner spec: serviceAccountName: nfs-client-provisioner containers: - name: nfs-client-provisioner image: quay.io/external_storage/nfs-client-provisioner:latest volumeMounts: - name: nfs-client-root mountPath: /persistentvolumes env: - name: PROVISIONER_NAME value: my-nfs-provisioner - name: NFS_SERVER value: 10.1.2.3 - name: NFS_PATH value: /var/k8s-nfs-share volumes: - name: nfs-client-root nfs: server: 10.1.2.3 path: /var/k8s-nfs-share
|
建立 StorageClass
透過以下設定檔,建立 StorageClass 來使用上面所佈署好的 NFS provisioner:
1 2 3 4 5 6 7
| apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: my-nfs-storage provisioner: my-nfs-provisioner parameters: archiveOnDelete: "false"
|
以上的設定都佈署完之後,就可以在系統中看到 StorageClass 出現:
1 2 3 4
| $ kubectl get storageclass NAME PROVISIONER AGE ... (略) my-nfs-storage my-nfs-provisioner 5h10m
|
驗證佈署是否成功
驗證的步驟如下:
建立 PVC,指定上面所設定好的 StorageClass
建立 Pod,使用上一個步驟設定好的 PVC
建立 PVC
使用下面的設定來建立一個測試用的 PVC:
1 2 3 4 5 6 7 8 9 10 11 12 13
| --- kind: PersistentVolumeClaim apiVersion: v1 metadata: name: test-claim annotations: volume.beta.kubernetes.io/storage-class: "my-nfs-storage" spec: accessModes: - ReadWriteMany resources: requests: storage: 1Mi
|
如果可以從系統中看到 PVC Status 為 Bound
就表示建立成功了:
1 2 3 4 5 6 7 8 9
| $ kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE test-claim Bound pvc-052b8e95-d8f4-11e8-9dda-54ab3a09ec1d 1Mi RWX my-nfs-storage 5s
$ kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pvc-052b8e95-d8f4-11e8-9dda-54ab3a09ec1d 1Mi RWX Delete Bound default/test-claim managed-nfs-storage 2m46s
|
上面的訊息表示 StorageClass 成功完成了以下幾件工作:
在 NFS share 上建立 volume
建立 PV,並與上述的 NFS volume 作繫結
將 PVC 與 PV 繫結
建立 Pod
最後就是建立 Pod 並指定掛載 PVC,而以下的設定如果成功在 NFS 上建立檔案,這個 Pod 的狀態就會顯示完成,反之則會顯示失敗:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| --- kind: Pod apiVersion: v1 metadata: name: test-pod spec: containers: - name: test-pod image: gcr.io/google_containers/busybox:1.24 command: - "/bin/sh" args: - "-c" - "touch /mnt/SUCCESS && exit 0 || exit 1" volumeMounts: - name: nfs-pvc mountPath: "/mnt" restartPolicy: "Never" volumes: - name: nfs-pvc persistentVolumeClaim: claimName: test-claim
|
檢視一下 Pod 產生的結果:
1 2 3
| $ kubectl get pod NAME READY STATUS RESTARTS AGE test-pod 0/1 Completed 0 9s
|
看到 Pod 的 Status 為 Completed 表示 StorageClass + NFS 成功設定完成囉!
References