iT邦幫忙

2026 iThome 鐵人賽

DAY 22
0
Kubernetes

不囉唆圖解 Kubernetes系列 第 22 篇

Day 22:K8s Cluster 島上的倉庫與借用單 PV 與 PVC

  • 分享至 

  • xImage
  •  

Day 22:K8s Cluster 島上的倉庫與借用單 PV 與 PVC

PV 與 PVC

昨天證明了泡泡(Pod)破掉資料就沒了。
但資料庫不能這樣,它需要一個「泡泡 Pod 掛了東西還在」的地方。

https://ithelp.ithome.com.tw/upload/images/20261005/20124462e5BHLB087Z.png
一座倉庫(PersistentVolume,PV)蓋在島的地面上,一張借用單(PersistentVolumeClaim,PVC)把樹上的泡泡(Pod)和地面的倉庫(PV)連起來。

倉庫 PV 蓋在地面上

https://ithelp.ithome.com.tw/upload/images/20261005/20124462t8vVsYRNFY.png
看圖上倉庫(PV)的位置。
它不在泡泡(Pod)裡,它蓋在地面上。
這一個構圖差異就是今天的全部重點:泡泡(Pod)在樹上生生滅滅,倉庫(PV)在地上動都不動。

這裡有三個角色,各司其職。

PV:對叢集可用的儲存資源抽象
它可能是雲端的一顆硬碟、機房的一台 NFS、或是筆電上的一個資料夾。
它是島級的東西,不屬於任何圍籬(Namespace),也不屬於任何泡泡(Pod)。
把泡泡(Pod)刪光時,倉庫(PV)通常仍可保留;PVC 與 PV 的回收策略會決定底層資料是否繼續存在。

PVC:一張「我要借多大、要怎麼用」的申請單
它才是屬於圍籬(Namespace)的東西,跟應用綁在一起。

Pod:拿著借用單(PVC)去用倉庫(PV)的人
注意:在 PVC 的模型裡,泡泡(Pod)通常不直接指定底層倉庫(PV),它只指定借用單(PVC)。

泡泡(Pod)裡看到的食盆(Volume Mount)是 Volume Mount。
當它透過 PVC 接到 PV 時,泡泡(Pod)可以被替換,但倉庫(PV)裡的資料仍可能保留。
這和沒有外接持久儲存的 emptyDir 不同。

為什麼要多一張單子

因為它把兩件事分開了:「有什麼倉庫(PV)」是管理員的事,「我要多大空間」是開發者的事。

寫應用的人不需要知道公司用的是 AWS EBS 還是機房的 NFS,只要說「我要 1 GB、可以讀寫」。
單子送出去,K8s 自己去找一個符合條件的倉庫(PV)綁上。

同一份 YAML 因此能跑在筆電、跑在測試機、跑在正式環境。
底下換成不同的儲存設備時,應用程式可維持使用 PVC,但 StorageClass、容量、權限與拓撲等環境設定仍可能需要調整。

這個「找到並綁上」的動作叫 Binding,一旦綁定就是一對一:這張單子綁走這個倉庫(PV),別人不能再借。
狀態欄會看到 Bound 這個字。

https://ithelp.ithome.com.tw/upload/images/20261005/20124462BDsx5pJZks.png
借用單(PVC)從樹上的泡泡(Pod)垂下來,接到地面倉庫(PV)的門口,倉庫門上貼著「已借出」。

誰來蓋倉庫

手動蓋(靜態)
管理員先建一批 PV 放著,等人來借。

自動蓋(動態)
送出借用單(PVC),由 StorageClass 指定的 provisioner 建立符合條件的儲存。
StorageClass 只描述類別與參數,不是它自己建立底層 volume。
雲端環境常用動態供應;但原生 Kind 不保證內建 StorageClass,今天為了讓步驟可重現,採用手動建立一個本機測試用 PV。

最後一個必須知道的行為:刪掉借用單(PVC),倉庫(PV)不一定跟著刪。
這由 PV 的回收策略決定,Delete 是連倉庫(PV)一起銷毀,Retain 是留著資料等人工處理。
正式環境的資料庫請用 Retain,這是那種「錯一次就回不來」的設定。

動手 5 分鐘

