Kubernetes 提供了一種方式,使得 Pod 中的容器可以透過檔案系統訪問和共享資料。你可以使用不同型別的捲來實現不同的目的,例如:

  • 根據 ConfigMapSecret 填充配置檔案
  • 為 Pod 提供一些臨時暫存空間
  • 在同一個 Pod 中的兩個不同容器之間共享檔案系統
  • 在兩個不同的 Pod 之間共享檔案系統(即使這些 Pod 執行在不同的節點上)
  • 持久儲存資料,即使 Pod 重啟或被替換,資料仍然可用
  • 根據容器所在 Pod 的詳細資訊,將配置資訊傳遞給容器中執行的應用程式(例如:告訴 邊車容器 Pod 正在哪個名稱空間中執行)
  • 提供對不同容器映象中的資料的只讀訪問

資料共享可以在容器內部的不同本地程序之間、不同容器之間或不同 Pod 之間進行。

為什麼卷很重要

  • 資料永續性: 容器中的磁碟檔案是短暫的,這給在容器中執行的非簡單應用程式帶來了一些問題。一個問題是當容器崩潰或停止時,容器狀態不會被儲存,因此在容器生命週期中建立或修改的所有檔案都會丟失。崩潰後,kubelet 會以乾淨的狀態重新啟動容器。

  • 共享儲存: 另一個問題是當多個容器在 `Pod` 中執行並需要共享檔案時。在所有容器之間設定和訪問共享檔案系統可能很困難。

Kubernetes 抽象可以幫助你解決這兩個問題。

在你瞭解卷、PersistentVolume 和 PersistentVolumeClaim 之前,你應該閱讀 Pod,並確保你理解 Kubernetes 如何使用 Pod 執行容器。

卷的工作原理

Kubernetes 支援多種卷型別。一個 Pod 可以同時使用任意數量的卷型別。臨時卷 型別的生命週期與特定的 Pod 繫結,而 持久卷 存在於任何單個 Pod 的生命週期之外。當 Pod 不再存在時,Kubernetes 會銷燬臨時卷;但是,Kubernetes 不會銷燬持久卷。對於給定 Pod 中的任何型別的卷,資料在容器重啟後仍會保留。

從本質上講,卷是一個目錄,可能包含一些資料,可供 Pod 中的容器訪問。該目錄如何生成,其背後的介質以及其內容由所使用的特定卷型別決定。

要使用卷,請在 `.spec.volumes` 中指定要為 Pod 提供的卷,並在 `.spec.containers[*].volumeMounts` 中宣告將這些卷掛載到容器中的位置。

當 Pod 啟動時,容器中的程序會看到一個由 容器映象 的初始內容以及掛載在容器內部的卷(如果已定義)組成的檔案系統檢視。程序會看到一個最初與容器映象內容匹配的根檔案系統。對該檔案系統層次結構內任何(如果允許)的寫入都會影響該程序在後續檔案系統訪問時所看到的檢視。卷被掛載到容器檔案系統內的指定路徑。對於 Pod 中定義的每個容器,你必須獨立指定該容器使用的每個卷的掛載位置。

卷不能掛載到其他卷內部(但請參閱使用 subPath 來了解相關的機制)。此外,一個卷不能包含指向不同卷中任何內容的硬連結。

卷型別

Kubernetes 支援多種型別的卷。

awsElasticBlockStore (已棄用)

在 Kubernetes 1.34 中,樹內 `awsElasticBlockStore` 型別的所有操作都被重定向到 `ebs.csi.aws.com` CSI 驅動。

AWSElasticBlockStore 樹記憶體儲驅動在 Kubernetes v1.19 版本中被棄用,然後在 v1.27 版本中完全移除。

Kubernetes 專案建議你改用 AWS EBS 第三方儲存驅動。

azureDisk (已棄用)

在 Kubernetes 1.34 中,樹內 `azureDisk` 型別的所有操作都被重定向到 `disk.csi.azure.com` CSI 驅動。

AzureDisk 樹記憶體儲驅動在 Kubernetes v1.19 版本中被棄用,然後在 v1.27 版本中完全移除。

Kubernetes 專案建議你改用 Azure Disk 第三方儲存驅動。

azureFile (已棄用)

在 Kubernetes 1.34 中,樹內 `azureFile` 型別的所有操作都被重定向到 `file.csi.azure.com` CSI 驅動。

AzureFile 樹記憶體儲驅動在 Kubernetes v1.21 版本中被棄用,然後在 v1.30 版本中完全移除。

Kubernetes 專案建議你改用 Azure File 第三方儲存驅動。

cephfs (已移除)

Kubernetes 1.34 不包含 `cephfs` 卷型別。

`cephfs` 樹記憶體儲驅動在 Kubernetes v1.28 版本中被棄用,然後在 v1.31 版本中完全移除。

cinder (已棄用)

在 Kubernetes 1.34 中,樹內 `cinder` 型別的所有操作都被重定向到 `cinder.csi.openstack.org` CSI 驅動。

