儲存

烟雨楼台,行云流水發表於2024-10-19

容器中的檔案在磁碟上是臨時存放的,這給在容器中執行較重要的應用帶來一些問題。 當容器崩潰或停止時會出現一個問題。此時容器狀態未儲存, 因此在容器生命週期內建立或修改的所有檔案都將丟失。 在崩潰期間,kubelet 會以乾淨的狀態重新啟動容器。 當多個容器在一個 Pod 中執行並且需要共享檔案時,會出現另一個問題。 跨所有容器設定和訪問共享檔案系統具有一定的挑戰性。

Kubernetes 卷(Volume) 這一抽象概念能夠解決這兩個問題。

emptyDir

對於定義了 emptyDir 卷的 Pod,在 Pod 被指派到某節點時此卷會被建立。 就像其名稱所表示的那樣,emptyDir 卷最初是空的。儘管 Pod 中的容器掛載 emptyDir 卷的路徑可能相同也可能不同,但這些容器都可以讀寫 emptyDir 卷中相同的檔案。 當 Pod 因為某些原因被從節點上刪除時,emptyDir 卷中的資料也會被永久刪除。

emptyDir 配置

[root@master NFS-storageclass]# cat po-2.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: registry.k8s.io/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir:
      sizeLimit: 500Mi
[root@master NFS-storageclass]# kubectl apply -f po-2.yaml 
pod/test-pd created
[root@master NFS-storageclass]# kubectl get po test-pd 
NAME      READY   STATUS    RESTARTS   AGE
test-pd   1/1     Running   0          2m2s

  

hostPath

hostPath 卷能將主機節點檔案系統上的檔案或目錄掛載到你的 Pod 中。 雖然這不是大多數 Pod 需要的,但是它為一些應用提供了強大的逃生艙。

hostPath 的一些用法有:

  • 執行一個需要訪問節點級系統元件的容器 (例如一個將系統日誌傳輸到集中位置的容器,使用只讀掛載 /var/log 來訪問這些日誌)
  • 讓儲存在主機系統上的配置檔案可以被靜態 Pod 以只讀方式訪問;與普通 Pod 不同,靜態 Pod 無法訪問 ConfigMap
[root@master svc]# cat ../host/po.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: host
spec:
  volumes:
  - name: test-host
    hostPath:
      path: /data
  containers:
  - name: web
    image: nginx
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: test-host
      mountPath: /test
  - name: cx
    image: tomcat:10
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: test-host
      mountPath: /chenxi
[root@master host]# kubectl exec -it host -c cx -- /bin/sh
# ls /    
bin   __cacert_entrypoint.sh  dev  home  lib64	mnt  proc  run	 srv  tmp  var
boot  chenxi		      etc  lib	 media	opt  root  sbin  sys  usr
# cd chenxi
/bin/sh: 2: cd: can't cd to chenxi
# ^[[A^[[B
/bin/sh: 3: : not found
# /bin/bash
root@host:/usr/local/tomcat# cd /chenxi/
root@host:/chenxi# echo "chenxi" > tomcat.txt
root@host:/chenxi# ls
tomcat.txt
[root@master ~]# kubectl exec -it host -c web -- /bin/bash
root@host:/# ls /test/
tomcat.txt
root@host:/# echo "nginx" >/test/nginx.txt
[root@master svc]# kubectl get po host -owide 
NAME   READY   STATUS    RESTARTS   AGE     IP              NODE     NOMINATED NODE   READINESS GATES
host   2/2     Running   0          6m52s   172.16.84.140   node-1   <none>           <none>
[root@node-1 ~]# ls /data/
nginx.txt  tomcat.txt

  nfs

nfs 卷能將 NFS (網路檔案系統) 掛載到你的 Pod 中。 不像 emptyDir 那樣會在刪除 Pod 的同時也會被刪除,nfs 卷的內容在刪除 Pod 時會被儲存,卷只是被解除安裝。 這意味著 nfs 卷可以被預先填充資料,並且這些資料可以在 Pod 之間共享。

