Pod là thứ tạm thời; dữ liệu thì thường không. Bài này đo bốn cách gắn lưu trữ vào pod và cái nào sống sót qua việc pod bị xoá.
Bốn loại, cùng phép ghi 300 MB
| Hệ tệp | Thời gian | Thông lượng | |
|---|---|---|---|
emptyDir: {} |
ext4 | 562 ms | 533 MB/giây |
emptyDir: {medium: Memory} |
tmpfs | 140 ms | 2.142 MB/giây |
hostPath |
tmpfs | 119 ms | 2.521 MB/giây |
| lớp ghi của container | overlay | 362 ms | 828 MB/giây |
PVC local-path |
ext4 | ~230 ms | ~900 MB/giây |
emptyDir trong RAM nhanh gấp bốn lần emptyDir trên đĩa.
Nhưng có một cái bẫy: medium: Memory tính vào giới hạn bộ nhớ của pod. Ghi 2 GB vào đó với limits.memory: 1Gi là OOMKilled (phần 54) — và nguyên nhân sẽ rất khó lần ra, vì ứng dụng không hề cấp phát bộ nhớ nào.
Chú ý dòng cuối cùng của bảng trên: lớp ghi của container (overlay) nhanh hơn emptyDir trên đĩa. Đó là kết quả tôi không chờ đợi, và nó nhắc rằng "ghi vào container thì chậm" không phải luôn đúng.
Nhưng lớp ghi container vẫn là chỗ tệ nhất để ghi dữ liệu, vì lý do khác: nó không giới hạn được, không theo dõi được, và đầy đĩa node thì kubelet đuổi pod (phần 54).
Dữ liệu sống hay chết
Ghi một tệp, xoá pod, tạo lại pod:
emptyDir -> số tệp còn lại: 0 MẤT
PVC -> "du lieu quan trong" CÒN
emptyDir gắn với vòng đời pod, không phải vòng đời container. Phân biệt này quan trọng:
- Container khởi động lại (
RESTARTStăng) → dữ liệu còn. - Pod bị xoá và tạo lại → dữ liệu mất.
Nghĩa là emptyDir sống qua một lần OOMKilled nhưng không sống qua một lần triển khai.
Điều đó khiến nó hợp lý cho: thư mục tạm, bộ nhớ đệm dựng lại được, và chia sẻ tệp giữa các container trong cùng pod (phần 44).
PVC được cấp phát muộn
StorageClass: standard rancher.io/local-path WaitForFirstConsumer
ngay sau khi tạo PVC: Pending
sau khi pod chạy: Bound pvc-f41aa46e-... 1Gi RWO
PVC nằm ở Pending cho tới khi có pod dùng tới nó. Đây không phải lỗi — đó là volumeBindingMode: WaitForFirstConsumer.
Lý do: nếu cấp phát ngay, hệ thống lưu trữ phải chọn vùng hoặc node trước khi biết pod sẽ chạy ở đâu — và có thể chọn sai chỗ, khiến pod không bao giờ xếp được.
Chờ tới khi bộ lập lịch quyết định xong rồi mới cấp là đúng thứ tự.
Với volumeBindingMode: Immediate thì ngược lại: PVC Bound ngay, và bộ lập lịch buộc phải đặt pod ở nơi volume đã nằm.
PVC bị ghim vào node
nodeAffinity của PV:
{"key":"kubernetes.io/hostname","operator":"In","values":["sc-worker"]}
Với local-path, PV là một thư mục trên đĩa của đúng một node. PV mang nodeAffinity trỏ vào node đó, và bộ lập lịch buộc phải đặt pod ở đấy.
Hệ quả: node chết là pod không chạy được ở đâu cả. Nó nằm Pending với node(s) had volume node affinity conflict cho tới khi node quay lại.
Đây chính là điều phần 42 đã nêu về kind. Lưu trữ mạng — NFS, đĩa đám mây, Ceph — không có ràng buộc này, và pod chuyển node tự do.
Ba chế độ truy cập
ReadWriteOnce (RWO) một NODE gắn được, đọc và ghi
ReadOnlyMany (ROX) nhiều node, chỉ đọc
ReadWriteMany (RWX) nhiều node, đọc và ghi
RWO là chế độ hay bị hiểu sai nhất. Nó nghĩa là một node, không phải một pod — nhiều pod trên cùng node gắn được cùng một PVC RWO.
Và phần lớn hệ thống lưu trữ khối (đĩa đám mây, iSCSI) chỉ hỗ trợ RWO. RWX cần hệ tệp mạng: NFS, CephFS, hoặc dịch vụ tệp của nhà cung cấp đám mây.
Đây là lý do Deployment nhiều bản dùng chung một PVC RWO sẽ kẹt: bản thứ hai xếp lên node khác không gắn được volume. Với ứng dụng có trạng thái, StatefulSet cho mỗi bản một PVC riêng — đó mới là mẫu đúng.
reclaimPolicy: điều gì xảy ra khi xoá PVC
Delete xoá PVC là xoá luôn PV và dữ liệu <- mặc định của phần lớn StorageClass
Retain giữ PV lại, phải dọn tay
Delete là mặc định, và nó nghĩa là kubectl delete pvc xoá dữ liệu vĩnh viễn. Không có thùng rác, không có xác nhận.
Với dữ liệu quan trọng, tạo một StorageClass riêng với reclaimPolicy: Retain. Cái giá là PV mồ côi phải dọn tay — và đó là cái giá rẻ so với việc mất dữ liệu vì một lệnh gõ nhầm.
Bốn loại volume khác đáng biết
configMap và secret — phần 61 đã đo, gắn dưới dạng liên kết mềm và cập nhật nguyên tử.
downwardAPI — đưa thông tin về chính pod (tên, namespace, nhãn, giới hạn tài nguyên) vào tệp hoặc biến môi trường.
projected — gộp nhiều nguồn (ConfigMap, Secret, downwardAPI, token) vào một thư mục.
csi — mọi hệ thống lưu trữ hiện đại. Kubernetes không còn nhúng driver cho từng nhà cung cấp; tất cả đều qua giao diện CSI.
Thử ba mươi giây
Xem PVC nào của bạn bị ghim vào node:
kubectl get pv -o custom-columns=\
TEN:.metadata.name,PVC:.spec.claimRef.name,\
NODE:.spec.nodeAffinity.required.nodeSelectorTerms[0].matchExpressions[0].values[0],\
CHINH_SACH:.spec.persistentVolumeReclaimPolicy
Cột NODE có giá trị nghĩa là pod dùng PVC đó chỉ chạy được trên node ấy. Cột CHINH_SACH là Delete nghĩa là xoá PVC sẽ xoá luôn dữ liệu.
Phần sau đo StatefulSet: vì sao cơ sở dữ liệu cần nó thay vì Deployment.