OpenStack Cinder 樹記憶體儲驅動在 Kubernetes v1.11 版本中被棄用,然後在 v1.26 版本中完全移除。

Kubernetes 專案建議你改用 OpenStack Cinder 第三方儲存驅動。

configMap

ConfigMap 提供了一種將配置資料注入 Pod 的方式。ConfigMap 中儲存的資料可以在 `configMap` 型別的卷中引用,然後由在 Pod 中執行的容器化應用程式使用。

當引用 ConfigMap 時,你需要在卷中提供 ConfigMap 的名稱。你可以自定義 ConfigMap 中特定條目的使用路徑。以下配置展示瞭如何將 `log-config` ConfigMap 掛載到名為 `configmap-pod` 的 Pod 上。

apiVersion: v1
kind: Pod
metadata:
  name: configmap-pod
spec:
  containers:
    - name: test
      image: busybox:1.28
      command: ['sh', '-c', 'echo "The app is running!" && tail -f /dev/null']
      volumeMounts:
        - name: config-vol
          mountPath: /etc/config
  volumes:
    - name: config-vol
      configMap:
        name: log-config
        items:
          - key: log_level
            path: log_level.conf

`log-config` ConfigMap 作為卷掛載,其 `log_level` 條目中儲存的所有內容都被掛載到 Pod 的路徑 `/etc/config/log_level.conf`。請注意,此路徑是根據卷的 `mountPath` 和以 `log_level` 為鍵的 `path` 派生出來的。

downwardAPI

一個 `downwardAPI` 卷使 downward API 資料可供應用程式使用。在卷內,你可以找到以純文字格式的只讀檔案形式公開的資料。

請參閱透過檔案向容器暴露 Pod 資訊瞭解更多資訊。

emptyDir

對於定義了 `emptyDir` 卷的 Pod,當 Pod 分配到節點時,該卷就會被建立。顧名思義,`emptyDir` 卷最初是空的。Pod 中的所有容器都可以在 `emptyDir` 卷中讀寫相同的檔案,儘管該卷可以在每個容器中掛載到相同或不同的路徑。當 Pod 因任何原因從節點中移除時,`emptyDir` 中的資料將被永久刪除。

`emptyDir` 的一些用途是:

  • 暫存空間,例如用於基於磁碟的歸併排序
  • 對長時間計算進行檢查點,以便從崩潰中恢復
  • 儲存內容管理容器獲取的檔案,而 Web 伺服器容器提供資料

`emptyDir.medium` 欄位控制 `emptyDir` 卷的儲存位置。預設情況下,`emptyDir` 卷儲存在支援節點的任何介質上,例如磁碟、SSD 或網路儲存,具體取決於你的環境。如果你將 `emptyDir.medium` 欄位設定為 `"Memory"`,Kubernetes 將為你掛載一個 tmpfs(RAM 支援的檔案系統)。雖然 tmpfs 速度非常快,但請注意,與磁碟不同,你寫入的檔案會計入寫入它們的容器的記憶體限制。

可以為預設介質指定大小限制,這限制了 `emptyDir` 卷的容量。儲存是從節點臨時儲存中分配的。如果該儲存被其他來源(例如日誌檔案或映象疊加層)填滿,則 `emptyDir` 可能會在該限制之前耗盡容量。如果未指定大小,則記憶體支援的卷的大小預設為節點可分配記憶體。

emptyDir 配置示例

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

emptyDir 記憶體配置示例

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
      medium: Memory

fc(光纖通道)

`fc` 卷型別允許在 Pod 中掛載現有的光纖通道塊儲存卷。你可以在卷配置中使用引數 `targetWWNs` 指定一個或多個目標全球通用名稱 (WWN)。如果指定了多個 WWN,`targetWWNs` 期望這些 WWN 來自多路徑連線。

gcePersistentDisk (已棄用)

在 Kubernetes 1.34 中,樹內 `gcePersistentDisk` 型別的所有操作都被重定向到 `pd.csi.storage.gke.io` CSI 驅動。

`gcePersistentDisk` 樹記憶體儲驅動在 Kubernetes v1.17 版本中被棄用,然後在 v1.28 版本中完全移除。

Kubernetes 專案建議你改用 Google Compute Engine Persistent Disk CSI 第三方儲存驅動。

gitRepo (已棄用)

如果你明確啟用 `GitRepoVolumeDriver` Feature Gate,則可以在叢集中使用此已棄用的儲存外掛。

`gitRepo` 卷是卷外掛的一個示例。此外掛掛載一個空目錄,並將 Git 倉庫克隆到該目錄中供 Pod 使用。

以下是一個 `gitRepo` 卷的示例:

apiVersion: v1
kind: Pod
metadata:
  name: server
spec:
  containers:
  - image: nginx
    name: nginx
    volumeMounts:
    - mountPath: /mypath
      name: git-volume
  volumes:
  - name: git-volume
    gitRepo:
      repository: "git@somewhere:me/my-git-repository.git"
      revision: "22f1d8406d464b0c0874075539c1f2e96c253775"

glusterfs (已移除)

Kubernetes 1.34 不包含 `glusterfs` 卷型別。

