Volume types, từ tạm thời đến bền vững

emptyDir, scratch space

volumes:
  - name: scratch
    emptyDir: {} # Mặc định: disk node
    # emptyDir:
    #   medium: Memory             # tmpfs, nhanh nhưng tính vào memory limit
    #   sizeLimit: 100Mi
  • Tạo khi pod start, xoá khi pod bị xoá (không phải khi container restart).
  • Dùng cho: cache tạm, shared data giữa containers trong pod, sort/transform.
  • Không bền vững, pod mất = data mất.

hostPath, mount từ node

volumes:
  - name: docker-sock
    hostPath:
      path: /var/run/docker.sock
      type: Socket

Cảnh báo lớn:

  • Pod trên node khác → path khác → data khác.
  • Rủi ro bảo mật: container access filesystem host.
  • Chỉ dùng cho: DaemonSet đọc log host, mount Docker socket (CI runner).
  • Không dùng cho persistent data.

PersistentVolume (PV) và PersistentVolumeClaim (PVC)

StorageClass (admin: loại disk + provisioner)
│  (dynamic provisioning)
▼
PersistentVolume (EBS / PD / NFS / Ceph…)
│  (bound)
▼
PersistentVolumeClaim (Pod yêu cầu dung lượng)
│  (mount)
▼
Pod

PVC, cách pod yêu cầu storage

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: data-pvc
spec:
  accessModes:
    - ReadWriteOnce # RWO: 1 node mount (phổ biến nhất)
  resources:
    requests:
      storage: 10Gi
  storageClassName: gp3 # StorageClass (cloud provisioner)

Access modes

ModeViết tắtÝ nghĩa
ReadWriteOnceRWO1 node mount read-write (block storage)
ReadOnlyManyROXNhiều node mount read-only
ReadWriteManyRWXNhiều node mount read-write (NFS, CephFS)
ReadWriteOncePodRWOP1 pod duy nhất mount (K8s 1.29+ GA)

Phổ biến nhất: RWO cho database, app state. RWX khi nhiều pod cần write cùng volume (hiếm, cần NFS hoặc CephFS).

Mount PVC vào Pod

spec:
  containers:
    - name: app
      volumeMounts:
        - name: data
          mountPath: /data
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: data-pvc

StorageClass, dynamic provisioning

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: gp3
provisioner: ebs.csi.aws.com # CSI driver
parameters:
  type: gp3
  fsType: ext4
reclaimPolicy: Delete # Hoặc Retain
volumeBindingMode: WaitForFirstConsumer # Chờ pod schedule rồi mới provision
allowVolumeExpansion: true # Cho phép resize PVC

reclaimPolicy

PolicyKhi PVC bị xoá
DeletePV (và disk thật) bị xoá → mất data
RetainPV giữ lại, admin phải xoá/reuse thủ công

Production database: dùng Retain + backup strategy.

volumeBindingMode

ModeHành vi
ImmediateProvision PV ngay khi PVC tạo
WaitForFirstConsumerChờ pod schedule → provision PV ở AZ đúng

WaitForFirstConsumer quan trọng trên multi-AZ cloud: tránh provision disk ở AZ A mà pod schedule ở AZ B.


Resize PVC

# Nếu StorageClass cho phép (allowVolumeExpansion: true)
kubectl edit pvc data-pvc
# Sửa spec.resources.requests.storage: 20Gi

# Kiểm tra status
kubectl describe pvc data-pvc
# Conditions: FileSystemResizePending → resize khi pod restart

Chỉ tăng, không giảm được. Filesystem resize thường cần pod restart (unmount/remount).


StatefulSet, workload có identity

Khác Deployment:

DeploymentStatefulSet
Pod nameRandom (my-app-7d8f9-x2k)Ordinal (my-db-0, my-db-1)
PVCShared hoặc khôngMỗi pod có PVC riêng (data-my-db-0)
Startup/shutdownParallelOrdered (0 → 1 → 2)
DNSQua ServiceMỗi pod có DNS riêng (headless)

StatefulSet spec

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: my-db
spec:
  serviceName: my-db # Headless Service (bắt buộc)
  replicas: 3
  selector:
    matchLabels:
      app: my-db
  template:
    metadata:
      labels:
        app: my-db
    spec:
      containers:
        - name: postgres
          image: postgres:16
          ports:
            - containerPort: 5432
          volumeMounts:
            - name: data
              mountPath: /var/lib/postgresql/data
  volumeClaimTemplates: # Tự tạo PVC per pod
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        storageClassName: gp3
        resources:
          requests:
            storage: 20Gi

DNS cho StatefulSet

Cần headless Service:

apiVersion: v1
kind: Service
metadata:
  name: my-db
spec:
  clusterIP: None
  selector:
    app: my-db
  ports:
    - port: 5432

DNS: my-db-0.my-db.default.svc.cluster.local, my-db-1.my-db.default.svc.cluster.local

Khi nào dùng StatefulSet

  • Database (PostgreSQL, MySQL, MongoDB).
  • Message queue (Kafka, RabbitMQ).
  • Distributed system cần stable network identity (etcd, ZooKeeper).

Khi nào KHÔNG dùng StatefulSet

  • App stateless (API server, web) → Deployment.
  • State lưu ở managed service (RDS, Cloud SQL) → Deployment gọi external DB.
  • Bạn chỉ cần shared storage → Deployment + PVC (RWX).

CSI (Container Storage Interface)

K8s không trực tiếp quản lý storage, giao cho CSI driver:

  • AWS EBS CSI: ebs.csi.aws.com
  • GCE PD CSI: pd.csi.storage.gke.io
  • Azure Disk CSI: disk.csi.azure.com
  • NFS CSI: NFS provisioner
  • Local path: rancher.io/local-path (dev/test)
# Xem CSI drivers
kubectl get csidrivers

Tóm tắt

  • emptyDir: tạm, mất khi pod xoá. hostPath: mount host, nguy hiểm.
  • PVC/PV: storage bền vững. StorageClass + CSI driver tự provision.
  • reclaimPolicy: Delete mất data, Retain giữ lại.
  • StatefulSet: ordered identity + PVC per pod. Dùng cho database, message queue.
  • Nguyên tắc: tránh state trên K8s nếu có managed alternative (RDS, Cloud SQL).

Câu hỏi hay gặp

PVC Pending mãi, nguyên nhân?

Trả lời: (1) StorageClass không tồn tại; (2) WaitForFirstConsumer nhưng chưa có pod yêu cầu; (3) CSI driver chưa cài; (4) Quota hết (cloud disk limit). Kiểm tra Events: kubectl describe pvc.

Xoá StatefulSet có xoá PVC không?

Trả lời: Không. PVC tạo bởi volumeClaimTemplates không bị xoá khi StatefulSet bị xoá. Phải xoá PVC thủ công. Đây là by design, tránh mất data.

Database trên K8s vs managed service, chọn thế nào?

Trả lời: Managed service (RDS, Cloud SQL) nếu: team nhỏ, không muốn quản lý backup/HA/upgrade. K8s StatefulSet nếu: cần portability, on-prem, hoặc dùng operator (CloudNativePG, Zalando PostgreSQL Operator) quản lý lifecycle. Rule of thumb: nếu có thể dùng managed, dùng managed.


Bài tiếp theo (Giai đoạn V): Requests, limits, QoS và OOM, tài nguyên và ổn định cluster.