はじめに
コンテナには書き込み可能なファイルシステムがありますが、そのストレージはコンテナに紐付いています。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 の置き換え後も保持すべきデータには永続ストレージを要求すべきタイミングを理解できたはずです。


