Lưu Trữ: Volumes, PV, PVC và StorageClass

K
Kai··5 min read

Đến giờ ứng dụng của ta không trạng thái — pod chết, dựng pod mới, chẳng mất gì. Nhưng database, file người dùng tải lên, hay dữ liệu cần giữ lại thì sao? Mọi thứ ghi vào trong pod sẽ bay hơi cùng pod khi nó chết. Bài này giải quyết: cách lưu trữ dữ liệu sống lâu hơn vòng đời pod.

Vấn đề: filesystem của pod là phù du

Mặc định, filesystem container gắn liền vòng đời pod. Pod bị xóa hay dựng lại (nhớ self-healing, rolling update ở Bài 4) → mọi thứ ghi bên trong biến mất. Với app không trạng thái thì tốt; với dữ liệu cần giữ thì thảm hoạ. Kubernetes có volume để gắn một vùng lưu trữ vào pod — và quan trọng là loại volume bền vững.

Volume đơn giản nhất là emptyDir: một thư mục trống sống cùng pod, dùng để chia sẻ file giữa các container trong cùng pod hoặc làm cache tạm. Nhưng emptyDir cũng mất khi pod chết — không phải thứ ta cần cho dữ liệu bền. Cái ta cần là PersistentVolume.

Ba khái niệm: PV, PVC, StorageClass

Kubernetes tách nhu cầu lưu trữ khỏi nguồn cung lưu trữ — giống cách bạn đặt phòng khách sạn mà không cần biết phòng nào cụ thể:

   PVC  (PersistentVolumeClaim)   "Tôi cần 100Mi, đọc-ghi"     ← bạn (dev) khai báo
        │  Kubernetes ghép
        ▼
   PV   (PersistentVolume)        ổ đĩa thật 100Mi             ← hạ tầng cung cấp
        │  được cấp bởi
        ▼
   StorageClass                   "cách cấp đĩa" (loại disk)    ← admin định nghĩa
  • PersistentVolume (PV) — một mẩu lưu trữ thật trong cluster (một đĩa EBS, một thư mục trên host, một NFS share...). Là tài nguyên cấp cluster.
  • PersistentVolumeClaim (PVC)yêu cầu lưu trữ của bạn: "cần 100Mi, kiểu truy cập ReadWriteOnce". Bạn làm việc với PVC, không động tới PV trực tiếp.
  • StorageClass — định nghĩa cách cấp PV động. Khi bạn tạo PVC, StorageClass tự tạo ra một PV khớp — gọi là dynamic provisioning. Khỏi phải tạo PV bằng tay.

Sự tách biệt này quan trọng: dev chỉ nói "tôi cần ngần này dung lượng"; làm sao có đĩa đó (EBS trên AWS, hostpath trên minikube...) là việc của StorageClass. Cùng một PVC chạy được trên mọi hạ tầng.

minikube có sẵn StorageClass mặc định

kubectl get storageclass
NAME                 PROVISIONER                RECLAIMPOLICY   VOLUMEBINDINGMODE   AGE
standard (default)   k8s.io/minikube-hostpath   Delete          Immediate           14m

minikube cung cấp standard (đánh dấu default), dùng minikube-hostpath — lưu trên đĩa của node. Vì có StorageClass mặc định, ta chỉ cần tạo PVC là tự có PV.

Tạo PVC và xem nó được cấp PV

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: data-pvc
spec:
  accessModes: ["ReadWriteOnce"]
  resources:
    requests:
      storage: 100Mi
kubectl apply -f pvc.yaml
kubectl get pvc,pv
NAME                             STATUS   VOLUME             CAPACITY   ACCESS MODES   STORAGECLASS
persistentvolumeclaim/data-pvc   Bound    pvc-04182fed...    100Mi      RWO            standard

NAME                             CAPACITY   RECLAIM POLICY   STATUS   CLAIM              STORAGECLASS
persistentvolume/pvc-04182fed... 100Mi      Delete           Bound    default/data-pvc   standard

Phép màu của dynamic provisioning: ta chỉ tạo PVC, nhưng một PV (pvc-04182fed...) tự xuất hiện và cả hai ở trạng thái Bound (đã ghép đôi). StorageClass đã âm thầm cấp đĩa. ACCESS MODES: RWOReadWriteOnce — một node gắn đọc-ghi tại một thời điểm (đủ cho phần lớn trường hợp; còn ReadWriteMany cho nhiều node cùng ghi, cần backend hỗ trợ).

Thí nghiệm: dữ liệu sống lâu hơn pod

Đây là phần chứng minh. Gắn PVC vào một pod, ghi dữ liệu, xóa pod, dựng pod mới dùng lại PVC đó, rồi đọc lại.

# trích spec pod
    volumeMounts:
      - name: data
        mountPath: /data
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: data-pvc
kubectl apply -f pod-writer.yaml
# ghi một dòng vào volume
kubectl exec writer -- sh -c 'echo "dữ liệu sống lâu hơn pod - $(date)" > /data/note.txt; cat /data/note.txt'
dữ liệu sống lâu hơn pod - Sat May 23 11:16:26 UTC 2026

Giờ xóa pod rồi dựng pod mới (cùng PVC):

kubectl delete pod writer
kubectl apply -f pod-writer.yaml
kubectl exec writer -- cat /data/note.txt
dữ liệu sống lâu hơn pod - Sat May 23 11:16:26 UTC 2026

Đúng dòng cũ, nguyên vẹn. Pod đã chết và sinh lại hoàn toàn mới, nhưng dữ liệu trong PVC ở nguyên đó. Đây chính là điều emptyDir hay filesystem pod không làm được. Database, upload, log cần giữ — tất cả dựa trên cơ chế này.

reclaim policy: chuyện gì xảy ra khi xóa PVC

Cột RECLAIM POLICY: Delete ở trên có nghĩa: khi bạn xóa PVC, PV (và dữ liệu) cũng bị xóa theo. Phù hợp cho dev/test. Production thường đặt Retain để PV (và dữ liệu) được giữ lại khi PVC mất, tránh xóa nhầm dữ liệu quý. Đây là một nút bạn cần ý thức trước khi xoá PVC ở môi trường thật.

Tổng kết

Filesystem pod phù du — mất khi pod chết, nên dữ liệu cần giữ phải nằm ngoài pod. Kubernetes tách PVC (nhu cầu: "cần ngần này dung lượng") khỏi PV (ổ đĩa thật), với StorageClass cấp PV động (dynamic provisioning) — dev chỉ làm việc với PVC, hạ tầng nào cũng chạy. Tạo PVC là tự có PV Bound; gắn vào pod qua persistentVolumeClaim. Thí nghiệm xóa-rồi-dựng-lại chứng minh dữ liệu sống lâu hơn pod. Để ý reclaim policy (Delete vs Retain) để không xóa nhầm dữ liệu. (StatefulSet ở Bài 12 dựa trên chính cơ chế này cho app có trạng thái.)

Ứng dụng giờ có cấu hình và lưu trữ. Còn một mảnh để phục vụ người dùng thật: đưa HTTP từ ngoài vào, định tuyến theo tên miền/đường dẫn. Bài 9: Ingress.