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)
▼
PodPVC, 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
| Mode | Viết tắt | Ý nghĩa |
|---|---|---|
| ReadWriteOnce | RWO | 1 node mount read-write (block storage) |
| ReadOnlyMany | ROX | Nhiều node mount read-only |
| ReadWriteMany | RWX | Nhiều node mount read-write (NFS, CephFS) |
| ReadWriteOncePod | RWOP | 1 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
| Policy | Khi PVC bị xoá |
|---|---|
Delete | PV (và disk thật) bị xoá → mất data |
Retain | PV giữ lại, admin phải xoá/reuse thủ công |
Production database: dùng Retain + backup strategy.
volumeBindingMode
| Mode | Hành vi |
|---|---|
Immediate | Provision PV ngay khi PVC tạo |
WaitForFirstConsumer | Chờ 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:
| Deployment | StatefulSet | |
|---|---|---|
| Pod name | Random (my-app-7d8f9-x2k) | Ordinal (my-db-0, my-db-1) |
| PVC | Shared hoặc không | Mỗi pod có PVC riêng (data-my-db-0) |
| Startup/shutdown | Parallel | Ordered (0 → 1 → 2) |
| DNS | Qua Service | Mỗ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:
Deletemất data,Retaingiữ 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.