GlusterFS 樹記憶體儲驅動在 Kubernetes v1.25 版本中被棄用,然後在 v1.26 版本中完全移除。

hostPath

一個 `hostPath` 卷將宿主機節點檔案系統中的檔案或目錄掛載到你的 Pod 中。這不是大多數 Pod 所需要的,但它為某些應用程式提供了強大的應急出口。

`hostPath` 的一些用途是:

  • 執行需要訪問節點級系統元件的容器(例如,一個將系統日誌傳輸到中央位置的容器,透過只讀掛載 `/var/log` 來訪問這些日誌)
  • 使儲存在主機系統上的配置檔案以只讀方式供靜態 Pod 使用;與普通 Pod 不同,靜態 Pod 無法訪問 ConfigMap

`hostPath` 卷型別

除了必需的 `path` 屬性外,你還可以選擇為 `hostPath` 卷指定 `type`。

`type` 可用的值為:

行為
‌""空字串(預設)是為了向後相容,這意味著在掛載 `hostPath` 卷之前不會執行任何檢查。
DirectoryOrCreate如果給定路徑不存在任何內容,則根據需要建立空目錄,許可權設定為 0755,與 Kubelet 具有相同的組和所有權。
Directory給定路徑必須存在目錄
FileOrCreate如果給定路徑不存在任何內容,則根據需要建立空檔案,許可權設定為 0644,與 Kubelet 具有相同的組和所有權。
File給定路徑必須存在檔案
Socket給定路徑必須存在 UNIX 套接字
CharDevice(僅限 Linux 節點)給定路徑必須存在字元裝置
BlockDevice(僅限 Linux 節點)給定路徑必須存在塊裝置

底層主機上建立的一些檔案或目錄可能只能由 root 訪問。然後,你需要將程序作為 root 在 特權容器 中執行,或者修改主機上的檔案許可權以從 `hostPath` 卷讀取或寫入。

hostPath 配置示例


---
# This manifest mounts /data/foo on the host as /foo inside the
# single container that runs within the hostpath-example-linux Pod.
#
# The mount into the container is read-only.
apiVersion: v1
kind: Pod
metadata:
  name: hostpath-example-linux
spec:
  os: { name: linux }
  nodeSelector:
    kubernetes.io/os: linux
  containers:
  - name: example-container
    image: registry.k8s.io/test-webserver
    volumeMounts:
    - mountPath: /foo
      name: example-volume
      readOnly: true
  volumes:
  - name: example-volume
    # mount /data/foo, but only if that directory already exists
    hostPath:
      path: /data/foo # directory location on host
      type: Directory # this field is optional


---
# This manifest mounts C:\Data\foo on the host as C:\foo, inside the
# single container that runs within the hostpath-example-windows Pod.
#
# The mount into the container is read-only.
apiVersion: v1
kind: Pod
metadata:
  name: hostpath-example-windows
spec:
  os: { name: windows }
  nodeSelector:
    kubernetes.io/os: windows
  containers:
  - name: example-container
    image: microsoft/windowsservercore:1709
    volumeMounts:
    - name: example-volume
      mountPath: "C:\\foo"
      readOnly: true
  volumes:
    # mount C:\Data\foo from the host, but only if that directory already exists
  - name: example-volume
    hostPath:
      path: "C:\\Data\\foo" # directory location on host
      type: Directory       # this field is optional

hostPath FileOrCreate 配置示例

以下清單定義了一個 Pod,它將 `/var/local/aaa` 掛載到 Pod 中的單個容器內部。如果節點上還沒有路徑 `/var/local/aaa`,kubelet 會將其建立為一個目錄,然後將其掛載到 Pod 中。

如果 `/var/local/aaa` 已經存在但不是目錄,則 Pod 會失敗。此外,kubelet 會嘗試在該目錄內部(從主機角度看)建立一個名為 `/var/local/aaa/1.txt` 的檔案;如果該路徑已經存在且不是常規檔案,則 Pod 會失敗。

這是示例清單

apiVersion: v1
kind: Pod
metadata:
  name: test-webserver
spec:
  os: { name: linux }
  nodeSelector:
    kubernetes.io/os: linux
  containers:
  - name: test-webserver
    image: registry.k8s.io/test-webserver:latest
    volumeMounts:
    - mountPath: /var/local/aaa
      name: mydir
    - mountPath: /var/local/aaa/1.txt
      name: myfile
  volumes:
  - name: mydir
    hostPath:
      # Ensure the file directory is created.
      path: /var/local/aaa
      type: DirectoryOrCreate
  - name: myfile
    hostPath:
      path: /var/local/aaa/1.txt
      type: FileOrCreate

image

功能狀態: `Kubernetes v1.33 [beta]` (預設啟用:false)

`image` 卷源表示 kubelet 主機上可用的 OCI 物件(容器映象或製品)。

使用 `image` 卷源的示例是

apiVersion: v1
kind: Pod
metadata:
  name: image-volume
