Day 6: ストレージとデータ永続化
今日学ぶこと
- KubernetesにおけるストレージのDocker との違い
- PersistentVolume(PV)とPersistentVolumeClaim(PVC)
- StorageClassによる動的プロビジョニング
- 実践的なデータベースのデータ永続化
DockerボリュームからKubernetesストレージへ
Docker書籍Day 6では、Volume、Bind Mount、tmpfsを学びました。Kubernetesでも同様にデータの永続化が必要ですが、複数ノードにまたがるクラスタ環境では追加の仕組みが必要になります。
| Docker | Kubernetes | 説明 |
|---|---|---|
| Volume | PersistentVolume | ストレージの実体 |
docker volume create |
PV作成 / StorageClass | ストレージの確保 |
-v myvolume:/data |
PersistentVolumeClaim | ストレージの利用要求 |
| tmpfs | emptyDir(medium: Memory) | 一時的なメモリストレージ |
ボリュームの種類
emptyDir
Podが存在する間だけ有効な一時ボリュームです。Pod内のコンテナ間でデータを共有する際に使います。
apiVersion: v1
kind: Pod
metadata:
name: shared-volume-pod
spec:
containers:
- name: writer
image: busybox:1.37
command: ["sh", "-c", "echo 'Hello' > /data/message.txt && sleep 3600"]
volumeMounts:
- name: shared-data
mountPath: /data
- name: reader
image: busybox:1.37
command: ["sh", "-c", "cat /data/message.txt && sleep 3600"]
volumeMounts:
- name: shared-data
mountPath: /data
volumes:
- name: shared-data
emptyDir: {}
注意: Podが削除されるとemptyDirのデータも消えます。
hostPath
ノードのファイルシステムをPodにマウントします。DockerのBind Mountに相当します。
volumes:
- name: host-data
hostPath:
path: /var/data
type: DirectoryOrCreate
注意: hostPathはノード固定のため、Podが別のノードに移動するとデータにアクセスできなくなります。本番環境では使わないようにしましょう。
PersistentVolumeとPersistentVolumeClaim
Kubernetesの本格的なストレージ管理は、**PersistentVolume(PV)とPersistentVolumeClaim(PVC)**の2つのリソースで行います。
flowchart LR
ADMIN["管理者"] -->|"作成"| PV["PersistentVolume\n(ストレージの実体)"]
DEV["開発者"] -->|"作成"| PVC["PersistentVolumeClaim\n(ストレージの要求)"]
PVC -->|"バインド"| PV
POD["Pod"] -->|"マウント"| PVC
style PV fill:#8b5cf6,color:#fff
style PVC fill:#3b82f6,color:#fff
style POD fill:#22c55e,color:#fff
PersistentVolume(PV)
クラスタ内のストレージリソースです。管理者が事前に用意するか、StorageClassで動的に作成されます。
apiVersion: v1
kind: PersistentVolume
metadata:
name: my-pv
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
hostPath:
path: /mnt/data
PersistentVolumeClaim(PVC)
開発者がストレージを要求するためのリソースです。条件に合うPVが自動的にバインドされます。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
PodからPVCを使う
apiVersion: v1
kind: Pod
metadata:
name: app-with-storage
spec:
containers:
- name: app
image: nginx:1.27
volumeMounts:
- name: data
mountPath: /usr/share/nginx/html
volumes:
- name: data
persistentVolumeClaim:
claimName: my-pvc
アクセスモード
| モード | 略称 | 説明 |
|---|---|---|
| ReadWriteOnce | RWO | 1つのノードから読み書き可能 |
| ReadOnlyMany | ROX | 複数ノードから読み取り専用 |
| ReadWriteMany | RWX | 複数ノードから読み書き可能 |
| ReadWriteOncePod | RWOP | 1つのPodからのみ読み書き可能 |
回収ポリシー
PVCが削除された後のPVの扱いを指定します。
| ポリシー | 説明 |
|---|---|
| Retain | PVとデータを保持。手動で再利用する |
| Delete | PVとストレージを自動削除 |
| Recycle | データを削除してPVを再利用(非推奨) |
StorageClass(動的プロビジョニング)
PVを事前に作成する代わりに、StorageClassを使えばPVC作成時に自動的にPVがプロビジョニングされます。
flowchart LR
PVC["PVC\n(5Gi要求)"] -->|"StorageClassを参照"| SC["StorageClass\n(standard)"]
SC -->|"自動作成"| PV["PersistentVolume\n(5Gi)"]
PVC -->|"バインド"| PV
style SC fill:#f59e0b,color:#fff
style PV fill:#8b5cf6,color:#fff
style PVC fill:#3b82f6,color:#fff
# 利用可能なStorageClassを確認
kubectl get storageclasses
# NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE
# standard (default) rancher.io/local-path Delete WaitForFirstConsumer
StorageClassを指定したPVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: dynamic-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: standard
resources:
requests:
storage: 5Gi
storageClassNameを省略すると、デフォルトのStorageClassが使用されます。
実践: PostgreSQLのデータ永続化
Docker書籍Day 6でMySQLの永続化を行いましたが、今回はKubernetesでPostgreSQLのデータを永続化します。
# postgres-storage.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres
spec:
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:17
ports:
- containerPort: 5432
env:
- name: POSTGRES_DB
value: myapp
- name: POSTGRES_USER
value: admin
- name: POSTGRES_PASSWORD
value: secret123
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
volumeMounts:
- name: postgres-data
mountPath: /var/lib/postgresql/data
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
volumes:
- name: postgres-data
persistentVolumeClaim:
claimName: postgres-pvc
---
apiVersion: v1
kind: Service
metadata:
name: postgres-service
spec:
type: ClusterIP
selector:
app: postgres
ports:
- port: 5432
targetPort: 5432
デプロイと確認
# リソースを作成
kubectl apply -f postgres-storage.yaml
# PVCの状態確認
kubectl get pvc
# NAME STATUS VOLUME CAPACITY ACCESS MODES
# postgres-pvc Bound pvc-abc12345-def6-7890-ghij-klmnopqrstuv 1Gi RWO
# PVの確認
kubectl get pv
# データの永続性を確認:Podを削除して再作成
kubectl delete pod -l app=postgres
# Deploymentが新しいPodを作成 → データは保持されている
PVのライフサイクル
flowchart LR
A["Available\n(利用可能)"] --> B["Bound\n(バインド済み)"]
B --> C["Released\n(解放済み)"]
C -->|"Retain"| D["手動で\n再利用"]
C -->|"Delete"| E["自動\n削除"]
style A fill:#22c55e,color:#fff
style B fill:#3b82f6,color:#fff
style C fill:#f59e0b,color:#fff
style E fill:#ef4444,color:#fff
# PVの状態確認
kubectl get pv
# NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS
# my-pv 10Gi RWO Retain Bound
# PVCの削除
kubectl delete pvc my-pvc
# Retainポリシーの場合、PVはReleasedになる
kubectl get pv
# STATUS: Released
まとめ
| 概念 | 説明 |
|---|---|
| emptyDir | Pod内コンテナ間の一時共有ボリューム |
| hostPath | ノードのファイルシステムをマウント(開発用) |
| PersistentVolume (PV) | クラスタ内のストレージリソース |
| PersistentVolumeClaim (PVC) | ストレージの利用要求 |
| StorageClass | PVの動的プロビジョニングを定義 |
| アクセスモード | RWO、ROX、RWX、RWOPの4種類 |
重要ポイント
- Docker Volumeに相当するのがPV + PVC。PVがストレージ、PVCが利用要求
- StorageClassを使えばPVの動的作成が可能。手動でPVを作る必要がなくなる
- データベースのデータ永続化にはPVCを使い、Podが再作成されてもデータを保持する
練習問題
問題1: 基本
5GiのPVCを作成し、Nginx PodにマウントしてHTMLファイルを永続化してください。
問題2: データベース
MySQL用のDeploymentをPVC付きで作成してください。データを投入した後、Podを削除して再作成し、データが残っていることを確認しましょう。
チャレンジ問題
emptyDirとPVCの違いを実験してください。両方にデータを書き込んだ後、Podを削除して再作成し、データの残存状態を比較しましょう。
参考リンク
次回予告: Day 7では「ConfigMapとSecret」について学びます。Docker書籍で環境変数や.envファイルで管理していた設定を、Kubernetesではどう扱うか見ていきましょう。