[root@master ~]# cat /etc/exports
/data/kubernetes/pv1  192.168.10.0/24(rw,sync,no_root_squash,no_all_squash)
/data/kubernetes/pv2  192.168.10.0/24(rw,sync,no_root_squash,no_all_squash)
/data/kubernetes/pv3  192.168.10.0/24(rw,sync,no_root_squash,no_all_squash)
/data/kubernetes/pv4  192.168.10.0/24(rw,sync,no_root_squash,no_all_squash)
/data/kubernetes/pv5  192.168.10.0/24(rw,sync,no_root_squash,no_all_squash)
/data/kubernetes/pv6  192.168.10.0/24(rw,sync,no_root_squash,no_all_squash)
[root@master NFS-storageclass]# cat po.yaml 
apiVersion: v1
kind: Pod
metadata: 
  name: nfs-1
spec: 
  containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
    ports:
    - name: web
      containerPort: 80
    volumeMounts:
    - name: nfs-volumes
      mountPath: /nginx
  volumes:
  - name: nfs-volumes
    nfs:
      server: 192.168.10.29
      path: /data/kubernetes/pv2
[root@master NFS-storageclass]# kubectl apply -f po.yaml 
pod/nfs-1 created
[root@master NFS-storageclass]# kubectl describe pod nfs-1 
Name:             nfs-1
Namespace:        default
Priority:         0
Service Account:  default
Node:             node-1/192.168.10.30
Start Time:       Fri, 18 Oct 2024 10:02:04 +0800
Labels:           <none>
Annotations:      cni.projectcalico.org/containerID: ce2101862c7aaafc907faf6652859a564c3d63770892e2f91acf357fb245ef00
                  cni.projectcalico.org/podIP: 172.16.84.139/32
                  cni.projectcalico.org/podIPs: 172.16.84.139/32
Status:           Running
IP:               172.16.84.139
IPs:
  IP:  172.16.84.139
Containers:
  nginx:
    Container ID:   containerd://036aed08ecdce0b3aee06a5369673ae54123362fa4c43ab00b52ef0be7efb009
    Image:          nginx
    Image ID:       docker.io/library/nginx@sha256:d2eb56950b84efe34f966a2b92efb1a1a2ea53e7e93b94cdf45a27cf3cd47fc0
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Fri, 18 Oct 2024 10:02:05 +0800
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /nginx from nfs-volumes (rw)
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-b8h9m (ro)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  nfs-volumes:
    Type:      NFS (an NFS mount that lasts the lifetime of a pod)
    Server:    192.168.10.29
    Path:      /data/kubernetes/pv2
    ReadOnly:  false
  kube-api-access-b8h9m:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  27s   default-scheduler  Successfully assigned default/nfs-1 to node-1
  Normal  Pulled     27s   kubelet            Container image "nginx" already present on machine
  Normal  Created    26s   kubelet            Created container nginx
  Normal  Started    26s   kubelet            Started container nginx
[root@master NFS-storageclass]# kubectl exec -it nfs-1  -- /bin/bash
root@nfs-1:/# ls nginx/
root@nfs-1:/# cd /nginx/
root@nfs-1:/nginx# echo "nginx" > nginx.txt 
root@nfs-1:/nginx# ls
nginx.txt
[root@master ~]# ls /data/kubernetes/pv2/
nginx.txt
[root@master ~]# cat /data/kubernetes/pv2/
cat: /data/kubernetes/pv2/: 是一個目錄
[root@master ~]# cat /data/kubernetes/pv2/nginx.txt 
nginx

 Persistent Volumes

本文描述 Kubernetes 中的持久卷(Persistent Volumes)

PersistentVolume 子系統為使用者和管理員提供了一組 API, 將儲存如何製備的細節從其如何被使用中抽象出來。 為了實現這點,我們引入了兩個新的 API 資源:PersistentVolume 和 PersistentVolumeClaim。

持久卷(PersistentVolume,PV) 是叢集中的一塊儲存,可以由管理員事先製備, 或者使用儲存類(Storage Class)來動態製備。 持久卷是叢集資源,就像節點也是叢集資源一樣。PV 持久卷和普通的 Volume 一樣, 也是使用卷外掛來實現的,只是它們擁有獨立於任何使用 PV 的 Pod 的生命週期。 此 API 物件中記述了儲存的實現細節,無論其背後是 NFS、iSCSI 還是特定於雲平臺的儲存系統。

