1. 程式人生 > >Kubernetes之(十二)存儲卷

Kubernetes之(十二)存儲卷

規格 計算 ech 叢書 容器 nes 集群 obj explain

目錄

  • Kubernetes之(十二)存儲卷
    • 簡介
    • emptyDir存儲卷
    • hostPath存儲卷
    • nfs共享存儲卷
    • PV和PVC
    • NFS使用PV和PVC
      • 配置NFS存儲
      • 定義PV
      • 定義PVC
      • 查看驗證
      • 測試訪問
    • StorageClass

Kubernetes之(十二)存儲卷

簡介

為了保證數據的持久性,必須保證數據在外部存儲在docker容器中,為了實現數據的持久性存儲,在宿主機和容器內做映射,可以保證在容器的生命周期結束,數據依舊可以實現持久性存儲。但是在k8s中,由於pod分布在各個不同的節點之上,並不能實現不同節點之間持久性數據的共享,並且,在節點故障時,可能會導致數據的永久性丟失。為此,k8s就引入了外部存儲卷的功能。

k8s的存儲卷類型:

[[email protected] ~]# kubectl explain pods.spec.volumes.
 emptyDir     <Object> # 臨時目錄。pod刪除數據也被刪除,用於數據的臨時存儲。
 hostPath   <Object> #宿主機目錄映射 和docker的一樣
#以上兩種都不能滿足持久性存儲
本地傳統存儲:
- SAN(iSCSI,FC)
- NAS(nfs,cifs,http)
分布式存儲:
- glusterfs
- cephfs
雲存儲:
- EBS,Azure Disk

persistentVolumeClaim

