Filestore CSI Driver & Multishares
Tại sao quan trọng trong production
Trong môi trường GKE với nhiều microservices, nhu cầu shared filesystem rất phổ biến: service A ghi file, service B đọc file đó. Cách naive là tạo một Filestore instance cho mỗi service cần shared storage — nhưng cách này dẫn đến:
- Mỗi instance tốn ít nhất 1 TiB (minimum capacity của Basic tier) cho dù service chỉ cần 50 GiB
- Quản lý lifecycle thủ công: tạo instance → tạo PV → tạo PVC → bind → delete ngược lại
- Chi phí tỉ lệ với số lượng service, không phải thực tế storage dùng
Filestore CSI driver giải quyết vấn đề lifecycle management. Multishares giải quyết vấn đề tốn kém khi có nhiều small workloads.
Internal model — CSI Driver
Kubernetes CSI (Container Storage Interface) là gì
CSI là interface chuẩn mà Kubernetes dùng để nói chuyện với external storage systems. Thay vì hardcode logic của từng storage provider vào Kubernetes core, CSI tách biệt thành plugin riêng.
Filestore CSI driver là một plugin chạy trong cluster GKE, bao gồm:
┌────────────────────────────────────────────────────────┐
│ Kubernetes Control Plane │
│ ┌──────────────────────────────────────────────────┐ │
│ │ External Provisioner (sidecar) │ │
│ │ Watches PVC creation → calls CSI CreateVolume │ │
│ └──────────────────────────────────────────────────┘ │
└──────────────────────────┬─────────────────────────────┘
│ gRPC
┌──────────────────────────▼─────────────────────────────┐
│ CSI Controller (DaemonSet / Deployment) │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Filestore CSI Plugin │ │
│ │ - CreateVolume → calls Filestore API │ │
│ │ - DeleteVolume → calls Filestore API │ │
│ │ - CreateSnapshot → calls Filestore backup API │ │
│ └──────────────────────────────────────────────────┘ │
│ │ │
│ ▼ Filestore API calls │
│ ┌──────────────────────────────────────────────────┐ │
│ │ GCP Filestore Service │ │
│ └──────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────┘Khi bạn tạo một PVC với StorageClass trỏ đến Filestore CSI, flow là:
- Kubernetes External Provisioner detect PVC mới
- Gọi CSI
CreateVolumeRPC - CSI plugin gọi Filestore API để tạo instance (hoặc share, với Multishares)
- Filestore trả về IP và export path
- CSI plugin tạo PV với thông tin kết nối
- Kubernetes bind PVC → PV
- Khi pod schedule đến node, CSI Node plugin thực hiện
NodePublishVolume→ mount NFS
Dynamic Provisioning — Standard (một PVC, một Instance)
Với dynamic provisioning thông thường (không dùng Multishares), mỗi PVC tạo ra một Filestore instance mới:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: filestore-standard
provisioner: filestore.csi.storage.gke.io
parameters:
tier: enterprise # hoặc basic, zonal, regional
network: default
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: trueapiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-app-storage
spec:
accessModes:
- ReadWriteMany # NFS supports multi-writer
storageClassName: filestore-standard
resources:
requests:
storage: 100GiKhi PVC này được tạo, CSI driver sẽ tạo một Filestore instance mới với capacity tối thiểu (1 TiB cho Enterprise tier, dù bạn chỉ request 100 GiB). Đây là vấn đề lãng phí khi có nhiều small PVC.
Snapshot qua CSI
CSI driver tích hợp với Filestore backup API. Khi tạo VolumeSnapshot trong Kubernetes:
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: my-app-snapshot
spec:
volumeSnapshotClassName: filestore-backup
source:
persistentVolumeClaimName: my-app-storageCSI driver gọi Filestore backup API để tạo backup (không phải snapshot theo nghĩa native Filestore). Restoration từ VolumeSnapshot tạo ra một Filestore instance mới từ backup đó.
Lưu ý quan trọng: VolumeSnapshot trong Kubernetes context đối với Filestore CSI tạo ra Filestore backup, không phải Filestore snapshot. Đây là hai khái niệm khác nhau (chi tiết ở Backup & Snapshot).
Internal model — Multishares
Vấn đề Multishares giải quyết
Hình dung bạn có 60 microservices, mỗi service cần 20–50 GiB shared storage. Với standard provisioning:
- 60 Filestore instances (Enterprise tier, minimum 1 TiB mỗi instance)
- Tổng: 60 TiB được provision, nhưng thực tế dùng < 3 TiB
- Chi phí: ~$600–$1,800/tháng thay vì ~$30–$90/tháng nếu pack hiệu quả
Multishares giải quyết bằng cách pack nhiều shares vào một instance:
┌─────────────────────────────────────────────────────────┐
│ Filestore Enterprise Instance (Multishares) │
│ Capacity: 1–10 TiB, expandable │
│ │
│ ┌──────┐ ┌──────┐ ┌──────┐ ... ┌──────┐ │
│ │Share1│ │Share2│ │Share3│ │Share N│ (max 80) │
│ │/vol1 │ │/vol2 │ │/vol3 │ │/volN │ │
│ │50GiB │ │30GiB │ │20GiB │ │... │ │
│ └──┬───┘ └──┬───┘ └──┬───┘ └──┬────┘ │
└─────┼────────┼────────┼─────────────┼────────────────────┘
│ │ │ │
PV-1 PV-2 PV-3 PV-N
│ │ │ │
PVC-1 PVC-2 PVC-3 PVC-N
│ │ │ │
service-1 service-2 service-3 service-NMỗi share là một NFS export riêng biệt với path riêng (/vol1, /vol2,...), mount vào một pod duy nhất. Các pod không thấy data của nhau — isolation hoàn toàn ở application level.
Cơ chế pack và scale
CSI driver quản lý toàn bộ quá trình pack:
Tạo PVC đầu tiên:
- Không có instance nào → CSI driver tạo Filestore Enterprise instance mới (capacity tối thiểu)
- Tạo share đầu tiên trong instance
- Tạo PV trỏ đến share đó
Tạo PVC tiếp theo (cùng StorageClass):
- CSI driver check: instance hiện tại còn chỗ không? (< 80 shares, còn capacity)
- Nếu còn → tạo share mới trong cùng instance (không tạo instance mới)
- Nếu hết slot (80 shares) → tạo instance mới
Tăng capacity tự động: Khi tổng capacity của các shares vượt quá capacity của instance, CSI driver gọi Filestore API để resize instance. Resize xảy ra online, không gây downtime với existing shares.
Ví dụ: Instance bắt đầu với 1 TiB. 40 shares × 50 GiB = 2 TiB được request → CSI driver tự tăng instance lên 2 TiB.
StorageClass parameters quan trọng
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: filestore-multishare
provisioner: filestore.csi.storage.gke.io
parameters:
tier: enterprise
multishare: "true"
multishare-instance-match-key: "prod-apps" # tag để group instances
max-volume-size: "256Gi" # max size của mỗi share
network: defaultmax-volume-size là parameter quan trọng nhất quyết định density:
128Gi: tối đa 80 shares/instance (nhưng mỗi share tối đa 128 GiB)256Gi: tối đa 40 shares/instance (10 TiB ÷ 256 GiB ≈ 40 shares)512Gi: tối đa 20 shares/instance1024Gi: tối đa 10 shares/instance
Bạn không thể thay đổi max-volume-size sau khi instance được tạo (StorageClass là immutable sau khi provisioned). Nếu muốn thay đổi → phải tạo StorageClass mới và migrate workload.
multishare-instance-match-key cho phép group instances theo label. Các PVC dùng cùng StorageClass với cùng key sẽ được pack vào cùng group instances. Dùng để tách biệt workload (prod vs dev, high-priority vs low-priority).
Capacity sizing cho từng share
Mỗi share có thể resize theo từng GiB (so với 256 GiB increment của standard provisioning). Đây là lợi thế lớn cho small workloads:
# Service cần 35 GiB
spec:
resources:
requests:
storage: 35Gi # resize chính xác 35 GiB, không cần làm tròn lên 256 GiBResize share là online operation, không cần restart pod.
Constraints và Limitations quan trọng
Constraint 1: Không có snapshot cho Multishares
Đây là limitation nghiêm trọng nhất: Filestore Multishares không support native snapshot. Điều này có nghĩa:
- Không thể dùng VolumeSnapshot cho PVC được provisioned qua Multishares
- Backup toàn bộ instance thay vì per-share
- Granular recovery (restore một service riêng) phức tạp hơn nhiều
Nguyên nhân kỹ thuật: Filestore snapshot hoạt động ở instance level, không phải share level. Với Multishares, một instance chứa nhiều shares của nhiều services — snapshot instance sẽ include data của tất cả services, không selective.
Nếu workload của bạn cần per-service snapshot, dùng standard provisioning (một instance per service) thay vì Multishares.
Constraint 2: Provisioning latency
Tạo Filestore instance lần đầu mất 5–10 phút. Khi scale lên (instance tiếp theo cần được tạo vì hit 80-share limit), pod sẽ pending trong thời gian này.
Với standard provisioning, latency này xảy ra tại mỗi PVC đầu tiên. Với Multishares, latency chỉ xảy ra khi tạo instance mới (sau mỗi 80 shares) — ít tốt hơn với burst scale scenarios.
Mitigate bằng cách pre-warm: tạo placeholder PVC để trigger instance creation trước khi thực sự cần.
Constraint 3: StorageClass immutability
Sau khi instances đã được provisioned với một StorageClass configuration, bạn không thể thay đổi max-volume-size hay multishare-instance-match-key mà không tạo StorageClass mới.
Migration giữa StorageClasses phức tạp: tạo PVC mới trên StorageClass mới, copy data, update pod references. Không có in-place migration path.
Implication thiết kế: Chọn max-volume-size cẩn thận dựa trên expected workload size. Nếu workloads nhỏ (< 100 GiB), dùng 128Gi để maximize density. Nếu workloads lớn hơn, chọn phù hợp.
Constraint 4: Linux only
GKE Filestore CSI driver version 1.27+ là requirement. CSI driver chỉ support Linux nodes — Windows node pools không support NFS mount qua CSI driver.
Constraint 5: Incompatibility với Regional tier
Multishares chỉ work với Enterprise tier (regional HA được tích hợp). Không thể dùng Multishares với standard Regional tier hay Zonal tier.
Anti-pattern: Dùng Multishares cho high-I/O workloads
Sai lầm: Dùng Multishares instance cho ML training jobs cần 50,000+ IOPS, giả định rằng nhiều shares trong một instance sẽ sum performance.
Thực tế: Các shares trong một Multishares instance chia sẻ performance budget của instance đó. Nếu instance có 100,000 IOPS, và bạn có 10 services đang chạy ML training đồng thời, mỗi service chỉ có hiệu quả ~10,000 IOPS.
Cơ chế: NFS server của Filestore không có per-share IOPS isolation. IO từ tất cả shares đều đi qua cùng storage backend và cùng NFS server process.
Fix: Workload cần dedicated high IOPS → dùng standard provisioning (Zonal tier, one instance per workload) với configured IOPS per TiB. Multishares phù hợp cho workloads với low-to-medium I/O requirements.
GKE Implementation — Setup thực tế
Bước 1: Kích hoạt CSI driver
# Kích hoạt khi tạo cluster mới
gcloud container clusters create my-cluster \
--addons=GcpFilestoreCsiDriver \
--zone=us-central1-a
# Kích hoạt cho cluster có sẵn
gcloud container clusters update my-cluster \
--update-addons=GcpFilestoreCsiDriver=ENABLED \
--zone=us-central1-aBước 2: Tạo StorageClass cho Multishares
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: filestore-multishare-prod
provisioner: filestore.csi.storage.gke.io
parameters:
tier: enterprise
multishare: "true"
multishare-instance-match-key: "production"
max-volume-size: "256Gi"
network: projects/my-project/global/networks/my-vpc
connect-mode: PRIVATE_SERVICE_ACCESS
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
reclaimPolicy: Retain # quan trọng: Retain thay vì Delete để tránh mất dataBước 3: PVC deployment
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: service-a-data
namespace: production
spec:
accessModes:
- ReadWriteMany
storageClassName: filestore-multishare-prod
resources:
requests:
storage: 50GiapiVersion: apps/v1
kind: Deployment
metadata:
name: service-a
spec:
template:
spec:
containers:
- name: app
volumeMounts:
- name: shared-data
mountPath: /data
volumes:
- name: shared-data
persistentVolumeClaim:
claimName: service-a-dataKiểm tra instances đã tạo
# List Filestore instances được tạo bởi CSI driver
gcloud filestore instances list \
--filter="labels.goog-k8s-cluster-name=my-cluster" \
--format="table(name,tier,capacity_gb,state)"