剛用 Kubernetes(K8s)部署應用時,我踩過一個致命坑:用默認存儲部署的數據庫 Pod 意外重啓後,數據全丟了。原來 K8s 的默認存儲是“臨時存儲”,Pod 銷燬後數據會跟着消失。後來才知道,要實現數據持久化,必須用 PV(PersistentVolume,持久卷)和 PVC(PersistentVolumeClaim,持久卷聲明)——它們就像 K8s 集羣的“共享硬盤”和“硬盤租用申請”,讓數據獨立於 Pod 生命週期,即使 Pod 重建,數據也能完好保留。這篇就從實戰角度,教你快速掌握 PV/PVC 的核心用法。

一、核心認知:為什麼需要 PV/PVC?

K8s 中 Pod 是臨時的,默認存儲(emptyDir、configMap 等)會隨 Pod 銷燬而丟失,無法滿足數據庫、文件存儲等場景的持久化需求。PV 和 PVC 正是為解決這個問題而生,它們的核心邏輯是“存儲與使用分離”:

  • PV(持久卷):集羣級別的“共享存儲資源”,由管理員提前創建,獨立於 Pod 存在,支持本地磁盤、NFS、雲存儲等多種存儲類型;
  • PVC(持久卷聲明):Pod 對存儲資源的“租用申請”,由開發人員創建,聲明需要的存儲大小、訪問模式等,K8s 會自動匹配符合條件的 PV 進行綁定;
  • 核心價值:開發人員無需關心存儲底層實現(是 NFS 還是雲存儲),只需通過 PVC 申請資源;管理員統一管理 PV,實現存儲資源的複用和管控。

通俗理解:PV 是管理員提前備好的“硬盤”(比如 10GB、20GB 規格),PVC 是開發人員提交的“租硬盤申請”(比如“我要 5GB 可讀寫的硬盤”),K8s 負責匹配申請和硬盤,綁定後 Pod 就能使用這塊“硬盤”存儲數據。

二、基礎概念:PV 的核心屬性

創建 PV 時,需要指定兩個關鍵屬性,這也是 PVC 匹配 PV 的依據:

1. 訪問模式(Access Modes)

定義 PV 的使用權限,支持三種模式:

  • ReadWriteOnce(RWO):僅允許單個節點以讀寫方式掛載(最常用,適合數據庫等獨佔存儲場景);
  • ReadOnlyMany(ROX):允許多個節點以只讀方式掛載(適合共享配置文件場景);
  • ReadWriteMany(RWX):允許多個節點以讀寫方式掛載(適合多節點共享數據場景,需存儲類型支持)。

2. 存儲容量(Capacity)

指定 PV 的存儲大小(如 10Gi),PVC 申請的容量不能超過 PV 的容量。

3. 存儲類型(StorageClass)

用於對 PV 分類,支持動態供應(無需管理員手動創建 PV,K8s 按需自動創建),後續會詳細説明。

三、實戰步驟:手動創建 PV/PVC 並使用

以 NFS 存儲為例(需提前搭建 NFS 服務器,假設共享目錄為 192.168.1.100:/data/nfs),一步步實現數據持久化。

1. 步驟 1:創建 PV(管理員操作)

創建 pv-nfs.yaml 文件,定義一個 10GB 的 NFS 類型 PV:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-nfs-10g  # PV 名稱
spec:
  capacity:
    storage: 10Gi  # 存儲容量 10GB
  accessModes:
    - ReadWriteOnce  # 訪問模式:單節點讀寫
  persistentVolumeReclaimPolicy: Retain  # 回收策略:PVC 釋放後保留 PV(不刪除數據)
  storageClassName: ""  # 不指定存儲類(手動創建 PV 時留空)
  nfs:
    path: /data/nfs  # NFS 共享目錄
    server: 192.168.1.100  # NFS 服務器 IP

應用配置創建 PV:

kubectl apply -f pv-nfs.yaml

# 查看 PV 狀態(STATUS 為 Available 表示可用)
kubectl get pv
# 輸出示例:
# NAME         CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
# pv-nfs-10g   10Gi       RWO            Retain           Available                                   30s

2. 步驟 2:創建 PVC(開發人員操作)

創建 pvc-nfs.yaml 文件,申請 5GB 存儲(需與 PV 的訪問模式、存儲類型匹配):

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-nfs-5g  # PVC 名稱
spec:
  accessModes:
    - ReadWriteOnce  # 與 PV 的訪問模式一致
  resources:
    requests:
      storage: 5Gi  # 申請 5GB 存儲(不超過 PV 的 10GB)
  storageClassName: ""  # 與 PV 保持一致(留空)

應用配置創建 PVC:

kubectl apply -f pvc-nfs.yaml

# 查看 PVC 狀態(STATUS 為 Bound 表示已綁定 PV)
kubectl get pvc
# 輸出示例:
# NAME          STATUS   VOLUME       CAPACITY   ACCESS MODES   STORAGECLASS   AGE
# pvc-nfs-5g    Bound    pv-nfs-10g   10Gi       RWO                           20s

此時 PV 的狀態會變為 Bound,表示已被 PVC 佔用。

3. 步驟 3:Pod 掛載 PVC(使用存儲)

創建 pod-with-pvc.yaml 文件,在 Pod 中掛載 PVC:

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pvc-demo
spec:
  containers:
  - name: nginx
    image: nginx:alpine
    ports:
    - containerPort: 80
    volumeMounts:
    - name: data-volume  # 卷名稱(與下方 volumes 對應)
      mountPath: /usr/share/nginx/html  # 容器內掛載路徑(Nginx 網站根目錄)
  volumes:
  - name: data-volume
    persistentVolumeClaim:
      claimName: pvc-nfs-5g  # 引用創建的 PVC 名稱

