介紹
- 容器中的文件在磁盤上是臨時存放的,這給容器中運行的特殊應用程序帶來一些問題。首先,當容器崩潰時,kubelet 將重新啓動容器,容器中的文件將會丟失,因爲容器會以乾淨的狀態重建。其次,當在一個 Pod 中同時運行多個容器時,常常需要在這些容器之間共享文件。 Kubernetes 抽象出 Volume 對象來解決這兩個問題。
- Kubernetes 卷具有明確的生命週期,與包裹它的 Pod 相同。 因此,卷比 Pod 中運行的任何容器的存活期都長,在容器重新啓動時數據也會得到保留。 當然,默認情況下當一個 Pod 不再存在時,卷也將不再存在,我們通也也可以做卷的持久化。也許更重要的是,Kubernetes 可以支持許多類型的卷,Pod 也能同時使用任意數量的卷。
- 卷不能掛載到其他卷,也不能與其他卷有硬鏈接。 Pod 中的每個容器必須獨立地指定每個卷的掛載位置。
- 實質上就是把數據和鏡像進行解耦,進行存儲。
- Kubernetes 支持下列類型的卷:
- awsElasticBlockStore 、azureDisk、azureFile、cephfs、cinder、configMap、csi
- downwardAPI、emptyDir、fc (fibre channel)、flexVolume、flocker
- gcePersistentDisk、gitRepo (deprecated)、glusterfs、hostPath、iscsi、local、
- nfs、persistentVolumeClaim、projected、portworxVolume、quobyte、rbd
- scaleIO、secret、storageos、vsphereVolume
emptyDir卷
-
emptyDir卷
- 當 Pod 指定到某個節點上時,首先創建的是一個 emptyDir 卷,並且只要 Pod 在該節點上運行,卷就一直存在。 就像它的名稱表示的那樣,卷最初是空的。 儘管Pod 中的容器掛載 emptyDir 卷的路徑可能相同也可能不同,但是這些容器都可以讀寫 emptyDir 卷中相同的文件。 當 Pod 因爲某些原因被從節點上刪除時,emptyDir 卷中的數據也會永久刪除。
-
emptyDir 的
使用場景
:- 緩存空間,例如基於磁盤的歸併排序。
- 爲耗時較長的計算任務提供檢查點,以便任務能方便地從崩潰前狀態恢復執行。
- 在 Web 服務器容器服務數據時,保存內容管理器容器獲取的文件。
-
默認情況下, emptyDir 卷存儲在支持該節點所使用的介質上;這裏的介質可以是磁盤或 SSD 或網絡存儲,這取決於您的環境。 但是,您可以將 emptyDir.medium 字段設置爲 “Memory”,以告訴 Kubernetes 爲您安裝
tmpfs
(基於內存的文件系統)。雖然tmpfs 速度非常快,但是要注意它與磁盤不同。 tmpfs 在節點重啓時會被清除,並且您所寫入的所有文件都會計入容器的內存消耗
,受容器內存限制約束。
示例:
apiVersion: v1
kind: Pod
metadata:
name: vol1
spec:
containers:
- name: vm1
image: busyboxplus
command: ["sleep", "300"]
volumeMounts:
- mountPath: /cache
name: cache-volume //掛載
- name: vm2
image: nginx
volumeMounts:
- mountPath: /usr/share/nginx/html //掛載到nginx發佈頁面
name: cache-volume //掛載
volumes:
- name: cache-volume //卷名稱
emptyDir:
medium: Memory //可以不指定使用內存,這兩行可以省略
sizeLimit: 100Mi
//卷被一個pod的多個容器掛載到了不同的路徑,但是他們數據是同步的
[root@server2 vol]# kubectl apply -f vol1.yml
pod/vol1 created
[root@server2 vol]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
my-nginx-7f45d597d5-9hk7h 1/1 Running 0 2m37s 10.244.141.221 server3 <none> <none>
vol1 2/2 Running 0 31s 10.244.22.21 server4 <none> <none>
[root@server2 vol]# curl 10.244.22.21
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.19.0</center>
</body> //說明服務是沒有問題的
他們之間共享網絡棧,而且共享卷,目前是空卷,所以我們去創建數據。
[root@server2 vol]# kubectl exec -it vol1 -c vm1 -- sh //登進pod的vm容器
Defaulting container name to vm1.
Use 'kubectl describe pod/vol1 -n default' to see all of the containers in this pod.
/ # cd cache/
/cache # ls
/cache # echo woaini > index.html /在容器一的掛載目錄創建文件
/cache #
[root@server2 vol]# curl 10.244.22.21
woaini
卻可以通過容器二的nginx服務訪問到了。說明通過卷在做數據共享。
我們的卷使用的是物理內存,直接消耗系統當中的內存量。
當前pod掛載在server4上,它的內存還有:
[root@server4 ~]# free -m
total used free shared buff/cache available
Mem: 1999 368 832 18 797 1445 /還有這些
Swap: 0 0 0
我們現在測試剛纔設置的內存限制。
[root@server2 vol]# kubectl exec -it vol1 -c vm1 -- sh
/ # cd cache/
/cache # dd if=/dev/zero of=bigfile bs=1M count=100
100+0 records in
100+0 records out
[root@server4 ~]# free -m
total used free shared buff/cache available
Mem: 1999 377 723 118 897 1336 /少了100M
Swap: 0 0 0
/cache # dd if=/dev/zero of=bigfile bs=1M count=200 /在截取200M
300+0 records in
300+0 records out
[root@server4 ~]# free -m
total used free shared buff/cache available
Mem: 1999 374 526 318 1098 1139 /少了200M
Swap: 0
竟然也能成功,我們不是設置了最多100M嗎。
/cache # command terminated with exit code 137 這是我們的pod突然退出了
^C[root@server2 vol]# kubectl get pod
NAME READY STATUS RESTARTS AGE
my-nginx-7f45d597d5-9hk7h 1/1 Running 0 15m
vol1 0/2 Evicted 0 12m
[root@server4 ~]# free -m
total used free shared buff/cache available
Mem: 1999 352 850 17 796 1462 /內存歸還了
Swap: 0
- 可以看到文件超過sizeLimit,則一段時間後(1-2分鐘)會被kubelet evict掉。
- 之所以不是“立即”被evict,是因爲kubelet是定期進行檢查的,這裏會有一個時間差。
- 一段時間後 kubelet 識別到它已經超出了內存限制,就把她驅逐了。
但是爲什麼這樣的操作可以執行哪,我們發現剛纔的操作已經跳過了k8s的監管,這就說明在使用內存當作卷的存儲時,是具有風險的,做的限制也不是事時的。
- emptydir缺點:
- 不能及時禁止用戶使用內存。雖然過1-2分鐘kubelet會將Pod擠出,但是這個時間內,其實
對node還是有風險的; - 影響kubernetes調度,因爲empty dir並不涉及node的resources,這樣會造成Pod“偷偷”
使用了node的內存,但是調度器並不知曉; - 用戶不能及時感知到內存不可用
- 不能及時禁止用戶使用內存。雖然過1-2分鐘kubelet會將Pod擠出,但是這個時間內,其實
hostPath卷
- hostPath 卷能將主機節點文件系統上的文件或目錄掛載到您的 Pod 中。 雖然這不是大多數 Pod
需要的,但是它爲一些應用程序提供了強大的逃生艙。
可以用於監控容器,把主機的文件掛接到pod中,通過pod中的監控進行識別。
-
hostPath 的一些用法有:
- 運行一個需要訪問 Docker 引擎內部機制的容器,掛載 /var/lib/docker 路徑。
- 在容器中運行 cAdvisor (監控)時,以 hostPath 方式掛載 /sys。
- 允許 Pod 指定給定的 hostPath 在運行 Pod 之前是否應該存在,是否應該創建以及應該以
什麼方式存在。
-
除了必需的 path 屬性之外,用戶可以選擇性地爲 hostPath 卷指定 type。
- 當使用這種類型的卷時要小心,因爲:
- 具有相同配置(例如從 podTemplate 創建)的多個 Pod 會由於節點上文件的不同而在不同
節點上有不同的行爲。 - 當 Kubernetes 按照計劃添加資源感知的調度時,這類調度機制將無法考慮由 hostPath 使
用的資源。 - 基礎主機上創建的文件或目錄只能由 root 用戶寫入。您需要在 特權容器 中以 root 身份運
行進程,或者修改主機上的文件權限以便容器能夠寫入 hostPath 卷。
- 具有相同配置(例如從 podTemplate 創建)的多個 Pod 會由於節點上文件的不同而在不同
示例:
[root@server2 vol]# vim vol1.yml
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: nginx
name: test-container
volumeMounts:
- mountPath: /usr/share/nginx/html /掛載到這裏
name: test-volume
volumes:
- name: test-volume
hostPath:
path: /data /映射宿主機的data目錄
type: DirectoryOrCreate /沒有就創建
[root@server3 ~]# ll -d /data
ls: cannot access /data: No such file or directo
[root@server4 ~]# ll -d /data
ls: cannot access /data: No such file or directo
當前我們的結點上是都沒/data 這個目錄的。
[root@server2 vol]# kubectl apply -f vol1.yml
pod/test-pd created
[root@server2 vol]# kubectl get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test-pd 1/1 Running 0 59s 10.244.141.223 server3 <none> <none>
/調度到了server3上
[root@server3 ~]# ll -d /data
drwxr-xr-x 2 root root 6 Jul 2 11:02 /data /創建了
[root@server3 data]# echo woaini >index.html /創建頁面
[root@server3 data]# ll
total 4
-rw-r--r-- 1 root root 7 Jul 2 11:06 index.html
[root@server2 vol]# kubectl get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test-pd 1/1 Running 0 6s 10.244.141.224 server3 <none> <none>
[root@server2 vol]# curl 10.244.141.224
woaini /就可以訪問到了
我們現在在server4上手動創建 /data 目錄,並編輯一個頁面:
[root@server4 ~]# mkdir /data
[root@server4 ~]# cd /data/
[root@server4 data]# echo 666 > index.html
然後修改yaml文件,選擇調度的結點在server4上:
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
nodeSelector:
kubernetes.io/hostname: server4 //這裏
containers:
- image: nginx
name: test-container
volumeMounts:
- mountPath: /usr/share/nginx/html
name: test-volume
volumes:
- name: test-volume
hostPath:
path: /data
type: DirectoryOrCreate
[root@server2 vol]# kubectl apply -f vol1.yml
kubec get podpod/test-pd created
[root@server2 vol]# kubectl get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test-pd 1/1 Running 0 4s 10.244.22.23 server4 <none> <none>
[root@server2 vol]# curl 10.244.22.23
666
現在訪問的卻是server4上的頁面,我們只是改變了調度的結點,它卻連頁面都改變了,這就說明這種卷的方式會受宿主機的影響,有干擾。
那我們怎樣讓數據一致哪?就可以使用nfs類型的卷。
NFS卷
- nfs 卷能將 NFS (網絡文件系統) 掛載到您的 Pod 中,讓多個結點掛載一個存儲。 不像 emptyDir 那樣會在刪除 Pod 的同時也會被刪除,nfs 卷的內容在刪除 Pod 時會被保存,卷只是被卸載掉了。 這意味着 nfs 卷可以被預先填充數據,並且這些數據可以在 Pod 之間"傳遞"。
[root@server1 ~]# yum install nfs-utils -y /安裝工具
[root@server1 ~]# mkdir /nfsdata /建立nfs數據目錄
[root@server1 ~]# vim /etc/exports
/nfsdata *(rw,sync) /將目錄共享出去
[root@server1 ~]# chmod 777 /nfsdata/
[root@server1 ~]# systemctl enable --now nfs /啓動服務
Created symlink from /etc/systemd/system/multi-user.target.wants/nfs-server.service to /usr/lib/systemd/system/nfs-server.service.
[root@server1 ~]# cd /nfsdata/
[root@server1 nfsdata]# echo 88888 > index.html /編輯一個頁面
[root@server1 ~]# showmount -e
Export list for server1:
/nfsdata * /共享出去了
然後去各個結點安裝nfs的支持:
[root@server3 ~]# yum insatll nfs-utils -y
[root@server4 ~]# yum insatll nfs-utils -y
[root@server4 data]# mount 172.25.254.1:/nfsdata /mnt/
[root@server4 data]# df
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/mapper/rhel-root 17811456 4220508 13590948 24% /
devtmpfs 1011516 0 1011516 0% /dev
tmpfs 1023608 0 1023608 0% /dev/shm
tmpfs 1023608 17532 1006076 2% /run
tmpfs 1023608 0 1023608 0% /sys/fs/cgroup
/dev/sda1 1038336 135224 903112 14% /boot
tmpfs 204724 0 204724 0% /run/user/
172.25.254.1:/nfsdata 17811456 12813440 4998016 72% /mnt /可以掛載了
[root@server4 data]# umount /mnt/
[root@server2 vol]# vim vol1.yml
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
containers:
- image: nginx
name: test-container
volumeMounts:
- mountPath: /usr/share/nginx/html
name: test-volume
volumes:
- name: test-volume
nfs: /設置類型爲nfs
server: 172.25.254.1 /指定ip和目錄
path: /nfsdata
[root@server2 vol]# kubectl apply -f vol1.yml
pod/test-pd created
[root@server2 vol]# kubectl get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test-pd 1/1 Running 0 7s 10.244.141.225 server3 <none> <none>
[root@server2 vol]# curl 10.244.141.225
88888
調度到server4上:
[root@server2 vol]# vim vol1.yml
apiVersion: v1
kind: Pod
metadata:
name: test-pd
spec:
nodeSelector:
kubernetes.io/hostname: server4 //指定標籤
containers:
- image: nginx
name: test-container
volumeMounts:
- mountPath: /usr/share/nginx/html
name: test-volume
volumes:
- name: test-volume
nfs:
server: 172.25.254.1
path: /nfsdata
[root@server2 vol]# kubectl apply -f vol1.yml
pod/test-pd created
[root@server2 vol]# kubectl get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
test-pd 1/1 Running 0 6s 10.244.22.24 server4 <none> <none>
[root@server2 vol]# curl 10.244.22.24
88888
看出不論pod運行在那個結點,數據都是一致的。