10日で覚えるKubernetesDay 6: ストレージとデータ永続化

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種類

重要ポイント

  1. Docker Volumeに相当するのがPV + PVC。PVがストレージ、PVCが利用要求
  2. StorageClassを使えばPVの動的作成が可能。手動でPVを作る必要がなくなる
  3. データベースのデータ永続化にはPVCを使い、Podが再作成されてもデータを保持する

練習問題

問題1: 基本

5GiのPVCを作成し、Nginx PodにマウントしてHTMLファイルを永続化してください。

問題2: データベース

MySQL用のDeploymentをPVC付きで作成してください。データを投入した後、Podを削除して再作成し、データが残っていることを確認しましょう。

チャレンジ問題

emptyDirとPVCの違いを実験してください。両方にデータを書き込んだ後、Podを削除して再作成し、データの残存状態を比較しましょう。


参考リンク


次回予告: Day 7では「ConfigMapとSecret」について学びます。Docker書籍で環境変数や.envファイルで管理していた設定を、Kubernetesではどう扱うか見ていきましょう。