spec:
  containers:
  - name: shell
    command: ["sleep", "infinity"]
    image: debian
    volumeMounts:
    - name: volume
      mountPath: /volume
  volumes:
  - name: volume
    image:
      reference: quay.io/crio/artifact:v2
      pullPolicy: IfNotPresent

卷在 Pod 啟動時根據提供的 `pullPolicy` 值進行解析

Always
kubelet 總是嘗試拉取引用。如果拉取失敗,kubelet 會將 Pod 設定為 `Failed`。
Never
kubelet 永不拉取引用,僅使用本地映象或製品。如果映象的任何層尚未在本地存在,或者該映象的清單尚未快取,則 Pod 變為 `Failed`。
IfNotPresent
如果引用在磁碟上不存在,kubelet 會拉取。如果引用不存在且拉取失敗,則 Pod 變為 `Failed`。

如果 Pod 被刪除並重新建立,卷會重新解析,這意味著新的遠端內容將在 Pod 重新建立時可用。在 Pod 啟動期間解析或拉取映象失敗將阻止容器啟動,並可能增加顯著延遲。失敗將使用正常的捲回退機制進行重試,並在 Pod 的原因和訊息中報告。

該卷可掛載的物件型別由主機上的容器執行時實現定義。至少,它們必須包括容器映象欄位支援的所有有效型別。OCI 物件將掛載到單個目錄 (`spec.containers[*].volumeMounts.mountPath`),並且將以只讀方式掛載。在 Linux 上,容器執行時通常還會以禁止檔案執行 (`noexec`) 的方式掛載該卷。

除此之外

  • 容器的 `subPath``subPathExpr` 掛載(`spec.containers[*].volumeMounts.[subPath,subPathExpr]`)僅在 Kubernetes v1.33 及更高版本中支援。
  • `spec.securityContext.fsGroupChangePolicy` 欄位對這種卷型別沒有影響。
  • `AlwaysPullImages` 准入控制器 對此卷源也像對容器映象一樣工作。

`image` 型別可用的欄位如下:

reference
要使用的製品引用。例如,你可以指定 `registry.k8s.io/conformance:v1.34.0` 來從 Kubernetes 一致性測試映象載入檔案。其行為與 `pod.spec.containers[*].image` 相同。拉取 Secret 將以與容器映象相同的方式進行組裝,方法是查詢節點憑據、Service Account 映象拉取 Secret 和 Pod Spec 映象拉取 Secret。此欄位是可選的,允許更高級別的配置管理在工作負載控制器(如 Deployments 和 StatefulSets)中預設或覆蓋容器映象。有關容器映象的更多資訊
pullPolicy
拉取 OCI 物件的策略。可能的值有:`Always`、`Never` 或 `IfNotPresent`。如果指定了 `:latest` 標籤,則預設為 `Always`;否則為 `IfNotPresent`。

請參閱使用帶 Pod 的映象卷示例,瞭解如何使用卷源的更多詳細資訊。

iscsi

`iscsi` 卷允許將現有 iSCSI (透過 IP 的 SCSI) 卷掛載到 Pod 中。與 Pod 移除時被擦除的 `emptyDir` 不同,`iscsi` 卷的內容會保留,並且卷只是被解除安裝。這意味著 iSCSI 卷可以預先填充資料,並且該資料可以在 Pod 之間共享。

iSCSI 的一個特性是可以被多個消費者同時以只讀方式掛載。這意味著你可以用你的資料集預先填充一個卷,然後從你需要的儘可能多的 Pod 中並行提供它。不幸的是,iSCSI 卷只能由一個消費者以讀寫模式掛載。不允許同時寫入。

local

`local` 卷表示一個已掛載的本地儲存裝置,例如磁碟、分割槽或目錄。

本地卷只能作為靜態建立的 PersistentVolume 使用。不支援動態供應。

與 `hostPath` 卷相比,`local` 卷以持久和可移植的方式使用,無需手動將 Pod 排程到節點。系統透過檢視 PersistentVolume 上的節點親和性來了解卷的節點約束。

然而,`local` 卷受底層節點的可用性限制,不適用於所有應用程式。如果節點變得不健康,那麼 `local` 卷將對 Pod 不可訪問。使用此卷的 Pod 將無法執行。使用 `local` 卷的應用程式必須能夠容忍這種可用性降低以及潛在的資料丟失,具體取決於底層磁碟的耐久性特徵。

以下示例顯示了一個使用 `local` 卷和 `nodeAffinity` 的 PersistentVolume

apiVersion: v1
kind: PersistentVolume
metadata:
  name: example-pv
spec:
  capacity:
    storage: 100Gi
  volumeMode: Filesystem
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Delete
  storageClassName: local-storage
  local:
    path: /mnt/disks/ssd1
  nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          - example-node

使用 `local` 卷時,必須設定 PersistentVolume `nodeAffinity`。Kubernetes 排程器使用 PersistentVolume `nodeAffinity` 將這些 Pod 排程到正確的節點。

PersistentVolume `volumeMode` 可以設定為 “Block”(而不是預設值 “Filesystem”),以將本地卷暴露為裸塊裝置。

