Kubernetes系列之Kubernetes存儲卷
### 第一章、前言
默認情況下容器的數據都是非持久化的, 在容器消亡以後數據也跟著丟失, 所以 Docker 提供了 Volume 機制以便將數據持久化存儲。 類似的, Kubernetes 提供了更強大的 Volume 機制和豐富的插件, 解決了容器數據持久化和容器間共享數據的問題。
與 Docker 不同, Kubernetes Volume 的生命週期與 Pod 綁定容器掛掉後 Kubelet 再次重啟容器時, Volume 的數據依然還在而 Pod 刪除時, Volume 才會清理。
數據是否丟失取決於具體的 Volume 類型, 比如 emptyDir 的數據會丟失, 而 PV 的數據則不會丟
PersistentVolume(pv)和PersistentVolumeClaim(pvc)是k8s提供的兩種API資源,用於抽象存儲細節。管理員關注於如何通過pv提供存儲功能而無需關注用戶如何使用,同樣的用戶只需要掛載pvc到容器中而不需要關注存儲卷採用何種技術實現。
pvc和pv的關係與pod和node關係類似,前者消耗後者的資源。pvc可以向pv申請指定大小的存儲資源並設置訪問模式。
### 第二章、pv pvc相關知識
#### 生命週期
pv和pvc遵循以下生命週期:
1.供應準備。管理員在集群中創建多個pv供用戶使用。
2.綁定。用戶創建pvc並指定需要的資源和訪問模式。在找到可用pv之前,pvc會保持未綁定狀態。
3.使用。用戶可在pod中像volume一樣使用pvc。
4.釋放。用戶刪除pvc來回收存儲資源,pv將變成“released”狀態。由於還保留著之前的數據,這些數據需要根據不同的策略來處理,否則這些存儲資源無法被其他pvc使用。
5.回收。pv可以設置三種回收策略:保留(Retain),回收(Recycle)和刪除(Delete)。
保留策略允許人工處理保留的數據。
刪除策略將刪除pv和外部關聯的存儲資源,需要插件支持。
回收策略將執行清除操作,之後可以被新的pvc使用,需要插件支持。
#### pv屬性
pv擁有以下屬性:
容量。目前僅支持存儲大小,未來可能支持IOPS和吞吐量等。
訪問模式。ReadWriteOnce:單個節點讀寫。ReadOnlyMany:多節點只讀。ReadWriteMany:多節點讀寫。掛載時只能使用一種模式。
回收策略。目前NFS和HostPath支持回收。 AWS、EBS、GCE、PD和Cinder支持刪除。
階段。分為Available(未綁定pvc)、Bound(已綁定)、Released(pvc已刪除但資源未回收)、Failed(自動回收失敗)
#### pvc屬性
訪問模式。與pv的語義相同。在請求資源時使用特定模式。
資源。申請的存儲資源數量
#### pv類型
emptyDir
hostPath
gcePersistentDisk
awsElasticBlockStore
nfs
iscsi
flocker
glusterfs
rbd
cephfs
gitRepo
secret
persistentVolumeClaim
downwardAPI
azureFileVolume
................
........(以下省略)
#### 目前常用Volume 類型
**emptyDir**
如果 Pod 設置了 emptyDir 類型 Volume, Pod 被分配到 Node 上時候, 會創建emptyDir, 只要 Pod 運行在 Node 上, emptyDir 都會存在( 容器掛掉不會導致emptyDir 丟失數據) , 但是如果 Pod 從 Node 上被刪除( Pod 被刪除, 或者 Pod 發生遷移) , emptyDir 也會被刪除, 並且永久丟失。
**hostPath**
hostPath 允許掛載 Node 上的文件系統到 Pod 裡面去。 如果 Pod 需要使用 Node 上的文件, 可以使用 hostPath
**NFS**
NFS 是 Network File System 的縮寫, 即網絡文件系統。 Kubernetes 中通過簡單地配置就可以掛載 NFS 到 Pod 中, 而 NFS 中的數據是可以永久保存的, 同時 NFS 支持同時寫操作。
**gcePersistentDisk**
gcePersistentDisk 可以掛載 GCE 上的永久磁盤到容器, 需要 Kubernetes 運行在 GCE的 VM 中
**awsElasticBlockStore**
awsElasticBlockStore 可以掛載 AWS 上的 EBS 盤到容器, 需要 Kubernetes 運行在AWS 的 EC2 上。
**gitRepo**
gitRepo volume 將 git 代碼下拉到指定的容器路徑中
**Projected Volume**
Projected volume 將多個 Volume 源映射到同一個目錄中, 支持 secret、 downwardAPI和 configMap
### 第三章、簡單示例
**1、emptyDir (節點級存儲,生命週期與pod相同)**
```
# cat emptydir.yaml #pod中有兩個container掛載同一個emptyDir,nginx提供web服務,busybox則循環向掛載目錄下的index.html文件寫入數據
apiVersion: v1
kind: Pod
metadata:
name: emptydir
namespace: default
labels:
app: myapp
tier: frontend
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
ports:
- name: myapp
containerPort: 80
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
- name: busybox
image: busybox:latest
volumeMounts: #見pod的volume掛載到container中
- name: html #名稱需要和 volumes中的name一致
mountPath: /data #掛載volume在container中的路徑
command:
- "/bin/sh"
- "-c"
- "while true; do echo $(date) >> /data/index.html; sleep 2; done"
volumes: #創建pod可以使用的volume,可以有多個
- name: html
emptyDir: {} #volume類型,默認不限制使用空間
```
**查看pod運行狀態,並訪問**
```
# kubectl apply -f emptydir.yaml
pod/emptydir created
# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
emptydir 2/2 Running 0 76s 10.244.3.34 huoban-k8s-node01
# while true; do curl 10.244.3.34; sleep 1; done
Fri Sep 20 03:34:38 UTC 2019
Fri Sep 20 03:34:40 UTC 2019
Fri Sep 20 03:34:42 UTC 2019
......
```
**2、[hostPath](https://kubernetes.io/docs/concepts/storage/volumes#hostpath) (節點級存儲,生命週期和node相同)**
```
#cat host-path.yaml
---
apiVersion: v1
kind: Pod
metadata:
name: pod-hostpath
namespace: default
spec:
containers: - name: myapp
image: ikubernetes/myapp:v1
volumeMounts: - name: html
mountPath: /usr/share/nginx/html
volumes: - name: html
hostPath:
path: "/data/pod/volumel" #依據type的值來確定掛載路徑是否需要創建 type: DirectoryOrCreate #掛載目錄不存在則創建
# kubectl apply -f host-path.yaml
pod/pod-hostpath created
# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
pod-hostpath 1/1 Running 0 58s 10.244.5.11 huoban-k8s-node03
```
**手動創建目錄並添加html文件測試**
```
# ssh node3 "ls -l /data/pod/volumel"
.
# ssh node03 "touch /data/pod/volumel/index.html"
# ssh node03 "ls -al /data/pod/volumel"
total 8
drwxr-xr-x 2 root root 4096 Sep 20 15:00 .
drwxr-xr-x 3 root root 4096 Sep 20 14:56 ..
-rw-r--r-- 1 root root 0 Sep 20 15:00 index.html
# echo "node03" > /data/pod/volumel/index.html #在node03服務器上執行
# cat /data/pod/volumel/index.html
node03
# curl 10.244.5.11
node03
#刪除服務,數據還在
# kubectl delete -f host-path.yaml
pod "pod-hostpath" deleted
# ssh node03 "ls -al /data/pod/volumel"
total 12
drwxr-xr-x 2 root root 4096 Sep 20 15:00 .
drwxr-xr-x 3 root root 4096 Sep 20 14:56 ..
-rw-r--r-- 1 root root 7 Sep 20 15:04 index.html
```
**3、NFS (永久存儲,生命週期與NFS server相同,不會刪除)**
```
1、在master上操作
# cat pod-nfs-vol.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-nfs
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/v1" #該目錄在NFS server上必須存在並可以被集群中node節點可以掛載,node節點需要安裝nfs-utils,可以執行NFS 掛載操作
server: 172.16.17.10 #該server需要安裝NFS 服務,並共享path中的目錄或文件
2、在其中一臺node節點上做測試
# mount -t nfs 172.16.17.10:/data/volumes/v1 /mnt 在任意一節點上進行掛載測試,確定可以掛載是否可以成功,需要安裝nfs-utils工具包
# df -h |grep mnt #查看掛載狀態
172.16.17.10:/data/volumes/v1 77G 3.5G 74G 5% /mnt
# umount /mnt #確認沒有問題後卸載
3、測試運行
# kubectl apply -f pod-nfs-vol.yaml #創建pod
pod "pod-nfs" created
# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
pod-nfs 1/1 Running 0 17s 10.244.1.154 huoban-k8s-node01
4、在節點上測試創建文件
#在NFS server上添加一個測試HTML文件
# cd /data/volumes/v1/ #掛載目錄
# echo "
NFS Server volume v1
" > index.html5、訪問一下並測試數據是否丟失
# curl 10.244.1.154
NFS Server volume v1
# kubectl delete pod pod-nfs #刪除剛剛創建的pod
pod "pod-nfs" deleted
# kubectl apply -f pod-nfs-vol.yaml #再重新創建
pod "pod-nfs" created
# kubectl get pod -o wide #查看新創建後pod所在的node節點級IP地址
NAME READY STATUS RESTARTS AGE IP NODE
pod-nfs 1/1 Running 0 17s 10.244.2.192 huoban-k8s-node02
# curl 10.244.2.192 #再次訪問一下,文件依然存在,文件不會隨著pod的終結而銷燬
NFS Server volume v1
```
**4、創建PV和PVC(用NFS創建)**
```
NFS server上創建多個掛載目錄,並共享
# cat /etc/exports
/data/volumes/v1 172.16.0.0/16(rw,no_root_squash)
/data/volumes/v2 172.16.0.0/16(rw,no_root_squash)
/data/volumes/v3 172.16.0.0/16(rw,no_root_squash)
/data/volumes/v4 172.16.0.0/16(rw,no_root_squash)
/data/volumes/v5 172.16.0.0/16(rw,no_root_squash)
# ll /data/volumes/
總用量 0
drwxr-xr-x 2 root root 24 2019-09-20 16:28 v1
drwxr-xr-x 2 root root 24 2019-09-20 16:28 v2
drwxr-xr-x 2 root root 24 2019-09-20 16:28 v3
drwxr-xr-x 2 root root 24 2019-09-20 16:28 v4
drwxr-xr-x 2 root root 24 2019-09-20 16:28 v5
# exportfs
/data/volumes/v1 172.16.0.0/16
/data/volumes/v2 172.16.0.0/16
/data/volumes/v3 172.16.0.0/16
/data/volumes/v4 172.16.0.0/16
/data/volumes/v5 172.16.0.0/16
# showmount -e
Export list for huoban-k8s-nfs:
/data/volumes/v5 172.16.0.0/16
/data/volumes/v4 172.16.0.0/16
/data/volumes/v3 172.16.0.0/16
/data/volumes/v2 172.16.0.0/16
/data/volumes/v1 172.16.0.0/16
將NFS server共享的目錄創建為PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-vol-001 #不允許定義名稱空間,應為pv是屬於集群級別的
spec:
capacity: #pv的大小
storage: 5Gi
accessModes: #訪問的模型,具體訪問模型官方文檔鏈接: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes
- ReadWriteOnce #支持的訪問模型與具體的共享存儲設備類型有關,具體見上方鏈接
- ReadWriteMany
persistentVolumeReclaimPolicy: Recycle
nfs:
path: /data/volumes/v1
server: 172.16.17.10
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-vol-02
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
nfs:
path: /data/volumes/v2
server: 172.16.17.10
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-vol-03
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
- ReadWriteMany
persistentVolumeReclaimPolicy: Recycle
nfs:
path: /data/volumes/v3
server: 172.16.17.10
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-vol-04
spec:
capacity:
storage: 15Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
nfs:
path: /data/volumes/v4
server: 172.16.17.10
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-vol-05
spec:
capacity:
storage: 20Gi
accessModes:
- ReadWriteOnce
- ReadWriteMany
persistentVolumeReclaimPolicy: Recycle
nfs:
path: /data/volumes/v5
server: 172.16.17.10
# kubectl apply -f nfs-vol.yaml
persistentvolume "nfs-vol-01" created
persistentvolume "nfs-vol-02" created
persistentvolume "nfs-vol-03" created
persistentvolume "nfs-vol-04" created
persistentvolume "nfs-vol-05" created
# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
nfs-vol-01 5Gi RWO,RWX Recycle Available 7s
nfs-vol-02 5Gi RWO Recycle Available 7s
nfs-vol-03 10Gi RWO,RWX Recycle Available 7s
nfs-vol-04 15Gi RWO Recycle Available 7s
nfs-vol-05 20Gi RWO,RWX Recycle Available 7s
#創建一個PVC
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
namespace: default
spec:
accessModes: ["ReadWriteOnce"] #pvc的訪問模式一定是pv訪問模式的子集
resources:
requests:
storage: 5Gi
---
apiVersion: v1
kind: Pod
metadata:
name: pod-pvc
namespace: default
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: html
persistentVolumeClaim:
claimName: my-pvc
# kubectl apply -f pod-pvc-vol.yaml
persistentvolumeclaim "my-pvc" created
pod "pod-pvc" created
# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
my-pvc Bound nfs-vol-02 5Gi RWO 1m
# kubectl get pv #查看pv狀態的變化,nfs-vol-02被 default名稱空間下my-pvc申請並綁定
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON A
nfs-vol-01 5Gi RWO,RWX Recycle Available 9
nfs-vol-02 5Gi RWO Recycle Bound default/my-pvc 9
nfs-vol-03 10Gi RWO,RWX Recycle Available 9
nfs-vol-04 15Gi RWO Recycle Available 9
nfs-vol-05 20Gi RWO,RWX Recycle Available
# 查看下pod的創建信息
# kubectl describe pod pod-pvc
......
Volumes:
html:
Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
ClaimName: my-pvc
ReadOnly: false
default-token-tcwjz:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-tcwjz
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 8m (x2 over 8m) default-scheduler pod has unbound PersistentVolumeClaims (repeated 2 times)
Normal Scheduled 8m default-scheduler Successfully assigned pod-pvc to huoban-k8s-node01
Normal SuccessfulMountVolume 8m kubelet, huoban-k8s-node01 MountVolume.SetUp succeeded for volume "default-token-tcwjz"
Normal SuccessfulMountVolume 8m kubelet, huoban-k8s-node01 MountVolume.SetUp succeeded for volume "nfs-vol-02"
Normal Pulled 8m kubelet, huoban-k8s-node01 Container image "ikubernetes/myapp:v1" already present on machine
Normal Created 7m kubelet, huoban-k8s-node01 Created container
Normal Started 7m kubelet, huoban-k8s-node01 Started container
#注意:處於綁定狀態下的pv無法直接被刪除,如果需要刪除被綁定的pv,需要先刪除申請綁定的PVC
```
閱讀更多 風月笑今生 的文章