Kubernetes の永続ストレージ: CSI、PV、StorageClass、StatefulSet
Kubernetes はステートレス ワークロードのプラットフォームとして誕生しましたが、アプリケーションの現実 エンタープライズと非常に異なるもの: データベース、メッセージ キュー、永続的キャッシュ システム、 共有ファイルシステム。いずれも、ポッドのライフサイクルを存続するストレージを必要とします。 このストレージを、クラウドプロバイダー間で信頼性が高く、高性能でポータブルな方法で管理します。 これは、日々の生産における最も具体的な課題の 1 つです。
この記事では、コンテナ ストレージから Kubernetes ストレージ レイヤー全体について説明します。 プロバイダー、PersistentVolume、および 動的プロビジョニング用の StorageClass、最大 ステートフルセット のために PostgreSQL、Cassandra、Redis などのデータベースを Kubernetes 上で管理します。
何を学ぶか
- Kubernetes ストレージ モデル: Volume、PersistentVolume、Persistent VolumeClaim
- Container Storage Interface (CSI) の仕組みと最も使用されるドライバー
- StorageClass と動的プロビジョニング: AWS EBS、GCE PD、Azure Disk の構成
- アクセス モード: ReadWriteOnce、ReadOnlyMany、ReadWriteMany - いつ使用するか
- StatefulSet: 安定した ID、自動 PVC、規則的なローリング アップデート
- StatefulSet を使用して Kubernetes 上で PostgreSQL を実行する方法
- Velero を使用した Persistent Volume のバックアップと復元
Kubernetes ストレージ モデル
Kubernetes は、「必要なもの」を分離するストレージの抽象化階層を定義します。 (PersistentVolumeClaim) は「提供されたまま」 (PersistentVolume および StorageClass) からのものです。これ 開発者はプロバイダーの詳細を知らなくてもストレージをリクエストできます 根底にある雲。
ストレージプリミティブ
| リソース | ほうき | 誰が管理しているのか | 説明 |
|---|---|---|---|
| 音量 | ポッド | 開発者 | ポッドのライフサイクルにリンクされた一時ストレージ |
| 永続ボリューム (PV) | クラスター | 管理者/プロビジョナー | クラスター内のストレージ部分、ポッドから独立したライフサイクル |
| PersistentVolumeClaim (PVC) | 名前空間 | 開発者 | ポッドからのストレージのリクエスト |
| ストレージクラス | クラスター | 管理者 | ストレージの「タイプ」とプロビジョナーを定義します |
Persistent Volume のライフサイクル
PV のライフサイクルはさまざまな状態を経ます。それらを理解することが不可欠です トラブルシューティング:
- 利用可能: PV は存在し、無料であり、どの PVC にも関連付けられていません
- バウンド: PV は要件を満たす PVC に接着されています。
- リリース: PVC は削除されましたが、PV はまだ利用できません (データはまだ存在します)。
- 失敗した: PV の自動回収に失敗しました
# Verifica lo stato dei PersistentVolume nel cluster
kubectl get pv -o wide
# Output tipico:
# NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS
# pv-db-001 100Gi RWO Retain Bound production/postgres fast-ssd
# pv-db-002 100Gi RWO Retain Available fast-ssd
# Descrizione dettagliata di un PV
kubectl describe pv pv-db-001
# Verifica i PVC in un namespace
kubectl get pvc -n production
kubectl describe pvc postgres-data -n production
コンテナストレージインターフェース(CSI)
CSI が登場する前は、すべてのストレージ プロバイダーはコードに組み込まれたプラグインを維持する必要がありました。 Kubernetes ソース (ツリー内プラグイン)。これにより、強力で効率的な結合が作成されました。 Kubernetes から独立してプラグインを更新するのは困難です。 CSIがこれを解決する サードパーティによるストレージ ドライバーの作成を可能にする標準の gRPC インターフェイスを使用 独立した Kubernetes ポッドとして。
主な CSI ドライバー
| CSIドライバー | プロバイダー | ストレージタイプ | 読み取り書き込み多数 |
|---|---|---|---|
| aws-ebs-csi-ドライバー | AWS | ブロック (gp3、io2) | No |
| aws-efs-csi-ドライバー | AWS | NFS (EFS) | Si |
| gce-pd-csi-ドライバー | GCP | ブロック (PD-SSD、PD-バランス) | いいえ (RWX FileStore のみ) |
| azuredisk-csi-ドライバー | アズール | ブロック (プレミアム SSD) | No |
| azurefile-csi-ドライバー | アズール | NFS (Azure ファイル) | Si |
| csi-rook-セフ | ルーク/セフ | ブロック/FS/オブジェクト | はい (CephFS) |
| ロングホーン | 牧場主 | ブロック分散 | はい (NFS あり) |
EKS への CSI EBS ドライバーのインストール
# Installa il driver CSI EBS su Amazon EKS
# Prima, crea un IAM Role con le policy necessarie
aws eks create-addon \
--cluster-name my-cluster \
--addon-name aws-ebs-csi-driver \
--service-account-role-arn arn:aws:iam::ACCOUNT_ID:role/EBSCSIRole
# Verifica il daemonset del driver CSI
kubectl get daemonset -n kube-system ebs-csi-node
kubectl get deployment -n kube-system ebs-csi-controller
ストレージクラス: 動的プロビジョニング
静的プロビジョニング (PV を手動で作成する) は、運用環境では現実的ではありません。と 動的プロビジョニング、PVC が到着すると Kubernetes が自動的に PV を作成します StorageClass で構成された CSI ドライバーを使用して作成されます。
AWS EBS の StorageClass
# storage-classes-aws.yaml
# StorageClass per dischi gp3 (performance ottimale)
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
annotations:
storageclass.kubernetes.io/is-default-class: "false"
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer # IMPORTANTE: evita cross-AZ mounting
reclaimPolicy: Retain # Protegge i dati in produzione
allowVolumeExpansion: true
parameters:
type: gp3
iops: "3000"
throughput: "125"
encrypted: "true"
kmsKeyId: "arn:aws:kms:eu-west-1:ACCOUNT:key/KEY_ID"
---
# StorageClass per io2 (database ad alto IOPS)
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: ultra-fast-ssd
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Retain
allowVolumeExpansion: true
parameters:
type: io2
iops: "32000"
encrypted: "true"
---
# StorageClass per EFS (ReadWriteMany, NFS)
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: shared-storage
provisioner: efs.csi.aws.com
reclaimPolicy: Retain
parameters:
provisioningMode: efs-ap
fileSystemId: fs-XXXXXXXX
directoryPerms: "700"
GKE(Google Kubernetes Engine)用のStorageClass
# storage-classes-gke.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd-gke
provisioner: pd.csi.storage.gke.io
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Retain
allowVolumeExpansion: true
parameters:
type: pd-ssd
replication-type: regional-pd # replica su 2 zone
availability-class: regional-hard-failover
volumeBindingMode: WaitForFirstConsumer を使用する理由
常に使用する WaitForFirstConsumer の代わりに Immediate いつ
クラスターには複数のアベイラビリティーゾーンがあります。と Immediate、PVが作成されます
プロビジョナーがスケジュールされているゾーン内 (ゾーンとは異なる場合があります)
ポッドがスケジュールされる場所。結果: ポッドはボリュームのマウントに失敗します。
WaitForFirstConsumer ポッドと同じ領域に PV を作成します。
PersistentVolumeClaim の実際
PVC とポッドがストレージを必要とする方法。 PVC はサイズ、アクセス モードを指定します とストレージクラス。 Kubernetes は互換性のある PV を検索または作成し、それを PVC にバインドします。
# pvc-database.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-data
namespace: production
labels:
app: postgres
tier: database
annotations:
# Snapshot policy (con alcuni storage providers)
storageclass.kubernetes.io/is-default-class: "false"
spec:
accessModes:
- ReadWriteOnce
storageClassName: fast-ssd
resources:
requests:
storage: 100Gi
# Espandi a 200Gi in futuro con:
# kubectl patch pvc postgres-data -p '{"spec":{"resources":{"requests":{"storage":"200Gi"}}}}'
アクセス モード: 適切なものを選択してください
| アクセスモード | 略語 | それはどういう意味ですか | 一般的な使用方法 |
|---|---|---|---|
| リードライトワンス | RWO | 読み取り/書き込みノードは 1 つだけ | データベース、単一インスタンスのアプリケーション |
| 読み取り専用多数 | ロックス | 多くの読み取り専用ノード | 共有静的データ、構成 |
| 読み取り書き込み多数 | RWX | 多くの読み取り/書き込みノード | 共有NFS、アップロードハンドラー |
| ReadWriteOncePod | RWOP | 読み取り/書き込みポッドは 1 つだけ | 単一ポッドの専用ストレージ (K8s 1.29+) |
StatefulSet: 安定した ID を持つワークロード
デプロイメントはステートレスなワークロードには最適ですが、データベースやアプリケーションには最適です。 安定した ID が必要 (予測可能なホスト名、専用ボリューム、ブート順序) それを提供します ステートフルセット。デプロイメントとの主な違いは次のとおりです。
- 安定したアイデンティティ: ポッドには予測可能な名前が付いています。
myapp-0,myapp-1,myapp-2 - 起動順序: ポッドは順序 (0、1、2) で開始され、逆の順序でシャットダウンされます。
- 専用PVC: 各ポッドは、次の経由で独自の PVC を取得します。
volumeClaimTemplates - ヘッドレスサービス: 各ポッドには安定した DNS エントリがあります。
myapp-0.myapp.namespace.svc.cluster.local
StatefulSet を使用した Kubernetes 上の PostgreSQL
以下は、StatefulSet を使用した PostgreSQL の完全な運用準備完了セットアップです。 構成用の ConfigMap、資格情報用の Secret、およびヘッドレス サービスが含まれます。
# postgres-statefulset.yaml
apiVersion: v1
kind: Service
metadata:
name: postgres
namespace: production
labels:
app: postgres
spec:
ports:
- port: 5432
name: postgres
clusterIP: None # Headless Service - abilita il DNS per Pod individuali
selector:
app: postgres
---
# Service per accesso al master (read/write)
apiVersion: v1
kind: Service
metadata:
name: postgres-master
namespace: production
spec:
ports:
- port: 5432
selector:
app: postgres
role: master
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
namespace: production
spec:
serviceName: postgres # deve corrispondere al nome del headless Service
replicas: 3
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
# Anti-affinity: distribuisce le repliche su nodi diversi
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: postgres
topologyKey: kubernetes.io/hostname
initContainers:
# init container per configurare i permessi del volume
- name: init-postgres
image: postgres:16
command:
- bash
- "-c"
- |
chown -R 999:999 /var/lib/postgresql/data
volumeMounts:
- name: postgres-data
mountPath: /var/lib/postgresql/data
containers:
- name: postgres
image: postgres:16
ports:
- containerPort: 5432
name: postgres
env:
- name: POSTGRES_DB
value: myapp
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: postgres-credentials
key: username
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-credentials
key: password
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
volumeMounts:
- name: postgres-data
mountPath: /var/lib/postgresql/data
- name: postgres-config
mountPath: /etc/postgresql/postgresql.conf
subPath: postgresql.conf
resources:
requests:
memory: "2Gi"
cpu: "1000m"
limits:
memory: "4Gi"
cpu: "2000m"
livenessProbe:
exec:
command:
- pg_isready
- -U
- $(POSTGRES_USER)
- -d
- $(POSTGRES_DB)
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
exec:
command:
- pg_isready
- -U
- $(POSTGRES_USER)
- -d
- $(POSTGRES_DB)
initialDelaySeconds: 5
periodSeconds: 5
volumes:
- name: postgres-config
configMap:
name: postgres-config
# PVC template: ogni Pod ottiene il proprio volume da 100Gi
volumeClaimTemplates:
- metadata:
name: postgres-data
spec:
accessModes:
- ReadWriteOnce
storageClassName: fast-ssd
resources:
requests:
storage: 100Gi
PostgreSQL 構成の ConfigMap
# postgres-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: postgres-config
namespace: production
data:
postgresql.conf: |
# Performance tuning per 4GB RAM
shared_buffers = 1GB
work_mem = 64MB
maintenance_work_mem = 256MB
effective_cache_size = 3GB
# WAL settings
wal_level = replica
max_wal_senders = 5
wal_keep_size = 1GB
# Checkpoint
checkpoint_completion_target = 0.9
max_wal_size = 4GB
min_wal_size = 1GB
# Connection settings
max_connections = 200
# Logging
log_min_duration_statement = 1000 # log query lente >1s
log_checkpoints = on
log_connections = on
log_disconnections = on
ボリュームのスナップショットとバックアップ
ボリューム スナップショットを使用すると、Persistent Volume のポイントインタイム バックアップを作成できます。 クラウド プロバイダーのネイティブ機能 (EBS スナップショット、GCE PD スナップショットなど) を使用します。
# Installa le CRD per Volume Snapshot (se non presenti)
kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/client/config/crd/snapshot.storage.k8s.io_volumesnapshotclasses.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/client/config/crd/snapshot.storage.k8s.io_volumesnapshotcontents.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/master/client/config/crd/snapshot.storage.k8s.io_volumesnapshots.yaml
# VolumeSnapshotClass
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
name: ebs-snapshot-class
driver: ebs.csi.aws.com
deletionPolicy: Retain
---
# Crea uno snapshot del volume di PostgreSQL
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: postgres-snapshot-20260801
namespace: production
spec:
volumeSnapshotClassName: ebs-snapshot-class
source:
persistentVolumeClaimName: postgres-data-postgres-0
---
# Verifica lo stato dello snapshot
kubectl get volumesnapshot -n production
# Restore da snapshot: crea un nuovo PVC da snapshot
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-data-restored
namespace: production
spec:
accessModes:
- ReadWriteOnce
storageClassName: fast-ssd
resources:
requests:
storage: 100Gi
dataSource:
name: postgres-snapshot-20260801
kind: VolumeSnapshot
apiGroup: snapshot.storage.k8s.io
完全なクラスター バックアップ用の Velero
Velero は、Kubernetes クラスター全体のバックアップと復元のためのリファレンス ツールです。 PersistentVolume を含む:
# Installa Velero con il plugin EBS
velero install \
--provider aws \
--plugins velero/velero-plugin-for-aws:v1.8.0 \
--bucket my-velero-backups \
--backup-location-config region=eu-west-1 \
--snapshot-location-config region=eu-west-1 \
--secret-file ./credentials-velero
# Crea un backup del namespace production con i volume
velero backup create production-backup-20260801 \
--include-namespaces production \
--snapshot-volumes \
--wait
# Verifica il backup
velero backup describe production-backup-20260801
velero backup logs production-backup-20260801
# Schedule: backup giornaliero a mezzanotte
velero schedule create daily-production \
--schedule="0 0 * * *" \
--include-namespaces production \
--snapshot-volumes \
--ttl 720h # mantieni per 30 giorni
# Restore in un nuovo cluster
velero restore create --from-backup production-backup-20260801 \
--namespace-mappings production:production-restored
AI/ML ワークロード用のストレージ
ML トレーニング ワークロードには、並列アクセスという特別なストレージ要件があります。 大規模なデータセットの高スループット。多くの場合、複数の GPU ワーカーから同時に実行されます。
# PVC con ReadWriteMany per training distribuito
# Usa EFS (AWS) o CephFS (on-premise) per RWX
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: ml-dataset-storage
namespace: ml-training
spec:
accessModes:
- ReadWriteMany
storageClassName: shared-storage # EFS o CephFS
resources:
requests:
storage: 10Ti # 10TB per dataset ImageNet, etc.
---
# Job di training che accede ai dati in parallelo
apiVersion: batch/v1
kind: Job
metadata:
name: distributed-training
namespace: ml-training
spec:
parallelism: 8 # 8 worker GPU in parallelo
completions: 8
template:
spec:
containers:
- name: trainer
image: pytorch/pytorch:2.3.0-cuda12.1-cudnn8-runtime
resources:
limits:
nvidia.com/gpu: "1"
volumeMounts:
- name: dataset
mountPath: /data
readOnly: true # tutti i worker leggono, nessuno scrive
- name: checkpoints
mountPath: /checkpoints
volumes:
- name: dataset
persistentVolumeClaim:
claimName: ml-dataset-storage
readOnly: true
- name: checkpoints
persistentVolumeClaim:
claimName: ml-checkpoints-rwx # RWX per checkpoint condivisi
Kubernetes ストレージのベスト プラクティス
本番ストレージのチェックリスト
- 常に reclaimPolicy を使用します: Retain 本番データ用。
DeletePVC が削除されるとデータが自動的に削除されます - volumeBindingMode: WaitForFirstConsumer: マルチゾーンクラスターでのクロス AZ バインディングの問題を回避する
- allowVolumeExpansion: true: ダウンタイムなしでボリュームを拡張できるように StorageClasses を構成する
- ディスク使用量を監視します。 PVC が容量の 80% を超えた場合に Prometheus でアラートを構成する
- 自動スナップショット: VolumeSnapshotClass とスケジュールされたバックアップを構成する
- 復元をテストします。 テストされていない、役に立たないバックアップ。毎月復元テストを行う
- PVC を役割ごとに分ける: データ用に 1 つ、ログ用に 1 つ、一時バックアップ用に 1 つ PVC
- アンチアフィニティを備えた StatefulSet: 異なるノードおよびゾーンにレプリカを分散する
アンチパターン: これはやめてください
- 運用環境では hostPath を使用しないでください。 Pod を特定のノードに結び付けるため、移植性はありません
- 永続データには emptyDir を使用しないでください。 ポッドを再起動するとクリアされます
- 運用データには reclaimPolicy: Delete を使用しないでください。 間違ってすべてを失う可能性があります
- 同じ PVC (RWO) を複数の Pod にマウントしないでください。 データ破損の原因となる
Prometheus によるストレージ監視
# Metriche chiave da monitorare con kube-state-metrics
# Aggiungi alert a Prometheus
# Alert: PVC vicino alla capacita massima
groups:
- name: kubernetes-storage
rules:
- alert: PVCStorageUsageHigh
expr: |
kubelet_volume_stats_used_bytes /
kubelet_volume_stats_capacity_bytes > 0.80
for: 5m
labels:
severity: warning
annotations:
summary: "PVC {{ $labels.persistentvolumeclaim }} e all'80% della capacita"
description: "Namespace: {{ $labels.namespace }}"
- alert: PVCStorageFull
expr: |
kubelet_volume_stats_used_bytes /
kubelet_volume_stats_capacity_bytes > 0.95
for: 2m
labels:
severity: critical
annotations:
summary: "PVC {{ $labels.persistentvolumeclaim }} quasi piena!"
- alert: PVCNotBound
expr: |
kube_persistentvolumeclaim_status_phase{phase="Pending"} == 1
for: 10m
labels:
severity: warning
annotations:
summary: "PVC {{ $labels.persistentvolumeclaim }} in stato Pending da 10 minuti"
結論と次のステップ
Kubernetes ストレージは、エンタープライズ アプリケーションにとって最も重要なレイヤーの 1 つです。 生産。 Container Storage Interface は、あらゆるものとの統合を標準化します。 プロバイダー、StorageClass による動的プロビジョニングにより手動作業が不要になります。 StatefulSet は、安定した ID でデータベースを管理するために必要なプリミティブを提供します。
実稼働環境で堅牢なストレージを実現する鍵は、アーキテクチャ上の選択の組み合わせです 正しい (reclaimPolicy Retain、WaitForFirstConsumer、アンチアフィニティ)、プロアクティブなモニタリング Prometheus を使用し、Velero または VolumeSnapshot を使用して定期的にテストされたバックアップ戦略を使用します。