使用本地卷時,建議建立一個將 `volumeBindingMode` 設定為 `WaitForFirstConsumer` 的 StorageClass。有關更多詳細資訊,請參見本地 StorageClass 示例。延遲卷繫結可確保 PersistentVolumeClaim 繫結決策也將與 Pod 可能擁有的任何其他節點約束(例如節點資源需求、節點選擇器、Pod 親和性和 Pod 反親和性)一起進行評估。

可以單獨執行一個外部靜態供應器,以改進本地卷生命週期的管理。請注意,此供應器尚不支援動態供應。有關如何執行外部本地供應器的示例,請參見 本地卷供應器使用者指南

nfs

`nfs` 卷允許將現有的 NFS (網路檔案系統) 共享掛載到 Pod 中。與 Pod 移除時被擦除的 `emptyDir` 不同,`nfs` 卷的內容會保留,並且卷只是被解除安裝。這意味著 NFS 卷可以預先填充資料,並且該資料可以在 Pod 之間共享。NFS 可以被多個寫入者同時掛載。

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: registry.k8s.io/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /my-nfs-data
      name: test-volume
  volumes:
  - name: test-volume
    nfs:
      server: my-nfs-server.example.com
      path: /my-nfs-volume
      readOnly: true

persistentVolumeClaim

`persistentVolumeClaim` 卷用於將 PersistentVolume 掛載到 Pod 中。PersistentVolumeClaims 是一種讓使用者“宣告”持久儲存(例如 iSCSI 卷)而無需瞭解特定雲環境細節的方式。

有關更多詳細資訊,請參閱 PersistentVolumes 的資訊。

portworxVolume (已棄用)

功能狀態: `Kubernetes v1.25 [已棄用]`

`portworxVolume` 是一個彈性塊儲存層,與 Kubernetes 超融合執行。Portworx 對伺服器中的儲存進行指紋識別,根據功能進行分層,並聚合多個伺服器的容量。Portworx 在虛擬機器或裸機 Linux 節點中以訪客模式執行。

`portworxVolume` 可以透過 Kubernetes 動態建立,也可以預先配置並在 Pod 中引用。以下是一個引用預配置 Portworx 卷的 Pod 示例:

apiVersion: v1
kind: Pod
metadata:
  name: test-portworx-volume-pod
spec:
  containers:
  - image: registry.k8s.io/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /mnt
      name: pxvol
  volumes:
  - name: pxvol
    # This Portworx volume must already exist.
    portworxVolume:
      volumeID: "pxvol"
      fsType: "<fs-type>"

Portworx CSI 遷移

特性狀態: Kubernetes v1.33 [stable] (預設啟用:true)

在 Kubernetes 1.34 中,樹內 Portworx 卷的所有操作預設都重定向到 `pxd.portworx.com` 容器儲存介面 (CSI) 驅動。
Portworx CSI 驅動必須安裝在叢集上。

projected

投影卷將多個現有卷源對映到同一個目錄中。有關更多詳細資訊,請參閱投影卷

rbd (已移除)

Kubernetes 1.34 不包含 `rbd` 卷型別。

Rados 塊裝置 (RBD) 樹記憶體儲驅動及其 CSI 遷移支援在 Kubernetes v1.28 版本中被棄用,然後在 v1.31 版本中完全移除。

secret

`secret` 卷用於將敏感資訊(例如密碼)傳遞給 Pod。你可以將 Secret 儲存在 Kubernetes API 中,並將其作為檔案掛載供 Pod 使用,而無需直接與 Kubernetes 耦合。`secret` 卷由 tmpfs(RAM 支援的檔案系統)支援,因此它們永遠不會寫入非易失性儲存。

有關更多詳細資訊,請參閱 配置 Secret

vsphereVolume (已棄用)

在 Kubernetes 1.34 中,樹內 `vsphereVolume` 型別的所有操作都被重定向到 `csi.vsphere.vmware.com` CSI 驅動。

`vsphereVolume` 樹記憶體儲驅動在 Kubernetes v1.19 版本中被棄用,然後在 v1.30 版本中完全移除。

Kubernetes 專案建議你改用 vSphere CSI 第三方儲存驅動。

使用 subPath

有時,在單個 Pod 中為多個用途共享一個卷很有用。`volumeMounts[*].subPath` 屬性指定引用卷內部的子路徑,而不是其根路徑。

以下示例展示瞭如何使用單個共享卷配置具有 LAMP 堆疊(Linux Apache MySQL PHP)的 Pod。此 `subPath` 示例配置不建議用於生產環境。

PHP 應用程式的程式碼和資源對映到卷的 `html` 資料夾,MySQL 資料庫儲存在卷的 `mysql` 資料夾中。例如:

apiVersion: v1
kind: Pod
metadata:
  name: my-lamp-site
spec:
    containers:
    - name: mysql
      image: mysql
      env:
      - name: MYSQL_ROOT_PASSWORD
        value: "rootpasswd"
      volumeMounts:
      - mountPath: /var/lib/mysql
        name: site-data
        subPath: mysql
    - name: php
      image: php:7.0-apache
      volumeMounts:
      - mountPath: /var/www/html
        name: site-data
        subPath: html
    volumes:
    - name: site-data
      persistentVolumeClaim:
        claimName: my-lamp-site-data

