.NET Core + Kubernetes:Volume
和 Docker 類似,Kubernetes 中也提供了 ?Volume 來實現數據卷掛載,但 Kubernetes 中 Volume 是基于 Pod,而不是容器,它可被 Pod 中多個容器共享,另外 Kubernetes 中提供比較豐富的 Volume 類型[1],如:emptyDir、hostPath、nfs、persistentVolumeClaim、downwardAPI、secret、configMap 等,每種類型都有其特點及使用場景。
下面將介紹幾種常用 Volume 類型的使用方式,在這之前先在 k8sdemo .NET Core 服務中添加以下兩個接口(鏡像版本升級為 1.2.0),以方便后面效果演示。
[HttpGet] public string GetConfig([FromQuery]string key) {// ...... }[HttpGet] public string GetVolumeData() {// ...... }GetConfig:通過傳入配置文件 appsettings.json 的 key 獲取對應值;GetVolumeData:獲取容器內 /Data/data.txt 的文件內容;
emptyDir
emptyDir 的初始狀態是一個沒有任何內容的 Volume,其生命周期與 Pod 一致,當 Pod 中的容器掛掉時,emptyDir Volume 中的內容不會被清除,容器重啟后數據依然可見。只有當整個 Pod 從集群中被刪除,emptyDir Volume 中的內容才會被清除。如下:emptyDir Volume 位于 Pod 內。
通過以下配置文件創建的 Pod 中將包含 k8sdemo 和 busybox 兩個 container,busybox 是一個集成了一些常用 linux 命令的鏡像,這里將使用它在 Pod 內進行文件內容修改。k8sdemo 容器的 /app/Data/ 目錄文件與 busybox 容器的 /data/ 目錄文件將通過 emptyDir Volume 進行共享。
apiVersion: apps/v1 kind: Deployment metadata:name: emptydir-demo spec:replicas: 1selector:matchLabels:name: emptydir-demotemplate:metadata:labels:name: emptydir-demospec:containers:- name: k8sdemoimage: beckjin/k8sdemo:1.2.0volumeMounts:- mountPath: /app/Data/name: shareports:- containerPort: 80- name: busyboximage: busyboxcommand:- "/bin/sh"- "-c"- "sleep 3600"volumeMounts:- mountPath: /data/name: sharevolumes:- name: shareemptyDir: {} --- apiVersion: v1 kind: Service metadata:name: emptydir-demo-service spec:selector:name: emptydir-demotype: NodePortports:- port: 80targetPort: 80執行命令 kubectl exec -it emptydir-demo-746f49b55b-p6pzz -c busybox -- /bin/sh 進入 busybox ?容器,然后執行 echo 'emptyDir Volume' > /data/data.txt,最后訪問 k8sdemo 服務的 GetVolumeData 接口獲取文件內容:
hostPath
hostPath 類型是掛載宿主機上的文件或目錄到 Pod 中,與 Pod 所在的 Node 是強關聯的,所以當 Pod 因重啟被重新調度時,一定要確保所在主機的相關文件或目錄的正確性,如下:
如下配置中 replicas 字段設置為 2 ,正常情況下 Pod 將會在 node1 和 node2 上分別被創建,另外 hostPath 字段中的 path 指定了 /data/k8sdemo/ 目錄掛載到容器內的 /app/Data/,所以分別在 node1 和 node2 創建 /data/k8sdemo/data.txt ,內容為 node1 hostPath Volume 和 node2 hostPath Volume。
kind: Deployment metadata:name: hostpath-demo spec:replicas: 2selector:matchLabels:name: hostpath-demotemplate:metadata:labels:name: hostpath-demospec:containers:- name: k8sdemoimage: beckjin/k8sdemo:1.2.0volumeMounts:- mountPath: /app/Data/name: shareports:- containerPort: 80volumes:- name: sharehostPath:path: /data/k8sdemotype: Directory --- apiVersion: v1 kind: Service metadata:name: hostpath-demo-service spec:selector:name: hostpath-demotype: NodePortports:- port: 81targetPort: 80訪問 k8sdemo 服務的 GetVolumeData 接口獲取文件內容,當路由到不同 Pod(即不同的 node) 返回內容將不一樣,如下:
nfs
NFS(network file system) 網絡文件系統,類似 Windows 中的文件夾共享。首先在 Kubernetes 集群外搭建一個 NFS Server,然后指定文件目錄進行共享,最終與 ?Pod 內的容器關聯,實現數據卷掛載,如下:
NFS Server 搭建
在機器上安裝依賴組件(集群外的機器 192.168.1.13,并關閉防火墻)
yum install -y nfs-utils rpcbind將主機上的 /share 目錄作為共享目錄,如果多個目錄可以添加多行
[root@localhost ~]# vim /etc/exports /share 192.168.1.0/24(insecure,rw,no_root_squash)啟動 NFS
systemctl start rpcbind.service systemctl enable rpcbind.servicesystemctl start nfs.service systemctl enable nfs.serviceKubernetes 集群內各節點安裝 nfs-utils,方便使用 showmount
yum install -y nfs-utils完成以上步驟后,在 Kubernetes 集群中任意節點執行 ?showmount -e 192.168.1.13 驗證是否正常:
如下配置中 volumes 指定了 nfs 字段配置,即將 ?NFS Server 中的 /share 目錄掛載到容器內的 /app/Data/,與 hostPath Volume 類型的主要區別是依賴單獨的 NFS Server,和 node 本身并不耦合。
apiVersion: apps/v1 kind: Deployment metadata:name: nfs-demo spec:replicas: 2selector:matchLabels:name: nfs-demotemplate:metadata:labels:name: nfs-demospec:containers:- name: k8sdemoimage: beckjin/k8sdemo:1.2.0volumeMounts:- mountPath: /app/Dataname: shareports:- containerPort: 80volumes:- name: sharenfs:server: 192.168.1.13path: /share --- apiVersion: v1 kind: Service metadata:name: nfs-demo-service spec:selector:name: nfs-demotype: NodePortports:- port: 82targetPort: 80在 NFS Server 中執行 echo 'nfs Volume' > /share/data.txt,然后訪問 k8sdemo 服務的 GetVolumeData 接口獲取文件內容,如下:
persistentVolumeClaim
PersistentVolumeClaim(PVC) 與 PersistentVolume(PV) 在使用上是一對密不可分的組合,PV 主要是資源對象定義,PVC 主要是對應資源對象的引用,PV 支持 多種插件類型[2] 進行實現,以下將繼續使用 NFS 來作為 PV 插件。
如下圖:首先基于 PV 插件在 Kubernetes 集群中創建各種資源規格的 PV,根據 Pod 需要存儲卷資源創建 PVC,Kubernetes 將符合資源規格要求且消耗資源最小的 PV 綁定到 PVC,PV 和 PVC 是一對一的關系,如果找不到符合條件的 PV,PVC 會一直處于未綁定狀態,PVC 綁定成功后可被 Pod 內的容器引用。
NFS Server 添加 mount 目錄
修改 NFS Server /etc/exports 并生效 ,在 Kubernetes 集群中任意節點執行 showmount -e 192.168.1.13 驗證是否正常:
創建 PV
以下配置將會創建3個 PV,storage 分別為 500M、1G、2G。
apiVersion: v1 kind: PersistentVolume metadata:name: pv-share-a spec:nfs:path: /share_aserver: 192.168.1.13accessModes:- ReadWriteManycapacity:storage: 500Mi --- apiVersion: v1 kind: PersistentVolume metadata:name: pv-share-b spec:nfs:path: /share_bserver: 192.168.1.13accessModes:- ReadWriteManycapacity:storage: 1Gi --- apiVersion: v1 kind: PersistentVolume metadata:name: pv-share-c spec:nfs:path: /share_cserver: 192.168.1.13accessModes:- ReadWriteManycapacity:storage: 2Gi創建 PVC
apiVersion: v1 kind: PersistentVolumeClaim metadata:name: pvc-k8sdemo spec:accessModes:- ReadWriteManyresources:requests:storage: 1GiPVC 創建成功后,pv-share-b 的 STATUS 會變為 Bound,同時 CLAIM 屬性會顯示相關的 PVC,從上圖也可以看出使用的是最小符合資源規格的 PV,并不會將 pv-share-c 綁定到當前 PVC。更多關于 PV 和 PVC 屬性說明可參考:persistent-volumes[3]。
創建 Pod
如下配置中 volumes 指定了 persistentVolumeClaim 字段配置,這里只需要設置 claimName 為前面創建的 PVC 名稱 pvc-k8sdemo 即可,使用上比較簡單。
apiVersion: apps/v1 kind: Deployment metadata:name: pvc-demo spec:replicas: 2selector:matchLabels:name: pvc-demotemplate:metadata:labels:name: pvc-demospec:containers:- name: k8sdemoimage: beckjin/k8sdemo:1.2.0volumeMounts:- mountPath: /app/Dataname: shareports:- containerPort: 80volumes:- name: sharepersistentVolumeClaim:claimName: pvc-k8sdemo --- apiVersion: v1 kind: Service metadata:name: pvc-demo-service spec:selector:name: pvc-demotype: NodePortports:- port: 83targetPort: 80在 NFS Server 中執行 echo 'pvc Volume share_a' > /share_a/data.txt,share_b、share_c 類似,然后訪問 k8sdemo 服務的 GetVolumeData 接口獲取文件內容,如下:
configMap
configMap 主要使鏡像和配置文件解耦,以便實現鏡像的可移植性和可復用性,configMap 是配置信息的集合,可直接注入到 Pod 的容器中使用,扮演著配置中心的角色。configMap 可以以數據卷的形式掛載,也可以基于環境變量的形式注入到 Pod 容器中使用。另外 secret 是一種相對安全的 configMap,它默認會將配置信息進行 base64 編碼,使配置不是明文直接存儲在 configMap 中,起到一定的保護作用。
下面主要介紹 configMap 以數據卷掛載方式的使用,如下圖,在 Kubernetes 集群中創建一個 configMap 資源類型,然后供 Pod 內的容器使用。
如下,創建一個數據卷形式的 ConfigMap,appsettings.json 是 .NET Core 程序內使用的配置文件。
apiVersion: v1 kind: ConfigMap metadata:name: configmap-k8sdemo data:appsettings.json: |-{"ServiceName": "k8sdemo"}如下配置中 volumes 指定了 configMap 資源的名稱為以上創建的 configMap 對象:configmap-k8sdemo。
apiVersion: apps/v1 kind: Deployment metadata:name: configmap-demo spec:replicas: 2selector:matchLabels:name: configmap-demotemplate:metadata:labels:name: configmap-demospec:containers:- name: k8sdemoimage: beckjin/k8sdemo:1.2.0volumeMounts:- name: configfilemountPath: /app/appsettings.jsonsubPath: appsettings.jsonports:- containerPort: 80volumes:- name: configfileconfigMap:name: configmap-k8sdemoitems:- key: appsettings.jsonpath: appsettings.json --- apiVersion: v1 kind: Service metadata:name: configmap-demo-service spec:selector:name: configmap-demotype: NodePortports:- port: 84targetPort: 80通過訪問 k8sdemo 服務的 GetConfig 接口獲取指定 key 的值:
參考資料
[1]
Volume 類型: https://kubernetes.io/docs/concepts/storage/volumes/#types-of-volumes
[2]多種插件類型: https://kubernetes.io/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes
[3]persistent-volumes: https://kubernetes.io/docs/concepts/storage/persistent-volumes/
總結
以上是生活随笔為你收集整理的.NET Core + Kubernetes:Volume的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [Mvp.Blazor] 动态路由与钩子
- 下一篇: WPF中的Data Binding调试指