PodにPersistentVolmueをマウントしたいとき、特にオンプレのKubernetesで、都合のいいNFSサーバーがなかったりすると、ノード上のローカルのファイルシステムをマウントしたいことがあります。その場合hostPath
が使えますが、local
というのもあります。違いがよくわからなかったので調べたメモです。
VolumeとPersistentVolume
わかりにくいですが、VolumeとPersistentVolumeは別です。VolumeとしてのhostPath
と、PersistentVolumeとしてのhostPath
があります。
local
については、その説明がVolumeページにあるので混乱しますが、VolumeではなくPersistentVolumeです。以下のAPIドキュメントを確認すると、local
というPesistentVolumeはありますが、local
というVolumeはないことが確認できます。
hostPath(Volume)
hostPath
のVolumeをPodのSpecに直接定義してコンテナにマウントできます。
kind: Pod
apiVersion: v1
metadata:
name: mypod
spec:
containers:
- name: liberty
image: websphere-liberty:18.0.0.4-kernel
volumeMounts:
- mountPath: /logs
name: my-volume
volumes:
- name: my-volume
hostPath:
path: /data
単純なPodではなくDeployment等から管理されるPodの場合、PodのSpecは基本的には同じになるので、上記のようなPodTemplateを書いたとすると、各Podはスケジュールされたノードの/data
をマウントします。PodはnodeSelector等で指定していなければどのノードで稼働するかわかりません。また、1つのノードで複数のPodが稼働すると、同じhostPath
をマウントしてしまいます。このためhostPath
のVolumeをマウントしても問題がない状況はかなり限定されます。
hostPath
のVolumeと相性がよいのは、各ノードで1つのみPodが稼働することが保証されるDaemonSetの場合です。IBM Cloud Privateの実装をみても、DaemonSetとして稼働しているコンテナからhostPath
のVolumeをマウントしているケースが多くあります。
(補足)
以下のPersistentVolumeの場合も同様ですが、ノード上の/data
ディレクトリーには適切な権限が必要です。上記のLibertyコンテナの場合は1001
のUIDで起動するのでchown 1001:0 /data
してあげる必要があります。
hostPath(PersistentVolume)
PersistentVolumeとしてhostPath
はAPIドキュメントに以下のように記載されており、シングルノード環境でのテスト用としてのみ使うように記載されています。VolumeとしてのhostPath
のAPIドキュメントにはこのような記載はありません。
This is useful for single-node development and testing only! On-host storage is not supported in any way and WILL NOT WORK in a multi-node cluster.
以下のようにhostPath
のPersistentVolumeを定義できます。
kind: PersistentVolume
apiVersion: v1
metadata:
name: my-pv-hostpath
spec:
storageClassName: manual
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
hostPath:
path: /data
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
コンテナからはPersistentVolumeClaimをマウントします。
kind: Pod
apiVersion: v1
metadata:
name: mypod
spec:
containers:
- name: liberty
image: websphere-liberty:18.0.0.4-kernel
volumeMounts:
- mountPath: /logs
name: my-volume
volumes:
- name: my-volume
persistentVolumeClaim:
claimName: my-pvc
単純なPodではなくDeployment/DaemonSetから管理されるPodの場合、全てのPodのSpecは基本的には同じになるので、上記のようなPodTemplateを書いたとすると、各Podが同じPersistentVolumeClaimをマウントしようとしてしまいます。しかしhostPath
はReadOnlyMany
やReadWriteMany
をサポートしていないため問題がありそうです(同じノード上で稼働する複数のPodからマウントするのもOKかもしれません)。このためDeploymentの場合はレプリカ数1でしか使えません。StatufulSetの場合はPersistentVolumeClaimTemplateを使ってPod毎に異なるPersistentVolumeClaimを定義できるので、各Podに異なるPersistentVolumeをアサインできます。
local
local
はVolumeではなくPersistentVolumeです。hostPath
との違いはなんでしょうか。ドキュメントによると、hostPath
と比べると、Node Affinityを使ってボリュームが実際に存在するノードを指定できるので、Podを手動でスケジュールする必要がないことが書かれています。
Compared to hostPath volumes, local volumes can be used in a durable and portable manner without manually scheduling Pods to nodes, as the system is aware of the volume’s node constraints by looking at the node affinity on the PersistentVolume.
試してみたところ、PersistentVolumeであればlocal
だけでなくhostPath
でもnfs
でもNode Affinityは設定でき機能したので、上記の"Compared to hostPath volumes"という部分は、PersistentVolumeのhostPath
ではなくVolumeのhostPath
を指しているように思われます。
local
の場合はNode Affintyの設定が必要です。設定していないと下記のように怒られます。
$ kubectl apply -f pv-local-test.yaml
The PersistentVolume "my-pv-local-test" is invalid: metadata.annotations: Required value: Local volume requires node affinity
$
ただし、Node Affinityで例えば以下のように全てのノードにマッチするような表現を書くことも可能です。
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: Exists
機能的にはNode Affinityの設定が必須であるくらいしか差異はなさそうですが、PersistentVolumeのhostPath
はマルチノードがサポートされていないことが明確に書かれています。local
のほうはv1.10からのBetaフィーチャーですが、以下のドキュメントに書かれているように、hostPath
が持つ課題を解決するための新しい機能であり、精力的に開発がされているようなので、基本的にはこちらを使うべきと思います。
IBM Cloud Privateでの実装をみてみると、ローカルにデータを持つためにStatefulSetとして稼働しているコンテナからPersistentVolumeマウントする場合は、local
のPersistentVolumeをマウントしています。
local
のPersistentVolumeは以下のように使います。
kind: PersistentVolume
apiVersion: v1
metadata:
name: my-pv-local
spec:
storageClassName: manual
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
local:
path: /data
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- node1
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
kind: Pod
apiVersion: v1
metadata:
name: mypod
spec:
containers:
- name: liberty
image: websphere-liberty:18.0.0.4-kernel
volumeMounts:
- mountPath: /logs
name: my-volume
volumes:
- name: my-volume
persistentVolumeClaim:
claimName: my-pvc
単純なPodではない場合、PersistentVolumeのhostPath
の場合と同じく、レプリカ数1のDeploymentか、StatufulSetから使用する必要があります。
まとめ
PersistentVolumeとしてのhostPath
とlocal
には明確な機能的な違いはなさそうですが、local
はBetaフィーチャー(追記:1.14でGAとなりました)である一方、hostPath
はマルチノード環境ではサポートされていないことが書かれています。利用方法についてまとめると以下です。
リソースタイプ | ボリュームタイプ | VolumeNodeAffinity | 主な利用方法 |
---|---|---|---|
Volume | hostPath | N/A | DaemonSetを構成するPodから使う |
PersistentVolume | hostPath | 設定可能 | シングルノード環境でテスト目的でのみ使う |
PersistentVolume | local | 設定必須 | StatefulSetを構成するPodから使う |