使用帶有擴充套件環境變數的 subPath

功能狀態: `Kubernetes v1.17 [穩定]`

使用 `subPathExpr` 欄位從 downward API 環境變數構建 `subPath` 目錄名。`subPath` 和 `subPathExpr` 屬性是互斥的。

在此示例中,一個 `Pod` 使用 `subPathExpr` 在 `hostPath` 卷 `/var/log/pods` 內建立一個目錄 `pod1`。`hostPath` 卷從 `downwardAPI` 獲取 `Pod` 名稱。主機目錄 `/var/log/pods/pod1` 在容器中掛載到 `/logs`。

apiVersion: v1
kind: Pod
metadata:
  name: pod1
spec:
  containers:
  - name: container1
    env:
    - name: POD_NAME
      valueFrom:
        fieldRef:
          apiVersion: v1
          fieldPath: metadata.name
    image: busybox:1.28
    command: [ "sh", "-c", "while [ true ]; do echo 'Hello'; sleep 10; done | tee -a /logs/hello.txt" ]
    volumeMounts:
    - name: workdir1
      mountPath: /logs
      # The variable expansion uses round brackets (not curly brackets).
      subPathExpr: $(POD_NAME)
  restartPolicy: Never
  volumes:
  - name: workdir1
    hostPath:
      path: /var/log/pods

資源

`emptyDir` 卷的儲存介質(如磁碟或 SSD)由 kubelet 根目錄(通常為 `/var/lib/kubelet`)所在檔案系統的介質決定。`emptyDir` 或 `hostPath` 卷可以消耗的空間沒有限制,容器或 Pod 之間也沒有隔離。

要了解如何使用資源規範請求空間,請參閱如何管理資源

樹外卷外掛

樹外卷外掛包括 容器儲存介面 (CSI),以及 FlexVolume(已棄用)。這些外掛使儲存供應商能夠建立自定義儲存外掛,而無需將其外掛原始碼新增到 Kubernetes 倉庫中。

以前,所有卷外掛都是“樹內”的。“樹內”外掛是隨核心 Kubernetes 二進位制檔案一起構建、連結、編譯和釋出的。這意味著將新儲存系統新增到 Kubernetes(一個卷外掛)需要將程式碼簽入核心 Kubernetes 程式碼倉庫。

CSI 和 FlexVolume 都允許卷外掛獨立於 Kubernetes 程式碼庫進行開發,並作為擴充套件部署(安裝)在 Kubernetes 叢集上。

對於希望建立樹外卷外掛的儲存供應商,請參閱 卷外掛常見問題

csi

容器儲存介面 (CSI) 定義了一個標準介面,用於容器編排系統(如 Kubernetes)將其任意儲存系統暴露給容器工作負載。

請閱讀CSI 設計提案以獲取更多資訊。

在 Kubernetes 叢集上部署 CSI 相容卷驅動程式後,使用者可以使用 `csi` 卷型別來掛載 CSI 驅動程式公開的卷。

`csi` 卷可以透過三種不同的方式在 Pod 中使用:

