Pod でエフェメラルボリュームと永続ボリュームを使用する

KubernetesBeginner
オンラインで実践に進む

はじめに

コンテナには書き込み可能なファイルシステムがありますが、そのストレージはコンテナに紐付いています。Kubernetes ボリュームを使用すると、Pod でファイルをより適切に管理できます。一部のボリュームはエフェメラル(一時的)であり、単一の Pod 内での一時的なデータ用です。一方、永続ボリュームは、Pod が削除されて再作成された後でもデータを保持できます。

この実験では、Pod ローカルのスクラッチデータ用に emptyDir ボリュームを使用し、次に PersistentVolumeClaim (PVC) を作成して 2 つの異なる Pod にマウントすることで、Pod が置き換わってもデータが存続することを証明します。

ボリューム演習用の名前空間を準備する

このステップでは、クリーンな名前空間を準備し、この実験に必要なストレージコンポーネントがクラスターに存在することを確認します。

/home/labex/project から開始します。このディレクトリ内に Pod と PVC のマニフェストを作成します。

mkdir -p /home/labex/project
cd /home/labex/project

Kubernetes API サーバーにアクセスできることを確認します。VM が起動した直後でノードの準備ができていない場合は、数秒待ってからコマンドを再実行してください。

kubectl get nodes --request-timeout=5s

期待される出力例:

NAME         STATUS   ROLES           AGE   VERSION
labex-v135   Ready    control-plane   ...   v1.35...

クラスターのネットワーク Pod が Ready になるまで待ちます。

kubectl wait --namespace kube-system --for=condition=Ready pod -l k8s-app=calico-node --timeout=120s

期待される出力:

pod/calico-node-... condition met

この実験では後ほど PersistentVolumeClaim を使用します。デフォルトの standard StorageClass が存在することを確認し、minikube のストレージプロビジョナー Pod を待ちます。

kubectl get storageclass standard
kubectl wait --namespace kube-system --for=condition=Ready pod/storage-provisioner --timeout=120s

期待される出力例:

NAME                 PROVISIONER                RECLAIMPOLICY   VOLUMEBINDINGMODE   ...
standard (default)   k8s.io/minikube-hostpath   Delete          Immediate           ...
pod/storage-provisioner condition met

ckad-prep-volumes という名前の名前空間を作成します。

kubectl create namespace ckad-prep-volumes

この名前空間を現在のコンテキストの名前空間として設定します。

kubectl config set-context --current --namespace=ckad-prep-volumes

現在の名前空間を確認します。

kubectl config view --minify --output 'jsonpath={..namespace}'; echo

期待される出力:

ckad-prep-volumes

Pod ローカルのスクラッチデータに emptyDir を使用する

このステップでは、emptyDir ボリュームを使用する Pod を作成します。

emptyDir ボリュームは、Pod が作成されると空の状態で開始されます。同じ Pod 内のコンテナは、これを共有のスクラッチ領域、キャッシュ領域、または一時的な作業ディレクトリとして使用できます。これは、Pod が削除された後にデータを保持することを目的としたものではありません。

emptydir-pod.yaml を作成します。

cat > emptydir-pod.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
  name: scratch-worker
  labels:
    app: scratch-worker
spec:
  terminationGracePeriodSeconds: 0
  volumes:
  - name: scratch-space
    emptyDir: {}
  containers:
  - name: worker
    image: busybox:1.36
    command:
    - /bin/sh
    - -c
    - 'echo scratch-ready > /scratch/status.txt; sleep 3600'
    volumeMounts:
    - name: scratch-space
      mountPath: /scratch
EOF

マニフェストを適用します。

kubectl apply -f emptydir-pod.yaml

期待される出力:

pod/scratch-worker created

Pod が Ready になるまで待ちます。

kubectl wait --for=condition=Ready pod/scratch-worker --timeout=120s

期待される出力:

pod/scratch-worker condition met

マウントされた emptyDir ボリュームからファイルを読み取ります。

kubectl exec scratch-worker -c worker -- cat /scratch/status.txt

期待される出力:

scratch-ready

Pod のボリュームタイプを調べます。jsonpath 式でボリューム名を出力し、それが emptyDir であることを確認します。

kubectl get pod scratch-worker -o 'jsonpath={.spec.volumes[0].name}{" emptyDir\n"}'

期待される出力:

