Thông báo lỗiĐây là một vấn đề phổ biến gây đau đầu: bạn triển khai một ứng dụng stateful, nhưng PersistentVolumeClaim (PVC) của bạn không thoát khỏi trạng thái Pending. Khi bạn kiểm tra kỹ hơn bằng lệnh kubectl describe pvc <pvc-name>, bạn sẽ gặp phải rào cản cụ thể này:
persistentvolumeclaims "my-pvc" is forbidden: no persistent volumes available for this claim and no storage class is set
Điều gì đang thực sự xảy ra?Về cơ bản, Kubernetes đang báo cho bạn biết rằng nó không biết nên lưu trữ dữ liệu của bạn ở đâu. Hãy coi PVC như một chiếc vé đặt chỗ trong rạp hát. Nếu rạp hát chưa xây bất kỳ chiếc ghế nào (Static Provisioning - Cấp phát tĩnh) và cũng không có máy tự động nào để xây ghế cho bạn (Dynamic Provisioning - Cấp phát động), bạn sẽ bị bỏ lại đứng chờ ở sảnh.
Lỗi này thường xuất hiện vì ba lý do:
- Thiếu mặc định: Cluster của bạn thiếu một StorageClass được chỉ định là "Default".- Manifest trống: File YAML của PVC không chỉ định
storageClassName, khiến Kubernetes phải tự đoán.- Sai lệch thủ công: Bạn đã tạo một PersistentVolume (PV) thủ công, nhưng kích thước (ví dụ: 5Gi) hoặc AccessMode không khớp với những gì PVC yêu cầu (ví dụ: 10Gi).## Giải pháp 1: Gán StorageClass mặc địnhHầu hết các dịch vụ quản lý như AWS EKS hoặc Google GKE đều đi kèm với các driver lưu trữ được cài đặt sẵn, nhưng chúng có thể không được thiết lập làm mặc định. Bằng cách đánh dấu một class là mặc định, bất kỳ PVC nào không yêu cầu loại cụ thể sẽ tự động sử dụng class này. Bắt đầu bằng cách liệt kê các class hiện có của bạn:
kubectl get storageclass
Nếu bạn thấy một class như gp2 (trên AWS) hoặc standard (trên GKE) nhưng nó không hiển thị (default), hãy chạy lệnh sau để khắc phục:
kubectl patch storageclass gp2 -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
Sau khi đã patch, hãy xóa PVC đang bị kẹt và tạo lại. Nó sẽ được liên kết (bind) gần như ngay lập tức.
Giải pháp 2: Xác định rõ storageClassNameĐôi khi bạn không muốn sử dụng một giá trị mặc định cho toàn bộ hệ thống. Bạn có thể cần SSD hiệu năng cao cho cơ sở dữ liệu nhưng chỉ cần ổ cứng HDD giá rẻ cho log. Trong trường hợp này, bạn phải chỉ định chính xác "template" nào PVC nên sử dụng.
Cập nhật file pvc.yaml của bạn để bao gồm trường storageClassName:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: database-storage
spec:
accessModes:
- ReadWriteOnce
storageClassName: premium-r3 # Sử dụng tên class cụ thể của bạn tại đây
resources:
requests:
storage: 20Gi
Áp dụng bản cập nhật. Kubernetes giờ đây sẽ liên hệ với CSI driver cụ thể (như EBS hoặc Azure Disk driver) để cấp phát volume 20Gi đó.
Giải pháp 3: Cấp phát thủ công cho Bare MetalNếu bạn đang chạy home lab hoặc một cluster bare-metal mà không có nhà cung cấp đám mây, tính năng cấp phát động (dynamic provisioning) sẽ không có sẵn ngay lập tức. Bạn phải tự mình đóng vai trò là "máy cấp phát lưu trữ".
Tạo một PersistentVolume thủ công khớp với các yêu cầu của claim:
apiVersion: v1
kind: PersistentVolume
metadata:
name: local-pv-01
spec:
capacity:
storage: 50Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
hostPath:
path: "/mnt/data/mysql"
Mẹo chuyên gia: Để PVC có thể nhận volume thủ công này, hãy đảm bảo storageClassName trong PVC của bạn hoặc là để trống ("") hoặc khớp với tên class mà bạn đặt cho PV.
Xác minh kết quảSau khi áp dụng một trong các giải pháp này, hãy kiểm tra lại trạng thái PVC của bạn:
kubectl get pvc
Bạn cần tìm trạng thái Bound. Nó trông như thế này:
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
database-storage Bound pvc-8a7b6c... 20Gi RWO premium-r3 15s
Nếu trạng thái là Bound, các Pod của bạn cuối cùng sẽ chuyển từ trạng thái ContainerCreating sang Running.