以下欄位可供儲存管理員配置 CSI 持久卷:

  • `driver`:一個字串值,指定要使用的卷驅動程式的名稱。此值必須與 CSI 驅動程式在 `GetPluginInfoResponse` 中返回的值相對應,如 CSI 規範中所定義。Kubernetes 使用它來識別要呼叫哪個 CSI 驅動程式,CSI 驅動程式元件使用它來識別哪些 PV 物件屬於該 CSI 驅動程式。
  • `volumeHandle`:一個字串值,唯一標識該卷。此值必須與 CSI 驅動程式在 `CreateVolumeResponse` 中返回的 `volume.id` 欄位值相對應,如 CSI 規範中所定義。在引用該卷時,該值將作為 `volume_id` 傳遞給所有對 CSI 卷驅動程式的呼叫。
  • `readOnly`:一個可選的布林值,指示卷是否應以只讀方式“ControllerPublished”(掛載)。預設為 false。此值透過 `ControllerPublishVolumeRequest` 中的 `readonly` 欄位傳遞給 CSI 驅動程式。
  • `fsType`:如果 PV 的 `VolumeMode` 為 `Filesystem`,則此欄位可用於指定應用於掛載卷的檔案系統。如果卷尚未格式化並且支援格式化,則此值將用於格式化卷。此值透過 `ControllerPublishVolumeRequest`、`NodeStageVolumeRequest` 和 `NodePublishVolumeRequest` 的 `VolumeCapability` 欄位傳遞給 CSI 驅動程式。
  • `volumeAttributes`:一個字串到字串的對映,指定卷的靜態屬性。此對映必須與 CSI 驅動程式在 `CreateVolumeResponse` 中返回的 `volume.attributes` 欄位中的對映相對應,如 CSI 規範中所定義。該對映透過 `ControllerPublishVolumeRequest`、`NodeStageVolumeRequest` 和 `NodePublishVolumeRequest` 中的 `volume_context` 欄位傳遞給 CSI 驅動程式。
  • `controllerPublishSecretRef`:對包含敏感資訊的 Secret 物件的引用,該資訊將傳遞給 CSI 驅動程式以完成 CSI `ControllerPublishVolume` 和 `ControllerUnpublishVolume` 呼叫。此欄位是可選的,如果不需要 Secret,則可以為空。如果 Secret 包含多個 Secret,則所有 Secret 都將被傳遞。
  • `nodeExpandSecretRef`:一個 Secret 物件的引用,其中包含要傳遞給 CSI 驅動程式的敏感資訊,以完成 CSI `NodeExpandVolume` 呼叫。此欄位是可選的,如果不需要 Secret,則可以為空。如果物件包含多個 Secret,則所有 Secret 都將被傳遞。當為節點發起的卷擴容配置了 Secret 資料時,kubelet 會透過 `NodeExpandVolume()` 呼叫將該資料傳遞給 CSI 驅動程式。所有支援的 Kubernetes 版本都提供 `nodeExpandSecretRef` 欄位,並預設可用。Kubernetes v1.25 之前的版本不包含此支援。
  • 為每個 kube-apiserver 和每個節點上的 kubelet 啟用名為 `CSINodeExpandSecret` 的功能門。從 Kubernetes 1.27 版本開始,此功能已預設啟用,無需顯式啟用功能門。你還必須使用支援或要求在節點發起的儲存大小調整操作期間使用 Secret 資料的 CSI 驅動程式。
  • `nodePublishSecretRef`:對包含敏感資訊的 Secret 物件的引用,該資訊將傳遞給 CSI 驅動程式以完成 CSI `NodePublishVolume` 呼叫。此欄位是可選的,如果不需要 Secret,則可以為空。如果 Secret 物件包含多個 Secret,則所有 Secret 都將被傳遞。
  • `nodeStageSecretRef`:一個 Secret 物件的引用,其中包含要傳遞給 CSI 驅動程式的敏感資訊,以完成 CSI `NodeStageVolume` 呼叫。此欄位是可選的,如果不需要 Secret,則可以為空。如果 Secret 包含多個 Secret,則所有 Secret 都將被傳遞。

CSI 裸塊卷支援

特性狀態: Kubernetes v1.18 [stable]

具有外部 CSI 驅動程式的供應商可以在 Kubernetes 工作負載中實現裸塊卷支援。

你可以像往常一樣設定你的 PersistentVolume/PersistentVolumeClaim,支援裸塊卷,無需任何 CSI 特定的更改。

CSI 臨時卷

特性狀態: Kubernetes v1.25 [穩定]

你可以在 Pod 規範中直接配置 CSI 卷。以這種方式指定的卷是臨時的,並且在 Pod 重啟後不會持久化。有關更多資訊,請參閱臨時卷

有關如何開發 CSI 驅動程式的更多資訊,請參閱 kubernetes-csi 文件

Windows CSI 代理

特性狀態:`Kubernetes v1.22 [stable]`

CSI 節點外掛需要執行各種特權操作,例如掃描磁碟裝置和掛載檔案系統。這些操作對於每個主機作業系統都不同。對於 Linux worker 節點,容器化的 CSI 節點外掛通常作為特權容器部署。對於 Windows worker 節點,容器化的 CSI 節點外掛的特權操作透過 csi-proxy 支援,這是一個社群管理、獨立的二進位制檔案,需要預先安裝在每個 Windows 節點上。

有關更多詳細資訊,請參閱你希望部署的 CSI 外掛的部署指南。

從樹內外掛遷移到 CSI 驅動

特性狀態: Kubernetes v1.25 [穩定]

`CSIMigration` 功能將針對現有樹內外掛的操作重定向到相應的 CSI 外掛(預計已安裝和配置)。因此,當過渡到取代樹內外掛的 CSI 驅動程式時,操作員無需對現有儲存類、PersistentVolume 或 PersistentVolumeClaim(引用樹內外掛)進行任何配置更改。

支援的操作和功能包括:卷的供應/刪除、附加/分離、掛載/解除安裝和大小調整。

支援 `CSIMigration` 並已實現相應 CSI 驅動程式的樹內外掛列在 卷型別 中。

flexVolume (已棄用)

功能狀態: `Kubernetes v1.23 [已棄用]`

FlexVolume 是一個樹外外掛介面,它使用基於執行的模型與儲存驅動程式進行互動。FlexVolume 驅動程式二進位制檔案必須安裝在每個節點上預定義的卷外掛路徑中,在某些情況下,控制平面節點也需要安裝。

Pod 透過 `flexVolume` 樹內卷外掛與 FlexVolume 驅動程式互動。

以下 FlexVolume 外掛,作為 PowerShell 指令碼部署在主機上,支援 Windows 節點:

掛載傳播

掛載傳播允許將容器掛載的卷共享給同一 Pod 中的其他容器,甚至共享給同一節點上的其他 Pod。