昨天的食盆(Volume Mount)隨著泡泡(Pod)一起碎掉。今天改用倉庫(PV),做同一個實驗,看結果怎麼不一樣。

先看看島上是否有動態供應器(不同 Kind/版本結果可能不同):

kubectl get storageclass

若沒有輸出,代表這座 Kind 沒有 StorageClass;今天不依賴它,改用明確的靜態 PV。若你看到 standard (default),也不要把它當成 Kind 的通用保證。

建立 hello-pv.yaml:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: hello-pv
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  hostPath:
    path: /var/local-path-provisioner/hello-data
    type: DirectoryOrCreate

這個 hostPath 是 Kind 節點容器裡的本機資料夾,只適合單節點練習;它不是跨節點高可用儲存,也不能當成正式資料庫的備份。

送出借用單(PVC)。建立 hello-pvc.yaml:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: hello-data
spec:
  storageClassName: ""
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

只有兩個重點欄位。storage: 1Gi 是要借多大;accessModes 是怎麼用,ReadWriteOnce 的意思是「同一時間只有一棵樹上的泡泡(Pod)能讀寫」,這是最常見也最單純的模式。

kubectl apply -f hello-pv.yaml -f hello-pvc.yaml
kubectl get pvc

STATUS 變成 Bound,因為這張單的容量與存取模式能和 hello-pv 配對。若你改用已安裝的 StorageClass,才會由 provisioner 動態建立 PV。

現在建一顆用它的泡泡(Pod)。建立 demo-pvc-pod.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: demo-store
spec:
  containers:
    - name: writer
      image: busybox:1.36
      command: ["sh", "-c", "sleep 3600"]
      volumeMounts:
        - name: store
          mountPath: /data
  volumes:
    - name: store
      persistentVolumeClaim:
        claimName: hello-data

跟昨天的結構幾乎一樣,只有 volumes 那段從 emptyDir: {} 換成 persistentVolumeClaim。泡泡(Pod)指的是借用單(PVC)的名字,不是倉庫(PV)。

kubectl apply -f demo-pvc-pod.yaml
kubectl get pvc,pv

現在 PVC 變成 Bound,看 PV 的 CLAIM 欄會寫著 default/hello-data,代表兩者已一對一綁定。

寫點東西進去:

kubectl exec demo-store -- sh -c "echo 'data written at' \$(date) > /data/important.txt"
kubectl exec demo-store -- cat /data/important.txt

現在做今天的關鍵實驗:把泡泡(Pod)整顆刪掉。

kubectl delete pod demo-store
kubectl get pvc,pv

泡泡(Pod)沒了,但 PVC 還是 Bound、PV 還在。倉庫(PV)蓋在地面上,泡泡(Pod)破了它不會跟著碎。

建一顆全新的泡泡(Pod)來接同一張單:

kubectl apply -f demo-pvc-pod.yaml
kubectl exec demo-store -- cat /data/important.txt

檔案還在,時間戳是舊的那個。 這是全新的泡泡(Pod)、全新的容器,讀到的是上一顆泡泡(Pod)寫的資料。昨天的食盆(Volume Mount)做不到這件事。

https://ithelp.ithome.com.tw/upload/images/20261005/20124462xE3IOGpK8c.png

前後兩次讀到的時間戳一模一樣 ── 中間那顆泡泡(Pod)已經被整個刪掉重建了。

最後看一眼倉庫(PV)實際在哪:

kubectl get pv hello-pv -o jsonpath='{.spec.hostPath.path}{"\n"}'

印出樹上的一個路徑 ── 這次 Kind 的倉庫(PV)就是節點容器裡的一個資料夾。正式環境通常會改用雲端磁碟或其他儲存後端,StorageClass、容量、存取模式與拓撲可能都要重新設計。

收工,泡泡(Pod)刪掉,倉庫(PV)留著明天用:

kubectl delete pod demo-store

帶走一句話

泡泡(Pod)指的是借用單(PVC),不是倉庫(PV)。

參考資源


上一篇
Day 21:K8s 泡泡 Pod 裡的 emptyDir,為什麼重啟之後資料就不見了
下一篇
Day 23:K8s 資料實戰,幫 hello service 接上一個資料庫
系列文
不囉唆圖解 Kubernetes 共 24 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言