こんにちは。
株式会社クラスアクト インフラストラクチャ事業部の大塚です。
前回、docker上でvolumeの作成やそれをコンテナにマウントする方法を学び、実際に試してみました。
以下がその内容です。
今回はKubernetes上で上記と同じようなことをやっていきたいと思います。
KubernetesはマルチノードでPod(コンテナ)をデプロイしたり管理できたりするのが長所であると思いますが、いきなりマルチノードでやると頭が混乱しかねないので、いったんシングルノードのk8sクラスタでやってみて、後日マルチノードのk8sクラスタ環境で触っていければと思っています。
環境
ubuntu22.04でVMを起動。
microk8sをインストールしてKubernetes環境を作っています。
root@ansible-tower:~# kubectl get node -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
ansible-tower Ready <none> 23h v1.26.4 192.168.2.35 <none> Ubuntu 22.04.2 LTS 5.15.0-71-generic containerd://1.6.15
用語
PV
PersistentVolume (PV)はストレージクラスを使って管理者もしくは動的にプロビジョニングされるクラスターのストレージの一部です。これはNodeと同じようにクラスターリソースの一部です。PVはVolumeのようなボリュームプラグインですが、PVを使う個別のPodとは独立したライフサイクルを持っています。
PVC
PersistentVolumeClaim (PVC)はユーザーによって要求されるストレージです。これはPodと似ています。PodはNodeリソースを消費し、PVCはPVリソースを消費します。Podは特定レベルのCPUとメモリーリソースを要求することができます。クレームは特定のサイズやアクセスモード(例えば、ReadWriteOnce、ReadOnlyMany、ReadWriteManyにマウントできます。
私のイメージですが、PVで大きくストレージを作って、それをPVCで論理的に切って使うことができるようです。
イメージとしては以下となるでしょうか?
検証:spec.persistentVolumeReclaimPolicyを"Delete"でPVやPVCをデプロイして使ってみる
まずはPVを用意しいていきます。
今回用意したyamlファイルは以下となります。
apiVersion: v1
kind: PersistentVolume
metadata:
name: my-vol
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Delete
storageClassName: my-vol-class
hostPath:
path: /tmp/k8s-vol
type: DirectoryOrCreate
yamlファイルに書いていることの詳細をざっくり書きます。
コンテンツ | 意味 |
---|---|
spec.accessModes:ReadWriteOnce | 1つのNodeからR/Wでマウントすることができる。このほかにReadOnlyManyやReadWriteManyがある 参考:Kubernetes: ReadWriteOnceとReadWriteOncePodの動作検証 |
spec:persistentVolumeReclaimPolicy:Delete | PVCが削除されるとPVも削除するような挙動にする。このほかにRetainなどもある。 参考:Kubernetes: ReadWriteOnceとReadWriteOncePodの動作検証 |
spec.hostpath.path:/tmp/k8s-vol | 作成するPVをノードのどのディレクトリに作成するかを指定している。今回のyamlでは/tmp/k8s-vol配下に作ることになる。 |
spec.hostpath.type:DirectoryOrCreate | spec.hostpath.pathで指定したディレクトリが存在しない場合作成する 参考:KubernetesでHostPathを使う |
デプロイしていきます。
作成できていそうですね。
root@ansible-tower:~/yaml# kubectl create -f my-vol.yaml
persistentvolume/my-vol created
root@ansible-tower:~/yaml# kubectl get pv -o wide
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE
my-vol 5Gi RWO Delete Available my-vol-class 6s Filesystem
PVや後述するPVCに対して、podなどと同様にdescribeをすることができます。
以下がその結果になります。yamlに書いていることがこちらでも確認できますね。
root@ansible-tower:~/yaml# kubectl describe pv my-vol
Name: my-vol
Labels: <none>
Annotations: <none>
Finalizers: [kubernetes.io/pv-protection]
StorageClass: my-vol-class
Status: Available
Claim:
Reclaim Policy: Delete
Access Modes: RWO
VolumeMode: Filesystem
Capacity: 5Gi
Node Affinity: <none>
Message:
Source:
Type: HostPath (bare host directory volume)
Path: /tmp/k8s-vol
HostPathType: DirectoryOrCreate
Events: <none>
このタイミングではノードの/tmp配下には作成されていません。
root@ansible-tower:~/yaml# ls /tmp/
snap-private-tmp systemd-private-e9093ba59c54473c8be00fd9efae24cd-systemd-resolved.service-8TljcD ubuntu-advantage
systemd-private-e9093ba59c54473c8be00fd9efae24cd-ModemManager.service-YQKnnw systemd-private-e9093ba59c54473c8be00fd9efae24cd-systemd-timesyncd.service-NfUEnV
systemd-private-e9093ba59c54473c8be00fd9efae24cd-systemd-logind.service-VAqu3p systemd-private-e9093ba59c54473c8be00fd9efae24cd-upower.service-oEMHBO
PVCを作成していきます。
今回用意したyamlファイルは以下
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc01-my-vol
spec:
resources:
requests:
storage: 5Gi
accessModes:
- ReadWriteOnce
storageClassName: my-vol-class
yamlをもとにデプロイします。
PVCのStatusがBoundになっていればPVとPVCがうまく紐づいていることとなります。
root@ansible-tower:~/yaml# kubectl create -f pvc01-my-vol.yaml
persistentvolumeclaim/pvc01-my-vol created
root@ansible-tower:~/yaml# kubectl get pv,pvc -o wide
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE
persistentvolume/my-vol 5Gi RWO Delete Bound default/pvc01-my-vol my-vol-class 13s Filesystem
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE VOLUMEMODE
persistentvolumeclaim/pvc01-my-vol Bound my-vol 5Gi RWO my-vol-class 46s Filesystem
PVCもdescribeで詳細を確認してみます。
root@ansible-tower:~/yaml# kubectl describe pvc pvc01-my-vol
Name: pvc01-my-vol
Namespace: default
StorageClass: my-vol-class
Status: Bound
Volume: my-vol
Labels: <none>
Annotations: pv.kubernetes.io/bind-completed: yes
pv.kubernetes.io/bound-by-controller: yes
Finalizers: [kubernetes.io/pvc-protection]
Capacity: 5Gi
Access Modes: RWO
VolumeMode: Filesystem
Used By: <none>
かなりざっくりですがイメージです。my-volという名前のPVの中にpvc01-my-volという名前のPVCが存在しています。
PostgreSQLのpodを作成し、/var/lib/postgresql/dataにPVCをマウントしていきます。
yamlは以下を用意
apiVersion: v1
kind: Pod
metadata:
name: postgres01
spec:
containers:
- name: postgres01
image: postgres:latest
env:
- name: POSTGRES_PASSWORD
value: "postgres"
volumeMounts:
- mountPath: /var/lib/postgresql/data
name: pvc01-my-vol
volumes:
- name: pvc01-my-vol
persistentVolumeClaim:
claimName: pvc01-my-vol
podをデプロイします。
root@ansible-tower:~/yaml# kubectl create -f vol-postgresql01.yaml
pod/postgres01 created
root@ansible-tower:~/yaml# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
postgres01 1/1 Running 0 108s 10.1.108.9 ansible-tower <none> <none>
podの詳細を確認してみますが、以下の出力からマウントできていそうです。
root@ansible-tower:~/yaml# kubectl describe pod postgres01
~中略~
Volumes:
pvc01-my-vol:
Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
ClaimName: pvc01-my-vol
ReadOnly: false
このタイミングで/tmp/k8s-volが作成されます。
実際に確認したログが以下となります。/tmp配下に指定したk8s-volという名前のディレクトリが自動で作成され、その配下にはPostgreSQLのデータが確認できます。
root@ansible-tower:/# cd /tmp
root@ansible-tower:/tmp# ls
k8s-vol systemd-private-7b30335e5c3847888ee14c9d4ae96fea-ModemManager.service-9JtOcV systemd-private-7b30335e5c3847888ee14c9d4ae96fea-systemd-resolved.service-y1Y1GA
snap-private-tmp systemd-private-7b30335e5c3847888ee14c9d4ae96fea-systemd-logind.service-f83oWV systemd-private-7b30335e5c3847888ee14c9d4ae96fea-systemd-timesyncd.service-Mr4GTU
root@ansible-tower:/tmp/k8s-vol# ls
base pg_commit_ts pg_hba.conf pg_logical pg_notify pg_serial pg_stat pg_subtrans pg_twophase pg_wal postgresql.auto.conf postmaster.opts
global pg_dynshmem pg_ident.conf pg_multixact pg_replslot pg_snapshots pg_stat_tmp pg_tblspc PG_VERSION pg_xact postgresql.conf postmaster.pid
デプロイしたpodでも確認してみます。
/tmp/k8s-vol/と内容は同じですね。
root@ansible-tower:~# kubectl get pod
NAME READY STATUS RESTARTS AGE
postgres01 1/1 Running 0 7h13m
root@ansible-tower:~# kubectl exec -it postgres01 -- /bin/bash
root@postgres01:/# cd /var/lib/postgresql/data
root@postgres01:/var/lib/postgresql/data# ls
base pg_commit_ts pg_hba.conf pg_logical pg_notify pg_serial pg_stat pg_subtrans pg_twophase pg_wal postgresql.auto.conf postmaster.opts
global pg_dynshmem pg_ident.conf pg_multixact pg_replslot pg_snapshots pg_stat_tmp pg_tblspc PG_VERSION pg_xact postgresql.conf postmaster.pid
pod側からデータを作成し、ノード側でも確認できるか確かめます。
podでtext.txtという空ファイルを作成
root@postgres01:/var/lib/postgresql/data# touch test.txt
root@postgres01:/var/lib/postgresql/data# ls -ltr test.txt
-rw-r--r-- 1 root root 0 May 10 21:15 test.txt
ノード側で確認します。問題なさそうですね。
root@ansible-tower:~# cd /tmp/k8s-vol/
root@ansible-tower:/tmp/k8s-vol# ls -ltr test.txt
-rw-r--r-- 1 root root 0 May 10 21:15 test.txt
イメージに起こすと以下のようになるでしょう。
赤点線で繋がっているのがイコールだと思っていったんは問題ないかと。。。
再利用できることを確認します。
まずPVCをマウントしているpodを削除します。
root@ansible-tower:~# kubectl delete pod postgres01
root@ansible-tower:~# kubectl get pod,pv,pvc -o wide
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE
persistentvolume/my-vol 5Gi RWO Delete Bound default/pvc01-my-vol my-vol-class 7h31m Filesystem
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE VOLUMEMODE
persistentvolumeclaim/pvc01-my-vol Bound my-vol 5Gi RWO my-vol-class 7h31m Filesystem
root@ansible-tower:~# ls /tmp/k8s-vol/
base pg_commit_ts pg_hba.conf pg_logical pg_notify pg_serial pg_stat pg_subtrans pg_twophase pg_wal postgresql.auto.conf postmaster.opts test.txt
global pg_dynshmem pg_ident.conf pg_multixact pg_replslot pg_snapshots pg_stat_tmp pg_tblspc PG_VERSION pg_xact postgresql.conf postmaster.pid
同じymalを使って再度podをデプロイ
root@ansible-tower:~/yaml# kubectl get pod,pv,pvc -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/postgres01 1/1 Running 0 21s 10.1.108.10 ansible-tower <none> <none>
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE
persistentvolume/my-vol 5Gi RWO Delete Bound default/pvc01-my-vol my-vol-class 7h33m Filesystem
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE VOLUMEMODE
persistentvolumeclaim/pvc01-my-vol Bound my-vol 5Gi RWO my-vol-class 7h33m Filesystem
再デプロイしたpodの/var/lib/postgresql/data配下を確認し、text.txtがあることを確認します。
下記ログから再利用できることがわかりました。
root@ansible-tower:~/yaml# kubectl exec -it postgres01 -- /bin/bash
root@postgres01:/# cd /var/lib/postgresql/data/
root@postgres01:/var/lib/postgresql/data# ls
base pg_commit_ts pg_hba.conf pg_logical pg_notify pg_serial pg_stat pg_subtrans pg_twophase pg_wal postgresql.auto.conf postmaster.opts test.txt
global pg_dynshmem pg_ident.conf pg_multixact pg_replslot pg_snapshots pg_stat_tmp pg_tblspc PG_VERSION pg_xact postgresql.conf postmaster.pid
podとPVCを削除します。PV作成時にDeleteを指定していることからPVC削除と同時にPVが削除されるはず。。。
getで何も出力されないことからPVC削除と同時にPVも削除されていると確認できます。
root@ansible-tower:~# kubectl delete pod postgres0
persistentvolumeclaim "pvc01-my-vol" deleted
root@ansible-tower:~# kubectl get pod,pv,pvc
No resources found
/tmp配下も削除されています。
root@ansible-tower:~# cd /tmp
root@ansible-tower:/tmp# ls
snap-private-tmp systemd-private-7b30335e5c3847888ee14c9d4ae96fea-systemd-resolved.service-y1Y1GA
systemd-private-7b30335e5c3847888ee14c9d4ae96fea-fwupd.service-Srke4w systemd-private-7b30335e5c3847888ee14c9d4ae96fea-systemd-timesyncd.service-Mr4GTU
systemd-private-7b30335e5c3847888ee14c9d4ae96fea-ModemManager.service-9JtOcV systemd-private-7b30335e5c3847888ee14c9d4ae96fea-upower.service-LLEENP
systemd-private-7b30335e5c3847888ee14c9d4ae96fea-systemd-logind.service-f83oWV
検証:spec.persistentVolumeReclaimPolicyを"Retain"でPVやPVCをデプロイして使ってみる
PVのyamlは以下
apiVersion: v1
kind: PersistentVolume
metadata:
name: my-vol-retain
spec:
capacity:
storage: 5Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: my-vol-retain-class
hostPath:
path: /tmp/my-vol-retain
type: DirectoryOrCreate
デプロイします
root@ansible-tower:~/yaml# kubectl create -f my-vol-retain.yaml
persistentvolume/my-vol-retain created
root@ansible-tower:~/yaml# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
my-vol-retain 5Gi RWO Retain Available my-vol-retain-class 6s
PVCのyamlは以下
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc01-my-vol-retain
spec:
resources:
requests:
storage: 5Gi
accessModes:
- ReadWriteOnce
storageClassName: my-vol-retain-class
デプロイします
root@ansible-tower:~/yaml# kubectl create -f pvc01-my-vol-retain.yaml
persistentvolumeclaim/pvc01-my-vol-retain created
root@ansible-tower:~/yaml# kubectl get pv,pvc -o wide
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE
persistentvolume/my-vol-retain 5Gi RWO Retain Bound default/pvc01-my-vol-retain my-vol-retain-class 68s Filesystem
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE VOLUMEMODE
persistentvolumeclaim/pvc01-my-vol-retain Bound my-vol-retain 5Gi RWO my-vol-retain-class 10s Filesystem
podのyamlは以下
apiVersion: v1
kind: Pod
metadata:
name: postgres01
spec:
containers:
- name: postgres01
image: postgres:latest
env:
- name: POSTGRES_PASSWORD
value: "postgres"
volumeMounts:
- mountPath: /var/lib/postgresql/data
name: pvc01-my-vol-retain
volumes:
- name: pvc01-my-vol-retain
persistentVolumeClaim:
claimName: pvc01-my-vol-retain
デプロイします
root@ansible-tower:~/yaml# kubectl create -f vol-retain-postgresql01.yaml
pod/postgres01 created
root@ansible-tower:~/yaml# kubectl get pod,pv,pvc -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/postgres01 1/1 Running 0 24s 10.1.108.11 ansible-tower <none> <none>
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE
persistentvolume/my-vol-retain 5Gi RWO Retain Bound default/pvc01-my-vol-retain my-vol-retain-class 5m12s Filesystem
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE VOLUMEMODE
persistentvolumeclaim/pvc01-my-vol-retain Bound my-vol-retain 5Gi RWO my-vol-retain-class 4m14s Filesystem
podの中に入ってtest.txtを/var/lib/postgresql/data配下に作成します。
root@ansible-tower:~/yaml# kubectl exec -it postgres01 -- /bin/bash
root@postgres01:/# cd /var/lib/postgresql/data/
root@postgres01:/var/lib/postgresql/data# touch test.txt
root@postgres01:/var/lib/postgresql/data# ls
base pg_commit_ts pg_hba.conf pg_logical pg_notify pg_serial pg_stat pg_subtrans pg_twophase pg_wal postgresql.auto.conf postmaster.opts test.txt
global pg_dynshmem pg_ident.conf pg_multixact pg_replslot pg_snapshots pg_stat_tmp pg_tblspc PG_VERSION pg_xact postgresql.conf postmaster.pid
ホストの/tmp/my-vol-retainにデータがあることを確認します。
root@ansible-tower:~# cd /tmp/my-vol-retain/
root@ansible-tower:/tmp/my-vol-retain# ls
base pg_commit_ts pg_hba.conf pg_logical pg_notify pg_serial pg_stat pg_subtrans pg_twophase pg_wal postgresql.auto.conf postmaster.opts test.txt
global pg_dynshmem pg_ident.conf pg_multixact pg_replslot pg_snapshots pg_stat_tmp pg_tblspc PG_VERSION pg_xact postgresql.conf postmaster.pid
podやPVCを削除しても自動で削除されないことを確認します。
root@ansible-tower:~/yaml# kubectl get pod,pv,pvc -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod/postgres01 1/1 Running 0 3m22s 10.1.108.11 ansible-tower <none> <none>
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE
persistentvolume/my-vol-retain 5Gi RWO Retain Bound default/pvc01-my-vol-retain my-vol-retain-class 8m10s Filesystem
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE VOLUMEMODE
persistentvolumeclaim/pvc01-my-vol-retain Bound my-vol-retain 5Gi RWO my-vol-retain-class 7m12s Filesystem
root@ansible-tower:~/yaml# kubectl delete pod postgres01
pod "postgres01" deleted
root@ansible-tower:~/yaml# kubectl delete pvc pvc01-my-vol-retain
PVが残っており、ホストからもデータが残っていることが確認ができますね。
root@ansible-tower:~/yaml# kubectl get pod,pv,pvc -o wide
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE VOLUMEMODE
persistentvolume/my-vol-retain 5Gi RWO Retain Released default/pvc01-my-vol-retain my-vol-retain-class 25m Filesystem
root@ansible-tower:~/yaml# cd /tmp/my-vol-retain/
root@ansible-tower:/tmp/my-vol-retain# ls
base pg_commit_ts pg_hba.conf pg_logical pg_notify pg_serial pg_stat pg_subtrans pg_twophase pg_wal postgresql.auto.conf postmaster.opts test.txt
global pg_dynshmem pg_ident.conf pg_multixact pg_replslot pg_snapshots pg_stat_tmp pg_tblspc PG_VERSION pg_xact postgresql.conf postmaster.pid
これを再利用するには少し手間が必要なのかも?です。
1.PersistentVolumeを削除します。PVが削除された後も、外部インフラストラクチャー(AWS EBS、GCE PD、Azure Disk、Cinderボリュームなど)に関連付けられたストレージアセットは依然として残ります。
2.ストレージアセットに関連するのデータを手動で適切にクリーンアップします。
3.関連するストレージアセットを手動で削除するか、同じストレージアセットを再利用したい場合、新しいストレージアセット定義と共にPersistentVolumeを作成します。