卷的掛載傳播由 `containers[*].volumeMounts` 中的 `mountPropagation` 欄位控制。其值包括:

  • `None` - 此卷掛載不會接收主機後續掛載到此卷或其任何子目錄的任何掛載。同樣,容器建立的任何掛載在主機上將不可見。這是預設模式。

    此模式等同於 `mount(8)` 中描述的 `rprivate` 掛載傳播。

    然而,當 `rprivate` 傳播不適用時,CRI 執行時可能會選擇 `rslave` 掛載傳播(即 `HostToContainer`)。已知 cri-dockerd (Docker) 在掛載源包含 Docker 守護程序的根目錄 (`/var/lib/docker`) 時選擇 `rslave` 掛載傳播。

  • `HostToContainer` - 此卷掛載將接收所有後續掛載到此卷或其任何子目錄的掛載。

    換句話說,如果主機在該卷掛載點內部掛載任何內容,容器將看到它被掛載在那裡。

    同樣,如果任何具有 `Bidirectional` 掛載傳播到同一卷的 Pod 在那裡掛載任何內容,具有 `HostToContainer` 掛載傳播的容器也將看到它。

    此模式等同於 `mount(8)` 中描述的 `rslave` 掛載傳播。

  • `Bidirectional` - 此卷掛載的行為與 `HostToContainer` 掛載相同。此外,容器建立的所有卷掛載都將傳播回主機以及使用相同卷的所有 Pod 的所有容器。

    此模式的典型用例是帶有 FlexVolume 或 CSI 驅動程式的 Pod,或需要使用 `hostPath` 卷在主機上掛載內容的 Pod。

    此模式等同於 `mount(8)` 中描述的 `rshared` 掛載傳播。

只讀掛載

透過將 `.spec.containers[].volumeMounts[].readOnly` 欄位設定為 `true`,可以將掛載設定為只讀。這不會使卷本身只讀,但該特定容器將無法向其寫入。Pod 中的其他容器可以以讀寫方式掛載相同的卷。

在 Linux 上,預設情況下只讀掛載並非遞迴只讀。例如,考慮一個 Pod,它將主機上的 `/mnt` 作為 `hostPath` 卷掛載。如果 `/mnt/` 上有另一個檔案系統以讀寫方式掛載(例如 tmpfs、NFS 或 USB 儲存),則即使掛載本身被指定為只讀,掛載到容器中的卷也將具有可寫 `/mnt/`。

遞迴只讀掛載

特性狀態: Kubernetes v1.33 [stable] (預設啟用:true)

可以透過為 kubelet 和 kube-apiserver 設定 `RecursiveReadOnlyMounts` 功能門,併為 Pod 設定 `.spec.containers[].volumeMounts[].recursiveReadOnly` 欄位來啟用遞迴只讀掛載。

允許的值為:

  • `Disabled`(預設):無效果。

  • `Enabled`:使掛載遞迴只讀。需要滿足以下所有要求:

    • `readOnly` 設定為 `true`
    • `mountPropagation` 未設定,或設定為 `None`
    • 主機正在執行 Linux 核心 v5.12 或更高版本
    • CRI 級別容器執行時支援遞迴只讀掛載
    • OCI 級別容器執行時支援遞迴只讀掛載。

    如果上述任何一項不為真,則會失敗。

  • `IfPossible`:嘗試應用 `Enabled`,如果核心或執行時類不支援此功能,則回退到 `Disabled`。

示例

apiVersion: v1
kind: Pod
metadata:
  name: rro
spec:
  volumes:
    - name: mnt
      hostPath:
        # tmpfs is mounted on /mnt/tmpfs
        path: /mnt
  containers:
    - name: busybox
      image: busybox
      args: ["sleep", "infinity"]
      volumeMounts:
        # /mnt-rro/tmpfs is not writable
        - name: mnt
          mountPath: /mnt-rro
          readOnly: true
          mountPropagation: None
          recursiveReadOnly: Enabled
        # /mnt-ro/tmpfs is writable
        - name: mnt
          mountPath: /mnt-ro
          readOnly: true
        # /mnt-rw/tmpfs is writable
        - name: mnt
          mountPath: /mnt-rw

當 kubelet 和 kube-apiserver 識別此屬性時,`.status.containerStatuses[].volumeMounts[].recursiveReadOnly` 欄位將被設定為 `Enabled` 或 `Disabled`。

實現

已知以下容器執行時支援遞迴只讀掛載。

CRI 級別

OCI 級別

  • runc,自 v1.1 起
  • crun,自 v1.8.6 起

下一步

請按照 使用持久卷部署 WordPress 和 MySQL 的示例操作。

本頁上的專案指的是提供 Kubernetes 所需功能的第三方產品或專案。Kubernetes 專案作者不對這些第三方產品或專案負責。有關更多詳細資訊,請參閱 CNCF 網站指南

在提議新增額外第三方連結的更改之前,你應該閱讀內容指南

最後修改於 2025 年 7 月 17 日太平洋標準時間上午 3:46:根據 KEP 1326 移除 Portworx 卷示例 (9fbaa42877)