kubernetes存儲 -- Volumes管理(一)emptyDir卷、hostpath卷、NFS卷

介紹

  • 容器中的文件在磁盤上是臨時存放的,這給容器中運行的特殊應用程序帶來一些問題。首先,當容器崩潰時,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的內存,但是調度器並不知曉;
    • 用戶不能及時感知到內存不可用

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 卷。

示例:

[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運行在那個結點,數據都是一致的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章