應用配置創建 Pod:

kubectl apply -f pod-with-pvc.yaml

# 查看 Pod 狀態(STATUS 為 Running 表示正常)
kubectl get pods

4. 驗證數據持久化

測試數據是否能持久化(即使 Pod 重建,數據也不丟失):

# 1. 進入 Pod,創建測試文件(寫入 Nginx 根目錄)
kubectl exec -it nginx-pvc-demo -- touch /usr/share/nginx/html/test-persist.txt
kubectl exec -it nginx-pvc-demo -- echo "K8s PV/PVC 持久化測試" > /usr/share/nginx/html/test-persist.txt

# 2. 手動刪除 Pod(模擬 Pod 故障重建)
kubectl delete pod nginx-pvc-demo

# 3. 重新創建 Pod(使用相同的 PVC)
kubectl apply -f pod-with-pvc.yaml

# 4. 驗證數據是否存在
kubectl exec -it nginx-pvc-demo -- cat /usr/share/nginx/html/test-persist.txt
# 輸出:K8s PV/PVC 持久化測試(數據成功保留)

四、進階用法:StorageClass 動態供應 PV

手動創建 PV 存在侷限性:需要管理員提前規劃存儲容量,無法按需創建。StorageClass 支持“動態供應”,讓 K8s 根據 PVC 自動創建 PV,無需人工干預。

1. 核心邏輯

  • 管理員創建 StorageClass,定義存儲類型(如 NFS、雲存儲)、回收策略等;
  • 開發人員創建 PVC 時,指定 StorageClass 名稱;
  • K8s 會根據 StorageClass 的配置,自動創建對應的 PV 並與 PVC 綁定。

2. 實戰:NFS 動態供應(需安裝 NFS Provisioner)

NFS 本身不支持動態供應,需安裝 nfs-subdir-external-provisioner 插件(第三方提供的動態供應器)。

(1)安裝 NFS Provisioner(Helm 方式,簡單高效)
# 1. 添加 Helm 倉庫
helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/

# 2. 安裝 Provisioner(指定 NFS 服務器地址和共享目錄)
helm install nfs-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
  --set nfs.server=192.168.1.100 \
  --set nfs.path=/data/nfs
(2)查看自動創建的 StorageClass
kubectl get sc
# 輸出示例(默認名稱為 nfs-client):
# NAME         PROVISIONER                                   RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
# nfs-client   cluster.local/nfs-provisioner-nfs-subdir-external-provisioner   Delete          Immediate           true                  1m
(3)創建 PVC(指定 StorageClass)

創建 pvc-dynamic.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-dynamic-8g
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 8Gi
  storageClassName: nfs-client  # 指定 StorageClass 名稱(動態供應)

應用配置:

kubectl apply -f pvc-dynamic.yaml

# 查看 PVC 和自動創建的 PV
kubectl get pvc  # STATUS 為 Bound 表示成功
kubectl get pv   # 會出現一個自動創建的 PV(名稱格式:pvc-xxx)

此時無需管理員手動創建 PV,K8s 已根據 PVC 需求自動創建,極大提升效率。

五、避坑指南:常見問題與解決方案

1. PVC 一直處於 Pending 狀態

  • 原因:沒有匹配的 PV(訪問模式、存儲容量、StorageClass 不匹配);
  • 解決:
  1. 檢查 PVC 和 PV 的 accessModes 是否一致;
  2. 確保 PVC 申請的存儲容量 ≤ PV 的容量;
  3. 若使用 StorageClass,檢查是否安裝了對應的 Provisioner。

2. Pod 掛載 PVC 失敗(狀態為 Error)

  • 原因:NFS 服務器地址錯誤、共享目錄權限不足、存儲服務器不可達;
  • 解決:
  1. 驗證 NFS 服務器是否正常:mount -t nfs 192.168.1.100:/data/nfs /tmp/test
  2. 確保 NFS 共享目錄權限開放:chmod 777 /data/nfs
  3. 查看 Pod 日誌排查:kubectl logs nginx-pvc-demo

3. PV 回收策略選擇不當

  • Retain:PVC 釋放後,PV 保留為 Released 狀態,數據不刪除(需手動清理);
  • Delete:PVC 釋放後,PV 自動刪除(動態供應默認策略,適合臨時存儲);
  • Recycle:PVC 釋放後,PV 自動清理數據並變為 Available(已廢棄,不推薦使用);
  • 建議:生產環境用 Retain 策略,避免誤刪數據;測試環境用 Delete 策略,自動清理資源。

4. 訪問模式使用錯誤

  • 例如:多個節點的 Pod 掛載同一個 PVC,卻使用 ReadWriteOnce 模式;
  • 解決:根據場景選擇正確的訪問模式,多節點共享需用 ReadWriteMany(需存儲類型支持,如 NFS、GlusterFS)。

總結

PV/PVC 是 K8s 持久化存儲的核心方案,核心優勢是“存儲與使用分離”——管理員統一管理存儲資源,開發人員只需專注於業務需求。實戰中:

  1. 小集羣或簡單場景,可手動創建 PV/PVC(適合本地磁盤、NFS 存儲);
  2. 中大型集羣或動態需求,優先使用 StorageClass 動態供應(減少人工干預);
  3. 生產環境需注意數據安全:選擇 Retain 回收策略,定期備份存儲數據,避免存儲服務器單點故障。

掌握 PV/PVC 後,你可以輕鬆實現數據庫、文件服務等應用的數據持久化,再也不用擔心 Pod 重建導致數據丟失的問題。這是 K8s 部署有狀態應用的基礎技能,也是從“部署無狀態服務”到“管理有狀態應用”的關鍵一步。