一、Volume介紹:
在k8s中Pod的生命週期可能很短,會被頻繁地銷燬和建立。容器銷燬時,儲存在容器內部檔案系統中的資料都會被清除。
為了持久化儲存容器資料,k8s 提供了卷(Volume)的抽象概念來解決上述問題。
卷(Volume)的核心是一個目錄,其中可能存有資料,Pod 中的容器可以訪問該目錄中的資料。 所採用的特定的卷型別將決定該目錄如何形成的、使用何種介質儲存資料以及目錄中存放的內容。
Kubernetes Volume 支援多種卷型別,包括 emptyDir、hostPath、nfs、local、configMap、AWSElasticBlockStore、Cinder、CSI等。
按照儲存可大概劃分為:
臨時儲存:emptydir
半持久化儲存:hostpath
持久化儲存:nfs、ceph、Cinder等
接下來分別介紹幾種常用型別:emptyDir、hostPath、nfs(PV、PVC)
二、Volume:emptyDir
emptyDir 是最基礎的 Volume 型別。正如其名字所示,一個 emptyDir Volume 是 Host 上的一個空目錄。
emptyDir Volume 對於容器來說是持久的,對於 Pod 則不是。當 Pod 從節點刪除時,Volume 的內容也會被刪除。但如果只是容器被銷燬而 Pod 還在,則 Volume 不受影響。(emptyDir Volume 的生命週期與 Pod 一致)
Pod 中的所有容器都可以共享 Volume,它們可以指定各自的掛載路徑。
驗證示例:
apiVersion: v1 kind: Pod metadata: name: producer-consumer spec: containers: - image: busybox name: producer volumeMounts: - mountPath: /producer_dir #掛載到容器中的路徑 name: shared-volume args: - /bin/sh - -c - echo "hello world" > /producer_dir/hello; sleep 3000 - image: busybox name: consumer volumeMounts: - mountPath: /consumer_dir #掛載到容器中的路徑 name: shared-volume args: - /bin/sh - -c - cat /consumer_dir/hello; sleep 3000 volumes: - name: shared-volume emptyDir: {} #指定儲存方式為emptydir
- 建立一個名為[shared-volume]的emptyDir的卷
- 容器producer 將 shared-volume掛載到 producer_dir 目錄
- 容器producer 通過echo 命令向hello 檔案中寫入文字-hello world
- 容器consumer 將 shared-volume掛載到 consumer_dir目錄
- 容器consumer 通過cat命令讀取consumer_dir中hello檔案內容
通過命令:kubectl logs 檢視讀取內容。
# 輸出producer-consumer Pod中容器 consumer 的日誌: kubectl logs producer-consumer -c consumer hello world
顯示容器 consumer
成功讀取到 producer
寫入的資料,驗證了兩個容器共享 emptyDir Volume。
三、Volume:hostPath
hostPath
卷能將主機節點檔案系統上的檔案或目錄掛載到你的 Pod 中。 雖然這不是大多數 Pod 需要的,但是它為一些應用程式提供了強大應急方式。
hostPath
的一些用法有:
- 執行一個需要訪問 Docker 內部機制的容器;可使用
hostPath
掛載/var/lib/docker
路徑。 - 在容器中執行 cAdvisor 時,以
hostPath
方式掛載/sys
。 - 允許 Pod 指定給定的
hostPath
在執行 Pod 之前是否應該存在,是否應該建立以及應該以什麼方式存在。
除了必需的 path
屬性之外,使用者可以選擇性地為 hostPath
卷指定 type,下表為type取值
取值 | 行為 |
---|---|
空字串(預設)用於向後相容,這意味著在安裝 hostPath 卷之前不會執行任何檢查。 | |
DirectoryOrCreate |
如果在給定路徑上什麼都不存在,那麼將根據需要建立空目錄,許可權設定為 0755,具有與 kubelet 相同的組和屬主資訊。 |
Directory |
在給定路徑上必須存在的目錄。 |
FileOrCreate |
如果在給定路徑上什麼都不存在,那麼將在那裡根據需要建立空檔案,許可權設定為 0644,具有與 kubelet 相同的組和所有權。 |
File |
在給定路徑上必須存在的檔案。 |
Socket |
在給定路徑上必須存在的 UNIX 套接字。 |
CharDevice |
在給定路徑上必須存在的字元裝置。 |
BlockDevice |
在給定路徑上必須存在的塊裝置。 |
hostPath示例:
apiVersion: v1 kind: Pod metadata: name: localpod spec: containers: - image: busybox name: local volumeMounts: - mountPath: /localdir #掛載到容器中的路徑 name: mydir - mountPath: loacl.txt name: myfile args: - /bin/sh - -c - echo "local dir test" > /localdir/test.txt; - -c - cat loacl.txt; volumes: - name: mydir hostPath: # 確保檔案所在目錄成功建立。 path: /var/local type: DirectoryOrCreate - name: myfile hostPath: # 確保檔案建立成功 path: /var/local/test.txt type: FileOrCreate
步驟:
1、建立兩個hostPath型別的Volume
2、將這兩個卷都掛載到local容器中
3、容器啟動時,寫入檔案內容“local dir test”,並讀取出來。
四、Volume:持久化儲存-nfs
說到持久化儲存:就需要提k8s中提供的重要的幾種資源型別:
- PersistentVolume (PV): 外部儲存系統中的一塊儲存空間,由管理員建立和維護。與 Volume 一樣,PV 具有永續性,生命週期獨立於 Pod。
- StorageClass:另外一種提供儲存資源的方式, 提供更多的層級選型, 如iops等引數。 但是具體的引數與提供方是繫結的。 如aws和gce它們提供的storageclass的引數可選項是有不同的。
- PersistentVolumeClaim (PVC):是對 PV 的申請 (Claim)。PVC 通常由普通使用者建立和維護。需要為 Pod 分配儲存資源時,使用者可以建立一個 PVC,指明儲存資源的容量大小和訪問模式(比如只讀)等資訊,Kubernetes 會查詢並提供滿足條件的 PV。
PersistentVolume :
生命週期:
- Provisioning- 配置階段, 分為static, dynamic兩種方式。靜態的方式是建立一系列的pv,然後pvc從pv中請求。 動態的方式是基於storageclass的。
- Binding - 繫結階段, pvc根據請求的條件篩選並繫結對應的pv。 一定pvc繫結pv後, 就會排斥其它繫結,即其它pvc無法再繫結同一個pv,即使這個pv設定的access mode允許多個node讀寫。 此外 ,pvc 如何匹配不到相應條件的pv, 那麼就會顯示unbound狀態, 直到匹配為止。 需要注意的是,pvc請求100Gi大小的儲存,即使使用者建立了很多50Gi大小的儲存, 也是無法被匹配的。
- Using- 使用階段, pods 掛載儲存, 即在pod的template檔案中定義volumn使用某個pvc。
- Releasing - 釋放階段, 當pvc物件被刪除後, 就處於釋放階段。 在這個階段, 使用的pv還不能被其它的pvc請求。 之前資料可能還會留存下來, 取決於使用者在pv中設定的policy, 見persistentVolumeReclaimPolicy。
- Reclaiming - 重宣告階段。 到這個階段, 會告訴cluster如何處理釋放的pv。 資料可能被保留(需要手工清除), 回收和刪除。動態分配的儲存總是會被刪除掉的。
- Recycling - 回收階段。回收階段會執行基本的遞迴刪除(取決於volumn plugins的支援),把pv上的資料刪除掉, 以使pv可以被新的pvc請求。 使用者也可以自定義一個 recycler pod , 對資料進行刪除。
卷模式:
PV支援兩種卷模式:
Filesystem
:卷會被 Pod 掛載(Mount) 到某個目錄。 如果卷的儲存來自某塊裝置而該裝置目前為空,Kuberneretes 會在第一次掛載卷之前 在裝置上建立檔案系統。- Block:將卷作為原始塊裝置來使用。 這類卷以塊裝置的方式交給 Pod 使用,其上沒有任何檔案系統。 這種模式對於為 Pod 提供一種使用最快可能方式來訪問卷而言很有幫助,Pod 和 卷之間不存在檔案系統層。另外,Pod 中執行的應用必須知道如何處理原始塊裝置。
訪問模式:
PersistentVolume 卷可以用資源提供者所支援的任何方式掛載到宿主系統上。 如下表所示,提供者(驅動)的能力不同,每個 PV 卷的訪問模式都會設定為 對應卷所支援的模式值。 例如,NFS 可以支援多個讀寫客戶,但是某個特定的 NFS PV 卷可能在伺服器 上以只讀的方式匯出。每個 PV 卷都會獲得自身的訪問模式集合,描述的是 特定 PV 卷的能力。
訪問模式有:
-
- ReadWriteOnce (RWO) -- 卷可以被一個節點以讀寫方式掛載;
- ReadOnlyMany (ROX) -- 卷可以被多個節點以只讀方式掛載;
- ReadWriteMany (RWX) -- 卷可以被多個節點以讀寫方式掛載
卷外掛 | ReadWriteOnce | ReadOnlyMany | ReadWriteMany |
---|---|---|---|
AWSElasticBlockStore | ✓ | - | - |
AzureFile | ✓ | ✓ | ✓ |
AzureDisk | ✓ | - | - |
CephFS | ✓ | ✓ | ✓ |
Cinder | ✓ | - | - |
CSI | 取決於驅動 | 取決於驅動 | 取決於驅動 |
FC | ✓ | ✓ | - |
FlexVolume | ✓ | ✓ | 取決於驅動 |
Flocker | ✓ | - | - |
GCEPersistentDisk | ✓ | ✓ | - |
Glusterfs | ✓ | ✓ | ✓ |
HostPath | ✓ | - | - |
iSCSI | ✓ | ✓ | - |
Quobyte | ✓ | ✓ | ✓ |
NFS | ✓ | ✓ | ✓ |
RBD | ✓ | ✓ | - |
VsphereVolume | ✓ | - | - (Pod 執行於同一節點上時可行) |
PortworxVolume | ✓ | - | ✓ |
ScaleIO | ✓ | ✓ | - |
StorageOS | ✓ | - | - |
回收策略:
目前的回收策略有:
- Retain -- 手動回收
- Recycle -- 基本擦除 (
rm -rf /thevolume/*
) - Delete -- 諸如 AWS EBS、GCE PD、Azure Disk 或 OpenStack Cinder 卷這類關聯儲存資產也被刪除
目前,僅 NFS 和 HostPath 支援回收(Recycle)。 AWS EBS、GCE PD、Azure Disk 和 Cinder 卷都支援刪除(Delete)
持久化儲存驗證:
1、nfs服務搭建:
所有節點安裝nfs
yum install -y nfs-common nfs-utils
在master節點建立共享目錄
[root@k8s-master k8s]# mkdir /nfsdata
授權共享目錄
[root@k8s-master k8s]# chmod 666 /nfsdata
編輯exports檔案
[root@k8s-master k8s]# cat /etc/exports /nfsdata *(rw,no_root_squash,no_all_squash,sync)
配置生效
[root@k8s-master k8s]# export -r
啟動rpc和nfs(注意順序)
[root@k8s-master k8s]# systemctl start rpcbind [root@k8s-master k8s]# systemctl start nfs
2、建立PV:
#建立Pv:name-pv01 apiVersion: v1 kind: PersistentVolume metadata: name: pv01 labels: name: pv01 spec: # 所有節點可共享訪問 accessModes: ["ReadWriteMany"]
# 回收策略:清除PV資料
persistentVolumeReclaimPolicy:Recycle
# 指定PV的Class為 nfs
storageClassName:nfs capacity: # Pv大小1G storage: 1Gi #nfs 服務設定,以及目錄設定 nfs: server: 192.168.115.6 path: /home
3、建立PVC:
#建立名為mypvc的PVC apiVersion: v1 kind: PersisitentVolumeClaim metadata: name: mypvc namespace: default spec: accessmodes: ["ReadWriteMany"] #所有節點可讀寫 resources: #指定資源說明 requests: #指定請求 storage: 4Gi #指定請求儲存空間的大小
4、建立POD使用PVC
#建立Pod並使用PVC apiVersion: v1 kind: Pod metadata: name: pvnginx labels: app: pvnginx spec: containers: - name: my-pvnginx image: nginx ports: - name: http containerPort: 80 - name: https containerPort: 443 volumeMounts: - name: html mountPath: /data/html volumes: - name: html persistentVolumeClaim: #指明使用pvc模式 claimname: mypvc #指明使用的pvc名稱
總結:
1、對於不需要持久化的資料可採用emptyDir型別捲來儲存相關資料,其生命週期同Pod相同
2、當需要訪問當前主機檔案時,可以採用hostPath型別的捲來實現
3、PV、PVC在實際場景中應用較多,需要了解透徹:包括PV的動/靜態建立、PVC、生命週期等基本概念
參考:
https://kubernetes.io/zh/docs/concepts/storage/
https://kubernetes.io/zh/docs/concepts/storage/