1. Tạo NFS Server để lưu trữ dữ liệu
Tạo thư mục chưa dữ liệu (thực hiện trên nfs-server)
mkdir /opt/k8s_data
sudo chown -R nobody:nogroup /opt/k8s_data/
sudo chmod 0777 /opt/k8s_data/
Thêm vào /etc/exporter
echo '/opt/k8s_data *(rw,sync,no_subtree_check,no_root_squash)' | sudo tee -a /opt/k8s_data
Apply config
sudo exportfs -ra
sudo systemctl restart nfs-server
Kiểm tra trên các máy trong cụm k8s
sudo apt-get update && sudo apt-get install -y nfs-common
sudo mount -t nfs4 10.100.1.21:/opt/k8s_data /mnt && ls /mnt && sudo umount /mnt
2. Cài đặt Dynamic Provisioner trên node master (k8s-master)
2.1 Dynamic Provisioner là gì?
Trong Kubernetes, khi Pod cần lưu trữ lâu dài, nó sẽ tạo PVC (PersistentVolumeClaim).
PVC này phải được gắn vào một PV (PersistentVolume).
Static provisioning: Admin phải tạo PV thủ công (chỉ định dung lượng, SC, path NFS…). PVC chỉ bind được khi có PV phù hợp. → Mất công quản lý, khó scale.
Dynamic provisioning: Có một Provisioner (controller) chạy trong cluster. Khi PVC được tạo, provisioner sẽ tự động tạo PV mới khớp với yêu cầu (size, StorageClass, accessMode). → App tự xin storage là có, không cần admin làm thủ công.
Ví dụ:
- PVC 10Gi → Provisioner tự tạo PV 10Gi trên NFS (thư mục con mới).
- PVC 2Gi khác → Provisioner tạo thêm PV riêng 2Gi.
→ Tất cả tự động, không cần mình viết file PV trước.
2.2 Tại sao cần Dynamic Provisioner?
Nếu không có provisioner (giống tình huống của của bài lab này khi StorageClass nfs-storage là no-provisioner):
- PVC sẽ bị Pending mãi: “no persistent volumes available to bind”.
- Muốn chạy được thì bạn phải tạo PV thủ công cho từng app (Prometheus, Grafana, Alertmanager, PostgreSQL, …). Rất phiền.
Nếu có Dynamic Provisioner:
- Tạo một StorageClass duy nhất (ví dụ
nfs-storage). - Mọi app chỉ cần khai báo PVC: size bao nhiêu, mode gì.
- Provisioner lo hết → tự tạo thư mục con trên NFS, tạo PV và gắn vào PVC.
- Khi xóa PVC → Provisioner có thể xóa luôn PV + thư mục (tùy reclaimPolicy).
Nói cách khác: Dynamic Provisioner = Automation cho PV. Nó biến Kubernetes storage thành “plug & play”, giống như cloud provider (AWS EBS, GCP PD, Azure Disk) làm.
2.3 Ưu điểm khi setup Dynamic Provisioner
- Nhanh: Không phải viết PV thủ công.
- Scale: Deploy thêm app nào cũng có storage.
- An toàn: Dữ liệu tách riêng theo PVC/PV → không “dẫm chân” nhau.
- Quản lý dễ: Chỉ cần theo dõi PVC/PV, không lo mapping thủ công
2.4 Cài đặt
Add repo + update
helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
helm repo update
Cài đặt vào kube-system, đặt tên storageClass là nfs-storage
helm upgrade --install nfs-provisioner \
nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
-n beobeo-storage \
--create-namespace \
--set nfs.server=10.100.1.21 \
--set nfs.path=/opt/k8s_data \
--set storageClass.name=beobeo-nfs-monitoring-storage \
--set storageClass.defaultClass=false

Kiểm tra
kubectl -n beobeo-storage get pods -l app=nfs-subdir-external-provisioner
kubectl get sc
# Kỳ vọng: thấy SC 'nfs-storage' có PROVISIONER (không phải kubernetes.io/no-provisioner)

=> Vì sao cần dynamic provisioner? Để mọi PVC được cấp PV tự động (không phải tạo PV thủ công). Nếu không có, PVC sẽ Pending mãi.
3. Cài đặt Prometheus – Grafana Stack bằng Helm Chart
3.1 Vì sao Prometheus đặc biệt cần?
Prometheus (và Grafana, Alertmanager) là stateful app:
- Prometheus lưu time-series data vài GB đến hàng trăm GB.
- Nếu không có PVC, Prometheus chỉ chạy được trong memory (ephemeral storage), khi pod bị xóa là mất hết data.
- Vì vậy
chart kube-prometheus-stackluôn tạo PVC. Nếu không có Dynamic Provisioner → PVC Pending → Pod Pending.
3.2 Tạo namespace monitoring & add repo chart
kubectl create ns beobeo-monitoring
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update

3.3 Cấu hình values-prom.yaml
file values-prom.yaml
prometheus:
prometheusSpec:
storageSpec:
volumeClaimTemplate:
spec:
storageClassName: beobeo-nfs-monitoring-storage
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
alertmanager:
alertmanagerSpec:
storage:
volumeClaimTemplate:
spec:
storageClassName: beobeo-nfs-monitoring-storage
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 2Gi
grafana:
persistence:
enabled: true
storageClassName: beobeo-nfs-monitoring-storage
accessModes: ["ReadWriteOnce"]
size: 5Gi
service:
type: NodePort
3.4 Cài đặt
helm upgrade --install beobeo prometheus-community/kube-prometheus-stack \
-n beobeo-monitoring \
-f values-prom.yaml

kubectl --namespace beobeo-monitoring get pods -l "release=beobeo"

Truy cập vào qua IP:Port của NodePort