scratch-space emptyDir

PersistentVolumeClaim にデータを書き込む

このステップでは、PersistentVolumeClaim (PVC) を作成し、それをライター Pod にマウントします。

PersistentVolumeClaim (PVC) は、アプリケーションによるストレージの要求です。この実験では、standard StorageClass が要求に対して動的にストレージを提供します。Pod はこの要求を /data にマウントし、そこにファイルを書き込みます。

notes-pvc.yaml を作成します。

cat > notes-pvc.yaml <<'EOF'
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: notes-pvc
spec:
  accessModes:
  - ReadWriteOnce
  storageClassName: standard
  resources:
    requests:
      storage: 1Mi
EOF

PVC を適用します。

kubectl apply -f notes-pvc.yaml

期待される出力:

persistentvolumeclaim/notes-pvc created

PVC が Bound になるまで待ちます。

kubectl wait --for=jsonpath='{.status.phase}'=Bound pvc/notes-pvc --timeout=120s

期待される出力:

persistentvolumeclaim/notes-pvc condition met

PVC をマウントするライター Pod を作成します。

cat > pvc-writer-pod.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
  name: pvc-writer
  labels:
    app: pvc-writer
spec:
  terminationGracePeriodSeconds: 0
  volumes:
  - name: notes-storage
    persistentVolumeClaim:
      claimName: notes-pvc
  containers:
  - name: writer
    image: busybox:1.36
    command:
    - /bin/sh
    - -c
    - 'echo persistent-note > /data/note.txt; sleep 3600'
    volumeMounts:
    - name: notes-storage
      mountPath: /data
EOF

ライター Pod を適用し、Ready になるまで待ちます。

kubectl apply -f pvc-writer-pod.yaml
kubectl wait --for=condition=Ready pod/pvc-writer --timeout=120s

期待される出力:

pod/pvc-writer created
pod/pvc-writer condition met

PVC マウントからファイルを読み取ります。

kubectl exec pvc-writer -c writer -- cat /data/note.txt

期待される出力:

persistent-note

新しい Pod から PVC を再利用する

このステップでは、ライター Pod を削除し、同じ PVC をマウントする新しいリーダー Pod を作成して、ファイルがまだ存在することを確認します。

これが、Pod ローカルのスクラッチデータと永続ストレージの実践的な違いです。ライター Pod は削除できますが、PVC は残ります。新しい Pod は同じ要求をマウントしてデータを読み取ることができます。

ライター Pod を削除します。

kubectl delete pod pvc-writer

期待される出力:

pod "pvc-writer" deleted

同じ PVC をマウントするリーダー Pod を作成します。

cat > pvc-reader-pod.yaml <<'EOF'
apiVersion: v1
kind: Pod
metadata:
  name: pvc-reader
  labels:
    app: pvc-reader
spec:
  terminationGracePeriodSeconds: 0
  volumes:
  - name: notes-storage
    persistentVolumeClaim:
      claimName: notes-pvc
  containers:
  - name: reader
    image: busybox:1.36
    command:
    - /bin/sh
    - -c
    - 'cat /data/note.txt; sleep 3600'
    volumeMounts:
    - name: notes-storage
      mountPath: /data
EOF

リーダー Pod を適用し、Ready になるまで待ちます。

kubectl apply -f pvc-reader-pod.yaml
kubectl wait --for=condition=Ready pod/pvc-reader --timeout=120s

期待される出力:

pod/pvc-reader created
pod/pvc-reader condition met

新しい Pod からファイルを読み取ります。

kubectl exec pvc-reader -c reader -- cat /data/note.txt

期待される出力:

persistent-note

PVC を調べます。元のライター Pod がなくなっても、依然として Bound 状態であるはずです。

kubectl get pvc notes-pvc

期待される出力例:

NAME        STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
notes-pvc   Bound    ...      1Mi        RWO            standard       <unset>                 ...

まとめ

Pod ローカルのスクラッチデータ用に emptyDir ボリュームを使用し、永続ストレージ用に PVC を作成しました。ある Pod を通じてデータを書き込み、その Pod を削除した後、同じ要求をマウントした新しい Pod から同じデータを読み取りました。これで、一時的な Pod データにはエフェメラルストレージを使用し、Pod の置き換え後も保持すべきデータには永続ストレージを要求すべきタイミングを理解できたはずです。