持久卷申領(PersistentVolumeClaim,PVC) 表達的是使用者對儲存的請求。概念上與 Pod 類似。 Pod 會耗用節點資源,而 PVC 申領會耗用 PV 資源。Pod 可以請求特定數量的資源(CPU 和記憶體)。同樣 PVC 申領也可以請求特定的大小和訪問模式 (例如,可以掛載為 ReadWriteOnce、ReadOnlyMany、ReadWriteMany 或 ReadWriteOncePod, 請參閱訪問模式)。

儘管 PersistentVolumeClaim 允許使用者消耗抽象的儲存資源, 常見的情況是針對不同的問題使用者需要的是具有不同屬性(如,效能)的 PersistentVolume 卷。 叢集管理員需要能夠提供不同性質的 PersistentVolume, 並且這些 PV 卷之間的差別不僅限於卷大小和訪問模式,同時又不能將卷是如何實現的這些細節暴露給使用者。 為了滿足這類需求,就有了儲存類(StorageClass) 資源。

卷和申領的生命週期

PV 卷是叢集中的資源。PVC 申領是對這些資源的請求,也被用來執行對資源的申領檢查。 PV 卷和 PVC 申領之間的互動遵循如下生命週期:

製備

PV 卷的製備有兩種方式:靜態製備或動態製備。

靜態製備

叢集管理員建立若干 PV 卷。這些卷物件帶有真實儲存的細節資訊, 並且對叢集使用者可用(可見)。PV 卷物件存在於 Kubernetes API 中,可供使用者消費(使用)。

動態製備

如果管理員所建立的所有靜態 PV 卷都無法與使用者的 PersistentVolumeClaim 匹配, 叢集可以嘗試為該 PVC 申領動態製備一個儲存卷。 這一製備操作是基於 StorageClass 來實現的:PVC 申領必須請求某個 儲存類, 同時叢集管理員必須已經建立並配置了該類,這樣動態製備卷的動作才會發生。 如果 PVC 申領指定儲存類為 "",則相當於為自身禁止使用動態製備的卷。

為了基於儲存類完成動態的儲存製備,叢集管理員需要在 API 伺服器上啟用 DefaultStorageClass 准入控制器。 舉例而言,可以透過保證 DefaultStorageClass 出現在 API 伺服器元件的 --enable-admission-plugins 標誌值中實現這點;該標誌的值可以是逗號分隔的有序列表。 關於 API 伺服器標誌的更多資訊,可以參考 kube-apiserver 文件。

繫結

使用者建立一個帶有特定儲存容量和特定訪問模式需求的 PersistentVolumeClaim 物件; 在動態製備場景下,這個 PVC 物件可能已經建立完畢。 控制平面中的控制迴路監測新的 PVC 物件,尋找與之匹配的 PV 卷(如果可能的話), 並將二者繫結到一起。 如果為了新的 PVC 申領動態製備了 PV 卷,則控制迴路總是將該 PV 卷繫結到這一 PVC 申領。 否則,使用者總是能夠獲得他們所請求的資源,只是所獲得的 PV 卷可能會超出所請求的配置。 一旦繫結關係建立,則 PersistentVolumeClaim 繫結就是排他性的, 無論該 PVC 申領是如何與 PV 卷建立的繫結關係。 PVC 申領與 PV 卷之間的繫結是一種一對一的對映,實現上使用 ClaimRef 來記述 PV 卷與 PVC 申領間的雙向繫結關係。

如果找不到匹配的 PV 卷,PVC 申領會無限期地處於未繫結狀態。 當與之匹配的 PV 卷可用時,PVC 申領會被繫結。 例如,即使某叢集上製備了很多 50 Gi 大小的 PV 卷,也無法與請求 100 Gi 大小的儲存的 PVC 匹配。當新的 100 Gi PV 卷被加入到叢集時, 該 PVC 才有可能被繫結。

使用

Pod 將 PVC 申領當做儲存捲來使用。叢集會檢視 PVC 申領,找到所繫結的卷, 併為 Pod 掛載該卷。對於支援多種訪問模式的卷, 使用者要在 Pod 中以卷的形式使用申領時指定期望的訪問模式。

