Kubernetes Storage - 數據持久化 (PV & PVC)
在 Kubernetes 中,Pod 是暫時的。當 Pod 被刪除重建,裡面的檔案系統也會重置。 如果要讓資料 (如資料庫檔案) 能夠 持久化 (Persist) 且跨 Pod 生命週期存在,我們需要使用 Kubernets 的儲存系統。
基本 Volume 類型
Kubernetes 支援多種 Volume 類型,最簡單的有:
emptyDir: 臨時目錄。Pod 建立時產生,Pod 刪除時消失。適合 Cache 或暫存檔。
- 應用情境:Redis 快取節點、Spark 任務的暫存空間、同一個 Pod 內不同 Container 共享資料 (sidecar pattern)。
volumes: - name: cache-volume emptyDir: {}hostPath: 掛載 Node (宿主機) 上的目錄。適合 Minikube 單節點測試,但在多節點叢集會有問題 (Pod 飄到別台機器就讀不到了)。
- 應用情境:Minikube 測試 PV/PVC、或是需要收集宿主機 Log (如 Fluentd) 或監控數據 (如 Prometheus Node Exporter) 的系統層級 Agent。
volumes: - name: test-volume hostPath: # directory location on host path: /data # this field is optional type: Directory
進階儲存架構: PV 與 PVC
這兩個概念通常一起出現,初學者容易搞混。簡單來說,這是 Kubernetes 為了讓開發者不需煩惱底層硬碟是用哪牌的,所設計的「供需媒合」機制。
你可以這樣想像:
PV (PersistentVolume) 是「實際的倉儲空間」(供應方)。
- 由 維運人員 (Ops) 負責準備。
- 它對應到真實的物理儲存(如 AWS EBS 硬碟、NFS 伺服器、GCP Persistent Disk)。
- 口語:「倉庫裡已經準備好一塊 100GB 的硬碟空間了。」
PVC (PersistentVolumeClaim) 是「領料申請單」(需求方)。
- 由 開發者 (Dev) 定義。
- 你在 YAML 裡只需要開出規格:「我需要 10GB、要可以讀寫」。
- 口語:「我的 App 需要申請 10GB 的空間來存資料。」
運作流程:
- 開發者建立 PVC (申請單)。
- Kubernetes 看到申請單,自動在系統裡尋找符合規格 (例如大小足夠) 的 PV (硬碟)。
- 一旦配對成功,兩者就會 綁定 (Bound) 在一起。
- Pod 只需要掛載這個 PVC,就能使用那塊 PV 的空間,完全不用管底層是接什麼線。
ReadWriteMany)。實戰:使用 HostPath 練習
在 Minikube 中,我們可以使用 hostPath 來模擬 PV。
定義 PV
# pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: task-pv-volume
labels:
type: local
spec:
# 定義 StorageClass 名稱,PVC 必須匹配此名稱才能綁定
storageClassName: manual
# 定義 PV 的總容量
capacity:
storage: 10Gi
# 定義可以被掛載的模式 (RWO, ROX, RWX)
accessModes:
- ReadWriteOnce
# 定義底層儲存類型,這裡是 hostPath (測試用)
hostPath:
path: '/mnt/data'
定義 PVC
# pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: task-pv-claim
spec:
# 必須與 PV 的 storageClassName 一致才能綁定
storageClassName: manual
# 申請的存取模式,必須是 PV 支援的模式之一
accessModes:
- ReadWriteOnce
# 申請的資源大小
resources:
requests:
storage: 3Gi # 只要 PV 容量 >= 3Gi 且其他條件符合,就可以綁定
在 Pod 中使用 PVC
Pod 不需要知道 PV 的存在,只需要引用 PVC 即可。
# pod-pvc.yaml
apiVersion: v1
kind: Pod
metadata:
name: task-pv-pod
spec:
volumes:
- name: task-pv-storage
persistentVolumeClaim:
claimName: task-pv-claim # 引用上面的 PVC
containers:
- name: task-pv-container
image: nginx
ports:
- containerPort: 80
name: 'http-server'
volumeMounts:
- mountPath: '/usr/share/nginx/html'
name: task-pv-storage
StorageClass (SC)
手動建立 PV 很麻煩。現代 K8s 叢集通常都有設定預設的 StorageClass (如 AWS gp2, GCP standard)。 只要定義 PVC 時指定 StorageClass (或者留空使用預設值),K8s 就會自動呼叫雲端 API 建立硬碟並掛載進來,這稱為 Dynamic Provisioning。
存取模式 (Access Modes) 與 PVC 重用性
常常有人問:「一個 PVC 可以給幾個 Pod 用?」這其實取決於 AccessMode 的設定。需要注意的是,PV 與 PVC 的綁定永遠是一對一的,但一個 PVC 可以被多個 Pod 掛載。
ReadWriteOnce (RWO):
- 單節點讀寫。
- 限制:該 PVC 同一時間只能被掛載到 單一個 Node。
- 情境:
- Pod A (在 Node 1) 使用 PVC -> 成功。
- Pod B (也在 Node 1) 使用同一 PVC -> 成功。
- Pod C (在 Node 2) 想用同一 PVC -> 失敗 (因為已在 Node 1 被掛載)。
- 適用:大多數雲端區塊儲存 (AWS EBS, GCP PD, Azure Disk)。
ReadOnlyMany (ROX):
- 多節點唯讀。
- 可以跨多個 Node 掛載,但是大家只能讀,不能寫。
ReadWriteMany (RWX):
- 多節點讀寫。
- PVC 可以同時被 多個 Node 上的多個 Pod 掛載並讀寫。
- 適用:檔案系統級別的儲存 (NFS, AWS EFS, Google Filestore, CephFS)。
PVC 的釋放與回收 (Reclaim Policy)
當你不再需要某個儲存空間時,可以刪除 PVC 來釋放資源:
kubectl delete pvc task-pv-claim
刪除 PVC 後,原本綁定的 PV 會發生什麼事?這取決於 PV 的 Reclaim Policy (回收策略):
- Retain (保留):
- PV 狀態變成
Released。 - 資料還在,但該 PV 不能被其他 PVC 直接重新綁定 (為了資料安全)。
- 需要管理員手動介入 (備份資料、刪除 PV 物件) 才能再次使用。
- PV 狀態變成
- Delete (刪除):
- (大多雲端 StorageClass 的預設值)
- PV 物件會被自動刪除。
- 背後的儲存資產也會被刪除 (例如 AWS EBS Volume 會被 Terminate)。資料會永久消失。
- Recycle (回收):
- (已棄用/少用)
- 系統會執行基本的
rm -rf /thevolume/*清除資料,然後讓 PV 變回Available狀態,供下一個 PVC 申請使用。
如果我有 100 個 Pod 怎麼辦? (StatefulSet)
這是一個常見的問題:如果我跑一個 MongoDB Replica Set (3 個 Pod),每個 Pod 都需要自己獨立的 10GB 空間,難道我要手動寫 mongo-pvc-1.yaml, mongo-pvc-2.yaml... 嗎?
不需要! 這時候你會使用 StatefulSet 搭配 volumeClaimTemplates。
什麼是 volumeClaimTemplates?
它就像是一個「PVC 模具」。當 StatefulSet 建立 Pod 時,會根據這個模具,自動 為每一個 Pod 產生一個專屬的 PVC。
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: 'nginx'
replicas: 3 # 會產生 web-0, web-1, web-2
template:
# Pod 的定義 (略)
volumeClaimTemplates: # 這裡定義 PVC 模板
- metadata:
name: www
spec:
accessModes: ['ReadWriteOnce']
storageClassName: 'my-storage-class'
resources:
requests:
storage: 1Gi
結果 (StatefulSet 自動化):
K8s 會自動幫你建立 3 個 PVC (與對應的 PV),名稱通常為 [模板名]-[Pod名]:
www-web-0(給 web-0 用)www-web-1(給 web-1 用)www-web-2(給 web-2 用)
這樣每個 Pod 都有自己獨立的儲存空間,而且擴展皆自動化 (Scale 到 100 個副本,就會有 100 個 PVC)。
總結
資料庫等有狀態應用必須使用 PV/PVC 來確保資料安全。結合 StatefulSet,可以為每個副本自動產生專屬的 PVC,實現分散式儲存架構。