-->PVC(存儲卷創建申請)
當你需要創建一個存儲卷時,只需要進行申請對應的存儲空間即可使用,這就是PVC。其關聯關系如圖:
技術分享圖片
(圖片來源: https://www.cnblogs.com/linuxk/)

在Pod上定義一個PVC,該PVC要關聯到當前名稱空間的PVC資源,該PVC只是一個申請,PVC需要和PV進行關聯。PV屬於存儲上的一部分存儲空間。但是該方案存在的問題是,我們無法知道用戶是什麽時候去創建Pod,也不知道創建Pod時定義多大的PVC,那麽如何實現按需創建?

不需要PV層,把所有存儲空間抽象出來,這一個抽象層稱為存儲類,當用戶創建PVC需要用到PV時,可以向存儲類申請對應的存儲空間,存儲類會按照需求創建對應的存儲空間,這就是PV的動態供給,如圖:

技術分享圖片
(圖片來源: https://www.cnblogs.com/linuxk/)

PV的動態供給,重點是在存儲類的定義,其分類大概是對存儲的性能進行分類的。

總結:
k8s要使用存儲卷,需要2步:
1、在pod定義volume,並指明關聯到哪個存儲設備
2、在容器使用volume mount進行掛載

emptyDir存儲卷

emptyDir 第一次創建是在一個pod被指定到具體node的時候,並且會一直存在在pod的生命周期當中,它初始化是一個空的目錄,pod中的容器都可以讀寫這個目錄,這個目錄可以被掛在到各個容器相同或者不相同的的路徑下。當一個pod因為任何原因被移除的時候,這些數據會被永久刪除。註意:一個容器崩潰了不會導致數據的丟失,因為容器的崩潰並不移除pod.

emptyDir 磁盤的作用:
(1)普通空間,基於磁盤的數據存儲
(2)作為從崩潰中恢復的備份點
(3)存儲那些那些需要長久保存的數據,例web服務中的數據
默認的,emptyDir 磁盤會存儲在主機所使用的媒介上,可能是SSD,或者網絡硬盤,這主要取決於你的環境。當然,我們也可以將emptyDir.medium的值設置為Memory來表示掛在一個基於內存的目錄tmpfs,因為tmpfs速度會比硬盤快,但是,當主機重啟的時候所有的數據都會丟失。

[[email protected] manifests]# mkdir volume &&cd volume 
[[email protected] volume]# vim  pod-vol-demo.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-demo
  namespace: default
  labels:
    app: myapp
    tier: frontend
  annotations:
    white/created-by: "white"
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    ports:
    - name: http
      containerPort: 80
    volumeMounts: #容器內掛載存儲卷
    - name: html
      mountPath: /usr/share/nginx/html/ 
  - name: busybox
    image: busybox
    volumeMounts:  #容器內掛載存儲卷
    - name: html
      mountPath: /data/ 
    command: [ '/bin/sh','-c','while true;do echo $(date) >> /data/index.html;sleep 2;done']
  volumes:
  - name: html  #存儲卷命名
    emptyDir: {} #定義存儲卷類型
    
[[email protected] volume]# kubectl apply -f pod-vol-demo.yaml 
pod/pod-demo created

上述配置用我們使用Pod內的busybox容器每隔兩秒把當前時間寫入容器內/data/index.html文件,由於容器busybox和容器myapp都掛載到名未html的存儲卷,所以容器myapp的/usr/share/nginx/html/主頁目錄內會存在index.html文件,內容是切入的日期,驗證:

[[email protected] volume]# kubectl apply -f pod-vol-demo.yaml  
pod/pod-demo created
[[email protected] volume]# kubectl get pods -o wide
NAME                                 READY   STATUS    RESTARTS   AGE     IP            NODE     NOMINATED NODE   READINESS GATES
filebeat-ds-h8rwk                    1/1     Running   0          20h     10.244.1.39   node01   <none>           <none>
filebeat-ds-kzhxw                    1/1     Running   0          20h     10.244.2.44   node02   <none>           <none>
myapp-backend-pod-6b56d98b6b-2dh5h   1/1     Running   0          159m    10.244.1.44   node01   <none>           <none>
myapp-backend-pod-6b56d98b6b-hwzws   1/1     Running   0          159m    10.244.2.49   node02   <none>           <none>
myapp-backend-pod-6b56d98b6b-ztwn2   1/1     Running   0          159m    10.244.2.48   node02   <none>           <none>
pod-demo                             2/2     Running   0          7s      10.244.2.53   node02   <none>           <none>
readiness-httpget-pod                1/1     Running   0          3d18h   10.244.2.18   node02   <none>           <none>
tomcat-deploy-5f554cd88d-7gzc7       1/1     Running   0          97m     10.244.2.51   node02   <none>           <none>
tomcat-deploy-5f554cd88d-c42t6       1/1     Running   0          97m     10.244.2.50   node02   <none>           <none>
tomcat-deploy-5f554cd88d-qhc4j       1/1     Running   0          97m     10.244.1.45   node01   <none>           <none>

[[email protected] volume]# curl 10.244.2.53 
Tue Apr 2 03:35:30 UTC 2019
Tue Apr 2 03:35:32 UTC 2019
Tue Apr 2 03:35:34 UTC 2019
Tue Apr 2 03:35:36 UTC 2019
Tue Apr 2 03:35:38 UTC 2019
Tue Apr 2 03:35:40 UTC 2019
Tue Apr 2 03:35:42 UTC 2019
Tue Apr 2 03:35:44 UTC 2019
Tue Apr 2 03:35:46 UTC 2019
Tue Apr 2 03:35:48 UTC 2019
Tue Apr 2 03:35:50 UTC 2019
Tue Apr 2 03:35:52 UTC 2019
Tue Apr 2 03:35:54 UTC 2019

hostPath存儲卷

hostPath宿主機路徑,就是把pod所在的宿主機之上的脫離pod中的容器名稱空間的之外的宿主機的文件系統的某一目錄和pod建立關聯關系,在pod刪除時,存儲數據不會丟失。

[[email protected] volume]# kubectl explain pods.spec.volumes.hostPath.
KIND:     Pod
VERSION:  v1

FIELDS:
   path <string> -required-

   type <string>
     Type for HostPath Volume Defaults to "" More info:
     https://kubernetes.io/docs/concepts/storage/volumes#hostpath

[[email protected] volume]# kubectl explain pods.spec.volumes.hostPath.type.
KIND:     Pod
VERSION:  v1

FIELD:    type <string>
e/volumes#hostpath

type多種類型:

  • DirectoryOrCreate:目錄不存在則創建
  • Directory: 目錄一定要存在,不存在會報錯
  • FileOrCreate:文件存在則創建
  • File:文件一定要存在,不存在會報錯
  • Socket:必須存在Soeket文件
  • CharDevice:必須存在char文件
  • BlockDevice: 必須存在塊設備文件

配置清單

[[email protected] volume]# vimpod-hostpath-vol.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pod-hostpath-vol
  namespace: default
spec:
  containers:
  - name: myapp
    iamge: ikubernetes/myapp:v1
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html/
  volumes:
  - name: html
    hostPath:
      path: /data/pod/volume1/
      type: DirectoryOrCreate

為了演示效果,提前在node上創建/data/pod/volume1目錄

[[email protected] ~]# mkdir /data/pod/volume1/ -p && echo 'node01.com'>>/data/pod/volume1/index.html
[[email protected] ~]#  mkdir /data/pod/volume1/ -p && echo 'node02.com'>>/data/pod/volume1/index.html

創建Pod

[[email protected] volume]# kubectl apply -f pod-hostpath-vol.yaml 
pod/pod-hostpath-vol created
[[email protected] volume]# kubectl get pods -o wide
NAME                                 READY   STATUS    RESTARTS   AGE     IP            NODE     NOMINATED NODE   READINESS GATES
filebeat-ds-h8rwk                    1/1     Running   0          23h     10.244.1.39   node01   <none>           <none>
filebeat-ds-kzhxw                    1/1     Running   0          23h     10.244.2.44   node02   <none>           <none>
myapp-backend-pod-6b56d98b6b-2dh5h   1/1     Running   0          5h25m   10.244.1.44   node01   <none>           <none>
myapp-backend-pod-6b56d98b6b-hwzws   1/1     Running   0          5h25m   10.244.2.49   node02   <none>           <none>
myapp-backend-pod-6b56d98b6b-ztwn2   1/1     Running   0          5h25m   10.244.2.48   node02   <none>           <none>
pod-hostpath-vol                     1/1     Running   0          80s     10.244.1.48   node01   <none>           <none>
readiness-httpget-pod                1/1     Running   0          3d21h   10.244.2.18   node02   <none>           <none>
tomcat-deploy-5f554cd88d-7gzc7       1/1     Running   0          4h23m   10.244.2.51   node02   <none>           <none>
tomcat-deploy-5f554cd88d-c42t6       1/1     Running   0          4h23m   10.244.2.50   node02   <none>           <none>
tomcat-deploy-5f554cd88d-qhc4j       1/1     Running   0          4h23m   10.244.1.45   node01   <none>           <none>

查看可知,pod-hostpath-vol運行在 node01上

[[email protected] volume]# curl 10.244.1.48
node01.com

刪除Pod後重新創建,查看

[[email protected] volume]# kubectl get pods -o wide
NAME                                 READY   STATUS    RESTARTS   AGE     IP            NODE     NOMINATED NODE   READINESS GATES
myapp-backend-pod-6b56d98b6b-2dh5h   1/1     Running   0          5h29m   10.244.1.44   node01   <none>           <none>
myapp-backend-pod-6b56d98b6b-hwzws   1/1     Running   0          5h29m   10.244.2.49   node02   <none>           <none>
myapp-backend-pod-6b56d98b6b-ztwn2   1/1     Running   0          5h29m   10.244.2.48   node02   <none>           <none>
pod-hostpath-vol                     1/1     Running   0          4s      10.244.2.54   node02   <none>           <none>
tomcat-deploy-5f554cd88d-7gzc7       1/1     Running   0          4h28m   10.244.2.51   node02   <none>           <none>
tomcat-deploy-5f554cd88d-c42t6       1/1     Running   0          4h28m   10.244.2.50   node02   <none>           <none>
tomcat-deploy-5f554cd88d-qhc4j       1/1     Running   0          4h28m   10.244.1.45   node01   <none>           <none>

此時pod-hostname-vol在node02上,IP為10.244.2.54

[[email protected] volume]# curl 10.244.2.54 
node02.com

hostPath可以實現持久存儲,但是在node節點故障時,也會導致數據的丟失。

nfs共享存儲卷

nfs使的我們可以掛在已經存在的共享到的我們的Pod中,和emptyDir不同的是,emptyDir會被刪除當我們的Pod被刪除的時候,但是nfs不會被刪除,僅僅是解除掛在狀態而已,這就意味著NFS能夠允許我們提前對數據進行處理,而且這些數據可以在Pod之間相互傳遞.並且,nfs可以同時被多個pod掛在並進行讀寫

註意:必須先保證NFS服務器正常運行在我們進行掛在nfs的時候
配置NFS
集群外部主機

主機名 IP地址 系統版本 虛擬機配置 部署軟件
nfs 10.0.0.14 Centos 7.5 1804 1核1G nfs-utils
[[email protected] ~]# yum install nfs-utils -y
[[email protected] ~]# mkdir /data/volumes -pv
[[email protected] ~]# vim /etc/exports
/data/volumes 10.0.0.0/24(rw,no_root_squash)
[[email protected] ~]# systemctl start nfs
[[email protected] ~]# showmount -e
Export list for nfs:
/data/volumes 10.0.0.0/24

在node01和node02節點上安裝nfs-utils,並測試掛載,掛載正常後卸載

[[email protected] ~]# mount -t nfs nfs:/data/volumes /mnt

[[email protected] ~]# df -h |grep mnt
nfs:/data/volumes   25G  1.9G   23G    8% /mnt
#測試正常
[[email protected] ~]# umount /mnt

配置清單

[[email protected] volume]# vim pod-nfs-vol.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-nfs-vol
  namespace: default
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html/
  volumes:
  - name: html
    nfs:
      path: /data/volumes  #掛載路徑
      server: nfs   #此處需提前做好host解析,否則使用IP

運行並查看

[[email protected] volume]# kubectl apply -f pod-nfs-vol.yaml 
pod/pod-nfs-vol created
[[email protected] volume]# kubectl get pods -o wide
NAME                                 READY   STATUS    RESTARTS   AGE     IP            NODE     NOMINATED NODE   READINESS GATES
myapp-backend-pod-6b56d98b6b-2dh5h   1/1     Running   0          5h50m   10.244.1.44   node01   <none>           <none>
myapp-backend-pod-6b56d98b6b-hwzws   1/1     Running   0          5h50m   10.244.2.49   node02   <none>           <none>
myapp-backend-pod-6b56d98b6b-ztwn2   1/1     Running   0          5h50m   10.244.2.48   node02   <none>           <none>
pod-hostpath-vol                     1/1     Running   0          20m     10.244.2.54   node02   <none>           <none>
pod-nfs-vol                          1/1     Running   0          4s      10.244.2.55   node02   <none>           <none>
tomcat-deploy-5f554cd88d-7gzc7       1/1     Running   0          4h49m   10.244.2.51   node02   <none>           <none>
tomcat-deploy-5f554cd88d-c42t6       1/1     Running   0          4h49m   10.244.2.50   node02   <none>           <none>
tomcat-deploy-5f554cd88d-qhc4j       1/1     Running   0          4h49m   10.244.1.45   node01   <none>           <none>

在NFS服務器掛載目錄內創建index.html文件,驗證

[[email protected] volumes]#  echo 'this is nfs-vol!!!'>> index.html   
[[email protected] volumes]# cat index.html 
this is nfs-vol!!!

#回到kubernetes集群內
[[email protected] volume]# curl 10.244.2.55
this is nfs-vol!!!

驗證持久性,刪除pod後查看nfs服務器文件是否存在,重新啟動pod後查看

[[email protected] volume]# kubectl delete -f pod-nfs-vol.yaml 
pod "pod-nfs-vol" deleted

[[email protected] volumes]# pwd &&ls
/data/volumes
index.html

[[email protected] volume]# kubectl apply -f pod-nfs-vol.yaml 
pod/pod-nfs-vol created
[[email protected] volume]# kubectl get pods -o wide
NAME                                 READY   STATUS    RESTARTS   AGE     IP            NODE     NOMINATED NODE   READINESS GATES
myapp-backend-pod-6b56d98b6b-2dh5h   1/1     Running   0          5h55m   10.244.1.44   node01   <none>           <none>
myapp-backend-pod-6b56d98b6b-hwzws   1/1     Running   0          5h55m   10.244.2.49   node02   <none>           <none>
myapp-backend-pod-6b56d98b6b-ztwn2   1/1     Running   0          5h55m   10.244.2.48   node02   <none>           <none>
pod-hostpath-vol                     1/1     Running   0          25m     10.244.2.54   node02   <none>           <none>
pod-nfs-vol                          1/1     Running   0          5s      10.244.2.56   node02   <none>           <none>
tomcat-deploy-5f554cd88d-7gzc7       1/1     Running   0          4h53m   10.244.2.51   node02   <none>           <none>
tomcat-deploy-5f554cd88d-c42t6       1/1     Running   0          4h53m   10.244.2.50   node02   <none>           <none>
tomcat-deploy-5f554cd88d-qhc4j       1/1     Running   0          4h53m   10.244.1.45   node01   <none>           <none>

[[email protected] volume]# curl 10.244.2.56
this is nfs-vol!!!

此時發現無論重啟pod還是刪除pod,文件都存在,實現了持久化存儲。

PV和PVC

我們前面提到kubernetes提供那麽多存儲接口,但是首先kubernetes的各個Node節點能管理這些存儲,但是各種存儲參數也需要專業的存儲工程師才能了解,由此我們的kubernetes管理變的更加復雜的。由此kubernetes提出了PV和PVC的概念,這樣開發人員和使用者就不需要關註後端存儲是什麽,使用什麽參數等問題。如下圖:
技術分享圖片
(圖片來源https://www.cnblogs.com/linuxk/)

PersistentVolume(PV)是集群中已由管理員配置的一段網絡存儲。 集群中的資源就像一個節點是一個集群資源。 PV是諸如卷之類的卷插件,但是具有獨立於使用PV的任何單個pod的生命周期。 該API對象捕獲存儲的實現細節,即NFS,iSCSI或雲提供商特定的存儲系統。
技術分享圖片
(圖片來源https://www.cnblogs.com/linuxk/)

PersistentVolumeClaim(PVC)是用戶存儲的請求。PVC的使用邏輯:在pod中定義一個存儲卷(該存儲卷類型為PVC),定義的時候直接指定大小,pvc必須與對應的pv建立關系,pvc會根據定義去pv申請,而pv是由存儲空間創建出來的。pv和pvc是kubernetes抽象出來的一種存儲資源。

雖然PersistentVolumeClaims允許用戶使用抽象存儲資源,但是常見的需求是,用戶需要根據不同的需求去創建PV,用於不同的場景。而此時需要集群管理員提供不同需求的PV,而不僅僅是PV的大小和訪問模式,但又不需要用戶了解這些卷的實現細節。 對於這樣的需求,此時可以采用StorageClass資源。這個在前面就已經提到過此方案。

PV是集群中的資源。 PVC是對這些資源的請求,也是對資源的索賠檢查。 PV和PVC之間的相互作用遵循這個生命周期:
Provisioning(配置)---> Binding(綁定)--->Using(使用)---> Releasing(釋放) ---> Recycling(回收)

Provisioning
這裏有兩種PV的提供方式:靜態或者動態

靜態-->直接固定存儲空間:
????集群管理員創建一些 PV。它們攜帶可供集群用戶使用的真實存儲的詳細信息。 它們存在於Kubernetes API中,可用於消費。

動態-->通過存儲類進行動態創建存儲空間:
????當管理員創建的靜態 PV 都不匹配用戶的 PVC 時,集群可能會嘗試動態地為 PVC 配置卷。此配置基於 StorageClasses:PVC 必須請求存儲類,並且管理員必須已創建並配置該類才能進行動態配置。 要求該類的聲明有效地為自己禁用動態配置。

Binding
在動態配置的情況下,用戶創建或已經創建了具有特定數量的存儲請求和特定訪問模式的PersistentVolumeClaim。 主機中的控制回路監視新的PVC,找到匹配的PV(如果可能),並將 PVC 和 PV 綁定在一起。 如果為新的PVC動態配置PV,則循環將始終將該PV綁定到PVC。 否則,用戶總是至少得到他們要求的內容,但是卷可能超出了要求。 一旦綁定,PersistentVolumeClaim綁定是排他的,不管用於綁定它們的模式。

如果匹配的卷不存在,PVC將保持無限期。 隨著匹配卷變得可用,PVC將被綁定。 例如,提供許多50Gi PV的集群將不匹配要求100Gi的PVC。 當集群中添加100Gi PV時,可以綁定PVC。

Using
Pod使用PVC作為卷。 集群檢查聲明以找到綁定的卷並掛載該卷的卷。 對於支持多種訪問模式的卷,用戶在將其聲明用作pod中的卷時指定所需的模式。

一旦用戶有聲明並且該聲明被綁定,綁定的PV屬於用戶,只要他們需要它。 用戶通過在其Pod的卷塊中包含PersistentVolumeClaim來安排Pods並訪問其聲明的PV。

Releasing
當用戶完成卷時,他們可以從允許資源回收的API中刪除PVC對象。 當聲明被刪除時,卷被認為是“釋放的”,但是它還不能用於另一個聲明。 以前的索賠人的數據仍然保留在必須根據政策處理的卷上.

Reclaiming
PersistentVolume的回收策略告訴集群在釋放其聲明後,該卷應該如何處理。 目前,卷可以是保留,回收或刪除。 保留可以手動回收資源。 對於那些支持它的卷插件,刪除將從Kubernetes中刪除PersistentVolume對象,以及刪除外部基礎架構(如AWS EBS,GCE PD,Azure Disk或Cinder卷)中關聯的存儲資產。 動態配置的卷始終被刪除.

Recycling
如果受適當的卷插件支持,回收將對卷執行基本的擦除(rm -rf / thevolume / *),並使其再次可用於新的聲明。

NFS使用PV和PVC

查看pv和pvc規格

[[email protected] ~]# kubectl explain pv.spec.
spec:
  nfs #定義存儲類型
    path #定義掛載卷路徑
    server #定義服務器名稱
  accessModes#定義訪問模型,有以下三種訪問模型,以列表的方式存在,也就是說可以定義多個訪問模式
    ReadWriteOnce  #單節點讀寫 RWO
    ReadOnlyMany  #多節點只讀 ROX
    ReadWriteMany  #多節點讀寫 RWX
  capacity #定義PV空間的大小
    storage #指定大小

[[email protected] ~]# kubectl explain pvc.spec.
spec:
  accessModes #定義訪問模式,必須是PV的訪問模式的子集
  resources #定義申請資源的大小#
    requests:
      storage: 

配置NFS存儲

[[email protected] volumes]# mkdir v{1..5} -p
[[email protected] volumes]# ll
總用量 4
-rw-r--r-- 1 root root 19 4月   2 14:49 index.html
drwxr-xr-x 2 root root  6 4月   2 16:42 v1
drwxr-xr-x 2 root root  6 4月   2 16:42 v2
drwxr-xr-x 2 root root  6 4月   2 16:42 v3
drwxr-xr-x 2 root root  6 4月   2 16:42 v4
drwxr-xr-x 2 root root  6 4月   2 16:42 v5

[[email protected] volumes]# vim /etc/exports
/data/volumes/v1 10.0.0.0/24(rw,no_root_squash)
/data/volumes/v2 10.0.0.0/24(rw,no_root_squash)
/data/volumes/v3 10.0.0.0/24(rw,no_root_squash)
/data/volumes/v4 10.0.0.0/24(rw,no_root_squash)
/data/volumes/v5 10.0.0.0/24(rw,no_root_squash)
[[email protected] volumes]# exportfs -rv
exporting 10.0.0.0/24:/data/volumes/v5
exporting 10.0.0.0/24:/data/volumes/v4
exporting 10.0.0.0/24:/data/volumes/v3
exporting 10.0.0.0/24:/data/volumes/v2
exporting 10.0.0.0/24:/data/volumes/v1
[[email protected] volumes]# showmount -e
Export list for nfs:
/data/volumes/v5 10.0.0.0/24
/data/volumes/v4 10.0.0.0/24
/data/volumes/v3 10.0.0.0/24
/data/volumes/v2 10.0.0.0/24
/data/volumes/v1 10.0.0.0/24

定義PV

這裏定義5個PV,並且定義掛載的路徑以及訪問模式,還有PV劃分的大小。

[[email protected] volume]# vim pv-demo.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv001
  labels:
    name: pv001
#pv不能定義名稱空間,屬於整個集群,pvc需要定義名稱空間
spec:
  nfs:
    path: /data/volumes/v1/
    server: nfs
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 1Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv002
  labels:
    name: pv002
spec:
  nfs:
    path: /data/volumes/v2/
    server: nfs
  accessModes: ["ReadWriteOnce"]
  capacity:
    storage: 2Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv003
  labels:
    name: pv003
spec:
  nfs:
    path: /data/volumes/v3/
    server: nfs
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 2Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv004
  labels:
    name: pv004
spec:
  nfs:
    path: /data/volumes/v4/
    server: nfs
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 4Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv005
  labels:
    name: pv005
spec:
  nfs:
    path: /data/volumes/v5/
    server: nfs
  accessModes: ["ReadWriteMany","ReadWriteOnce"]
  capacity:
    storage: 4Gi

1Gi=1024Mi=1024Ki
1G=1000M=1000K
創建PV

[[email protected] volume]# kubectl apply -f pv-demo.yaml 
persistentvolume/pv001 created
persistentvolume/pv002 created
persistentvolume/pv003 created
persistentvolume/pv004 created
persistentvolume/pv005 created
[[email protected] volume]# kubectl get pv
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pv001   1Gi        RWO,RWX        Retain           Available                                   3s
pv002   2Gi        RWO            Retain           Available                                   3s
pv003   2Gi        RWO,RWX        Retain           Available                                   3s
pv004   4Gi        RWO,RWX        Retain           Available                                   3s
pv005   4Gi        RWO,RWX        Retain           Available                                   3s

定義PVC

[[email protected] volume]# vim pod-pvc-vol.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mypvc
  namespace: default
spec:
  accessModes: ["ReadWriteMany"]
  resources:
    requests:
      storage: 3Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: pod-pvc-vol
  namespace: default
spec:
  containers:
  - name: myapp
    image: ikubernetes/myapp:v1
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html/
  volumes:
  - name: html
    persistentVoumeClaim:
      claimName: mypvc

創建PVC

[[email protected] volume]# kubectl apply -f pod-pvc-vol.yaml  
persistentvolumeclaim/mypvc created
pod/pod-nfs-vol created

查看驗證

[[email protected] volume]# kubectl get pvc
NAME    STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
mypvc   Bound    pv005    4Gi        RWO,RWX                       26s
[[email protected] volume]#  kubectl get pv
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM           STORAGECLASS   REASON   AGE
pv001   1Gi        RWO,RWX        Retain           Bound       default/mypvc                           14m
pv002   2Gi        RWO            Retain           Available                                           14m
pv003   2Gi        RWO,RWX        Retain           Available                                           14m
pv004   4Gi        RWO,RWX        Retain           Released    default/mypvc                           14m
pv005   4Gi        RWO,RWX        Retain           Released    default/mypvc                           14m

測試訪問

[[email protected] volume]# kubectl get pods -o wide           
NAME                                 READY   STATUS    RESTARTS   AGE     IP            NODE     NOMINATED NODE   READINESS GATES
myapp-backend-pod-6b56d98b6b-2dh5h   1/1     Running   0          8h      10.244.1.44   node01   <none>           <none>
myapp-backend-pod-6b56d98b6b-hwzws   1/1     Running   0          8h      10.244.2.49   node02   <none>           <none>
myapp-backend-pod-6b56d98b6b-ztwn2   1/1     Running   0          8h      10.244.2.48   node02   <none>           <none>
pod-hostpath-vol                     1/1     Running   0          179m    10.244.2.54   node02   <none>           <none>
pod-pvc-vol                          1/1     Running   0          4s      10.244.2.58   node02   <none>           <none>
tomcat-deploy-5f554cd88d-7gzc7       1/1     Running   0          7h27m   10.244.2.51   node02   <none>           <none>
tomcat-deploy-5f554cd88d-c42t6       1/1     Running   0          7h27m   10.244.2.50   node02   <none>           <none>
tomcat-deploy-5f554cd88d-qhc4j       1/1     Running   0          7h27m   10.244.1.45   node01   <none>           <none>

在存儲服務器上創建index.html,並寫入數據,通過訪問Pod進行查看,可以獲取到相應的頁面。

[[email protected] v1]# pwd
/data/volumes/v1
[[email protected] v1]# echo $(date)>>./index.html
[[email protected] v1]# echo $(date)>>./index.html
[[email protected] v1]# echo $(date)>>./index.html

[[email protected] volume]# curl 10.244.2.58
2019年 04月 02日 星期二 17:26:57 CST
2019年 04月 02日 星期二 17:27:08 CST
2019年 04月 02日 星期二 17:27:08 CST

StorageClass

在pv和pvc使用過程中存在的問題,在pvc申請存儲空間時,未必就有現成的pv符合pvc申請的需求,上面nfs在做pvc可以成功的因素是因為我們做了指定的需求處理。那麽當PVC申請的存儲空間不一定有滿足PVC要求的PV事,又該如何處理呢???為此,Kubernetes為管理員提供了描述存儲"class(類)"的方法(StorageClass)。舉個例子,在存儲系統中劃分一個1TB的存儲空間提供給Kubernetes使用,當用戶需要一個10G的PVC時,會立即通過restful發送請求,從而讓存儲空間創建一個10G的image,之後在我們的集群中定義成10G的PV供給給當前的PVC作為掛載使用。在此之前我們的存儲系統必須支持restful接口,比如ceph分布式存儲,而glusterfs則需要借助第三方接口完成這樣的請求.

[[email protected] ~]# kubectl explain storageclass
KIND:     StorageClass
VERSION:  storage.k8s.io/v1

FIELDS:
   allowVolumeExpansion <boolean>

   allowedTopologies    <[]Object>

     feature.

   apiVersion   <string>

   kind <string>

   metadata     <Object>

   mountOptions <[]string>   #掛載選項

   parameters   <map[string]string> #參數,取決於分配器,可以接受不同的參數。 例如,參數 type 的值 io1 和參數 iopsPerGB 特定於 EBS PV。當參數被省略時,會使用默認值。  

   provisioner  <string> -required- #存儲分配器,用來決定使用哪個卷插件分配 PV。該字段必須指定。

   reclaimPolicy        <string> #回收策略,可以是 Delete 或者 Retain。如果 StorageClass 對象被創建時沒有指定 reclaimPolicy ,它將默認為 Delete。 

   volumeBindingMode    <string>   #卷的綁定模式

StorageClass 中包含 provisioner、parameters 和 reclaimPolicy 字段,當 class 需要動態分配 PersistentVolume 時會使用到。由於StorageClass需要一個獨立的存儲系統,此處就不再演示。

參考資料

https://www.cnblogs.com/linuxk
馬永亮. Kubernetes進階實戰 (雲計算與虛擬化技術叢書)
Kubernetes-handbook-jimmysong-20181218

Kubernetes之(十二)存儲卷