一旦使用者有了申領物件並且該申領已經被繫結, 則所繫結的 PV 卷在使用者仍然需要它期間一直屬於該使用者。 使用者透過在 Pod 的 volumes 塊中包含 persistentVolumeClaim 節區來排程 Pod,訪問所申領的 PV 卷。 相關細節可參閱使用申領作為卷

保護使用中的儲存物件

保護使用中的儲存物件(Storage Object in Use Protection) 這一功能特性的目的是確保仍被 Pod 使用的 PersistentVolumeClaim(PVC) 物件及其所繫結的 PersistentVolume(PV)物件在系統中不會被刪除,因為這樣做可能會引起資料丟失。

PV

[root@master pv]# cat pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-cx
spec:
  capacity: 
    storage: 1Gi
  accessModes: ["ReadWriteOnce"]
  nfs:
    server: 192.168.10.29
    path: /data/kubernetes/pv3
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-cx-2
spec:
  capacity: 
    storage: 2Gi
  accessModes: ["ReadWriteMany"]
  nfs:
    server: 192.168.10.29
    path: /data/kubernetes/pv4
[root@master pv]# kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM                STORAGECLASS          REASON   AGE
nfs-cx                                     1Gi        RWO            Retain           Available                                                       8m20s
nfs-cx-2                                   2Gi        RWX            Retain           Available                                                       8m20s
[root@master pv]# cat pvc.yaml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: cx-pvc
spec:
  accessModes: ["ReadWriteMany"]
  resources:
    requests:
      storage: 2Gi 

[root@master pv]# kubectl get pvc
NAME         STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
cx-pvc       Bound    nfs-cx-2                                   2Gi        RWX                                  9m43s

[root@master pv]# cat po.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
    - name: myfrontend
      image: nginx
      volumeMounts:
      - mountPath: "/var/www/html"
        name: mypd
  volumes:
    - name: mypd
      persistentVolumeClaim:
        claimName: cx-pvc
[root@master pv]# kubectl describe po mypod 
Name:             mypod
Namespace:        default
Priority:         0
Service Account:  default
Node:             node-2/192.168.10.31
Start Time:       Sat, 19 Oct 2024 09:28:22 +0800
Labels:           <none>
Annotations:      cni.projectcalico.org/containerID: 59ba3be077ca2c966a44cbd16404fcf88075394125a16d4e4c32cba4a7a281e3
                  cni.projectcalico.org/podIP: 172.16.247.40/32
                  cni.projectcalico.org/podIPs: 172.16.247.40/32
Status:           Running
IP:               172.16.247.40
IPs:
  IP:  172.16.247.40
Containers:
  myfrontend:
    Container ID:   containerd://3817af539efa8fd11e1f082cfb57d315ecfb48db14ed951c9e124c0901ba58df
    Image:          nginx
    Image ID:       docker.io/library/nginx@sha256:28402db69fec7c17e179ea87882667f1e054391138f77ffaf0c3eb388efc3ffb
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Sat, 19 Oct 2024 09:28:53 +0800
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-vv7kt (ro)
      /var/www/html from mypd (rw)
Conditions:
  Type              Status
  Initialized       True 
  Ready             True 
  ContainersReady   True 
  PodScheduled      True 
Volumes:
  mypd:
    Type:       PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
    ClaimName:  cx-pvc
    ReadOnly:   false
  kube-api-access-vv7kt:
    Type:                    Projected (a volume that contains injected data from multiple sources)
    TokenExpirationSeconds:  3607
    ConfigMapName:           kube-root-ca.crt
    ConfigMapOptional:       <nil>
    DownwardAPI:             true
QoS Class:                   BestEffort
Node-Selectors:              <none>
Tolerations:                 node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
                             node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
  Type    Reason     Age    From               Message
  ----    ------     ----   ----               -------
  Normal  Scheduled  5m24s  default-scheduler  Successfully assigned default/mypod to node-2
  Normal  Pulling    5m22s  kubelet            Pulling image "nginx"
  Normal  Pulled     4m53s  kubelet            Successfully pulled image "nginx" in 28.407s (28.408s including waiting)
  Normal  Created    4m53s  kubelet            Created container myfrontend
  Normal  Started    4m53s  kubelet            Started container myfrontend

  儲存類: https://www.cnblogs.com/rdchenxi/p/17113820.html

相關文章