emptyDir と hostPath の違い

v1.37 時点(2026年10月26日 確認)

Kubernetes 基本仕様第26回 / 全45回 ・ 第5部 ストレージ
目次

この記事では、Pod の中のコンテナがファイルを読み書きできるディレクトリである ボリューム の仕組みと、その種類のうち emptyDir と hostPath の違いを、図で説明します。コンテナの中に書いたファイルがいつ消えるのか、emptyDir と hostPath のデータはどこに置かれ、Pod を作り直すとどうなるのかがわかります。後半では kind のクラスタで、コンテナのファイルシステム、emptyDir、hostPath の 3 か所にファイルを書いてから Pod を作り直し、消えるデータと残るデータを比べる手順を示します。

この回から第5部(ストレージ)に入ります。Pod の中のコンテナがネットワークとストレージを共有することを扱った第8回の内容を前提にしています。まだの方は先にこちらをどうぞ。

基本仕様 ・ 第8回 Pod を動かして理解するKubernetes で作って管理できる最小の単位である Pod の仕組みを図で説明します。Pod とコンテナの関係、Pod の中のコンテナが共有するもの、Pod が 1 つのノードに置かれて移らないことを押さえ、kind のクラスタで Pod を直接作って削除し、もう戻らないことを確かめる手順を紹介します。

以下の図は、後半の「手元で試す」で作る Pod と、その Pod が使う 2 つのボリュームが、Pod とどう結び付いているかを表しています。

Pod の中にある emptyDir と、Pod の外にあるノードのディレクトリをマウントする hostPath

図では emptyDir を Pod の枠の中に、hostPath のディレクトリを Pod の枠の外に描いています。emptyDir は Pod のために作られる、最初は空のディレクトリで、Pod がノードから消えると中のデータも消えます。hostPath はノードのファイルシステムにあるファイルやディレクトリを、Pod にマウントします。どちらもコンテナから決まったパスで読み書きしますが、いつまで存在するかが違います。ノードのディレクトリへの線は Pod の枠から引いていますが、読み書きするのはコンテナです。/container.txt はボリュームではなく、コンテナ自身のファイルシステムに書いたファイルです。

参考:Volumes | Kubernetes、Volumes | Kubernetes、Ephemeral Volumes | Kubernetes

ボリュームとは

ボリューム(Volume)は Pod の中のコンテナから使える、データが入っていることもあるディレクトリ です。公式ドキュメントによると、そのディレクトリがどのように用意されるか、何の上に置かれるか、中身が何かは、ボリュームの種類で決まります。たとえば第17回の configMap のボリュームには最初から ConfigMap のデータが入っていて、第10回の emptyDir のボリュームは空から始まります。Kubernetes は多くの種類のボリュームを扱え、1 つの Pod でいくつの種類のボリュームでも同時に使えます。

参考:Volumes | Kubernetes

公式ドキュメントはボリュームの使い道をいくつか挙げています。そのうち、このシリーズにかかわる主なものは次の 5 つです。

  • ConfigMap や Secret をもとに、設定ファイルを用意する
  • Pod に一時的な作業場所を用意する
  • 同じ Pod の 2 つのコンテナで、ファイルシステムを共有する
  • Pod が再起動したり置き換えられたりしても使えるように、データを長く保存する
  • コンテナが動く Pod の情報をもとに、アプリケーションに設定を渡す

参考:Volumes | Kubernetes

ボリュームの種類には一時的なもの(ephemeral)と永続的なもの(persistent)があります。公式ドキュメントによると、一時的なボリュームの種類は特定の Pod と結び付いた期間だけ存在し、Pod が存在しなくなると、Kubernetes が消します。永続的なボリュームは個々の Pod の期間を超えて存在し、Kubernetes は消しません。どちらでも、同じ Pod の中では、コンテナが再起動してもデータは残ります。永続的なボリュームは第27回で扱います。

参考:Volumes | Kubernetes

これまでの回のマニフェストに書いたボリュームは、どれも一時的なボリュームです。公式ドキュメントが挙げる一時的なボリュームの種類のうち、このシリーズで扱うものを次の表にまとめます。

種類公式ドキュメントの説明扱った回
emptyDirPod の起動時には空。ストレージは kubelet の基準のディレクトリ(ふつうはルートディスク)か RAM から用意される第10回、この回
configMapConfigMap のデータを Pod に入れる第17回
secretSecret のデータを Pod に入れる第18回
downwardAPIPod とコンテナのフィールドの値を Pod に入れる第19回

参考:Ephemeral Volumes | Kubernetes

公式ドキュメントによると、この 4 つはノードのローカルの一時的なストレージ(local ephemeral storage)として用意され、各ノードの kubelet(第4回)が管理します。ローカルの一時的なストレージは、ノードに直接つながった書き込める記憶装置か、場合によっては RAM が支える、ノードの記憶領域です。ここでの「一時的」は長く残る保証がない(no long-term guarantee about durability)という意味です。「ローカル」はノードに直接つながった(locally-attached)記憶装置を指していると読めます。RAM が支える場合もあるので、ディスクとは限りません。第18回で見た Secret のボリュームは RAM の上に置かれますが、これも RAM が支える場合にあたると読めます。

参考:Ephemeral Volumes | Kubernetes、Local ephemeral storage | Kubernetes

一時的なボリュームにはほかにも、コンテナイメージの中身をマウントする image、CSI のドライバーが用意するもの、永続的なボリュームに対応したストレージのドライバーが用意する generic ephemeral volumes などがあります。CSI は第18回で触れたとおり、外部のストレージを Kubernetes につなぐための共通の仕組みです。この回で扱う hostPath はこの一時的なボリュームの一覧には入っていません。

参考:Ephemeral Volumes | Kubernetes

第19回で触れた projected は、公式ドキュメントによると、すでにあるいくつかのボリュームの中身を、同じ 1 つのディレクトリにまとめるボリュームです。第19回で見たとおり、secret、downwardAPI、configMap などをまとめられます。

参考:Volumes | Kubernetes、Projected Volumes | Kubernetes

なぜボリュームが必要なのか

コンテナの中に書いたファイルは、コンテナと同じ期間しか存在しません。公式ドキュメントによると、コンテナのディスクの上のファイルは一時的なもの(ephemeral)です。コンテナが異常終了したり止められたりすると、コンテナの状態は保存されず、コンテナが動いていたあいだに作ったり変えたりしたファイルはすべて失われます。異常終了のあと、kubelet はコンテナをまっさらな状態(clean state)で再起動します。第9回で見たコンテナの再起動では、コンテナの中に書いたファイルは残らないということです。

参考:Volumes | Kubernetes

公式ドキュメントのボリュームの使い方のページも、コンテナのファイルシステムはコンテナが存在するあいだだけ存在し、コンテナが終了して再起動すると、ファイルシステムへの変更は失われる、と説明しています。コンテナから独立した、より一貫したストレージにはボリュームを使えます。これは Redis のようなキーと値を保存するソフトウェアや、データベースのような、状態を持つアプリケーションで特に重要だと書かれています。

参考:Configure a Pod to Use a Volume for Storage | Kubernetes

公式ドキュメントはもう 1 つの問題として、1 つの Pod で動く複数のコンテナがファイルを共有したい場合を挙げています。すべてのコンテナから使える共有のファイルシステムを用意するのは、難しいことがあります。第10回では、init コンテナが書いたファイルを nginx のコンテナが読むために、emptyDir のボリュームを使いました。公式ドキュメントによると、ボリュームという仕組みはこの 2 つの問題を解く助けになります。

参考:Volumes | Kubernetes

ボリュームの仕組み

マニフェストに書く場所

第10回で見たとおり、ボリュームを使うには、Pod に用意するボリュームを .spec.volumes に書き、コンテナのどこにマウントするかを .spec.containers[*].volumeMounts に書きます。マウントはボリュームのディレクトリをコンテナの中の決まったパスから見えるようにすることです。この回で使うフィールドを、v1.37 時点の API リファレンスに沿って次の表にまとめます。

フィールド内容
spec.volumes[*].nameボリュームの名前。DNS ラベルの決まり(第8回)で付け、Pod の中で一意にする
spec.volumes[*].emptyDirPod と同じ期間だけ存在する、一時的なディレクトリ
spec.volumes[*].hostPathホストのマシンにすでにあるファイルやディレクトリを、コンテナに直接見せる
spec.containers[*].volumeMounts[*].nameマウントするボリュームの名前。spec.volumes[*].name と合わせる
spec.containers[*].volumeMounts[*].mountPathコンテナの中で、ボリュームをマウントするパス
spec.containers[*].volumeMounts[*].readOnlytrue なら読み取り専用でマウントする。既定は false(読み書きできる)

参考:Pod | Kubernetes API Reference、Pod | Kubernetes API Reference、Volumes | Kubernetes

公式ドキュメントによると、Pod が起動すると、コンテナの中のプロセスからは、コンテナイメージの最初の中身に、マウントしたボリュームを加えたファイルシステムが見えます。ボリュームはコンテナのファイルシステムの中の、指定したパスにマウントされます。マウントする場所はボリュームを使うコンテナごとに別々に指定する必要があります。

参考:Volumes | Kubernetes

emptyDir

公式ドキュメントによると、emptyDir のボリュームは、Pod がノードに割り当てられたときに作られます。名前のとおり、最初は空です。Pod のすべてのコンテナが emptyDir の同じファイルを読み書きできます。マウントするパスはコンテナごとに同じでも違っていても構いません。Pod がどんな理由でノードから消えても、emptyDir のデータは完全に消えます。一方で、コンテナが異常終了しても Pod はノードから消えないので、emptyDir のデータは残ります。第10回で見たとおりです。

参考:Volumes | Kubernetes

API リファレンスも emptyDir を、Pod と同じ期間(a pod’s lifetime)だけ存在する一時的なディレクトリと説明しています。「Pod と同じ期間」の意味は Pod のライフサイクルのページに書かれています。Pod と同じ期間存在するもの(ボリュームなど)は、その UID の Pod が存在するあいだだけ存在します。その Pod がどんな理由で削除されても、たとえまったく同じ代わりの Pod が作られても、ボリュームも消され、新しく作り直されます。第8回で見たとおり、同じ名前で作り直した Pod も UID が違う別の Pod なので、emptyDir も新しい空のディレクトリになります。

参考:Pod | Kubernetes API Reference、Pod Lifecycle | Kubernetes

公式ドキュメントが挙げる emptyDir の使い道は、次の 3 つです。

  • ディスクを使うマージソート(データの並べ替えの方法の 1 つ)のような処理の作業場所
  • 長い計算の途中経過を保存して、異常終了から立ち直れるようにする
  • 中身を取ってくるコンテナが取ってきたファイルを、Web サーバーのコンテナが配信する

参考:Volumes | Kubernetes

3 つ目は第10回の、init コンテナがファイルを書き、nginx がそれを配信する Pod と同じ形です。

emptyDir には置き場所と大きさの上限を指定できます。v1.37 時点の API リファレンスに沿って、emptyDir に書けるフィールドを次の表にまとめます。

フィールド内容
mediumディレクトリを置く記憶装置の種類。既定は "" で、ノードの既定の記憶装置を使う。"" か Memory のどちらかにする
sizeLimitこのボリュームに必要なローカルのストレージの合計(容量の上限として働く)。Memory のときにも当てはまる。既定は書かない状態(nil)で、上限は決まっていない
modeディレクトリの権限(Unix のパーミッションのビット)。v1.37 時点ではアルファの機能で、既定では無効。機能ゲート EmptyDirVolumeMode を有効にしたときだけ使える

参考:Pod | Kubernetes API Reference、Volumes | Kubernetes

公式ドキュメントによると、既定では、emptyDir はノードを支える記憶装置に置かれます。それがディスクなのか、SSD なのか、ネットワークのストレージなのかは、環境によって違います。ボリュームの種類のページの別の節には、emptyDir の記憶装置は kubelet のルートディレクトリ(ふつうは /var/lib/kubelet)があるファイルシステムの記憶装置で決まる、と書かれています。一時的なボリュームの種類をまとめた表の「kubelet の基準のディレクトリ(ふつうはルートディスク)」も、言い方は違いますが同じものを指していると読めます。

参考:Volumes | Kubernetes、Volumes | Kubernetes

既定の記憶装置のときは、sizeLimit で emptyDir の容量を制限できます。公式ドキュメントによると、この容量はノードのローカルの一時的なストレージから割り当てられます。そのストレージがほかの用途(ログのファイルや、イメージのデータなど)で埋まると、emptyDir は sizeLimit に届く前に容量が尽きることがあります。

参考:Volumes | Kubernetes、Local ephemeral storage | Kubernetes

medium を Memory にすると、Kubernetes はディスクではなく tmpfs をマウントします。tmpfs は第18回の Secret のボリュームでも使われていた、RAM(メモリー)の上に置くファイルシステムです。公式ドキュメントによると、tmpfs はとても速い一方で、ディスクとは違い、書いたファイルはそのファイルを書いたコンテナのメモリーの上限(limits)に数えられます。API リファレンスによると、メモリーの上の emptyDir が使える最大の量は、sizeLimit と、Pod のすべてのコンテナのメモリーの上限の合計の、小さいほうです。メモリーの上限(limits)の詳しい仕組みは第29回で扱います。この回では、メモリーの上の emptyDir がノードのメモリーを使うことと、sizeLimit を書かないとメモリーを使いすぎるおそれがあると公式ドキュメントが注意していることを押さえておけば十分です。後者は例の後で見ます。

参考:Volumes | Kubernetes、Pod | Kubernetes API Reference

以下は公式ドキュメントにある、メモリーの上に置く emptyDir の例です。sizeLimit で上限を 500 MiB にしています。

yaml
apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: registry.k8s.io/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir:
      sizeLimit: 500Mi
      medium: Memory

参考:Volumes | Kubernetes

sizeLimit を書かなかったときについて、公式ドキュメントは注意を促しています。ボリュームの種類のページによると、sizeLimit を書かなければ、メモリーの上の emptyDir の大きさはノードの割り当て可能なメモリーの大きさになります。割り当て可能なメモリーは、公式ドキュメントの定義では、Pod が使える計算資源の量です。ノードの資源から、Kubernetes や OS のデーモン(裏で動き続けるプログラム)のために取っておく分と、退避を始めるしきい値の分を除いたものです。ただし、リソース管理のページによると、そのボリュームが使うことがあるのは Pod のメモリーの上限までです。メモリーの上限も設定していなければ、Pod のメモリーの使用量に上限はなく、ノードの使えるメモリーをすべて使いかねません。その結果、ノードの OS がメモリー不足(OOM)の処理をすることがあります。ボリュームのファイルは Kubernetes も OS も自動では消さないので、メモリーが足りなくなっても、そのファイルが使うメモリーは取り戻せない、とも書かれています。公式ドキュメントによると、kubelet はメモリーの上の emptyDir を、ローカルの一時的なストレージではなくコンテナのメモリーの使用量として扱います。

参考:Volumes | Kubernetes、Resource Management for Pods and Containers | Kubernetes、Local ephemeral storage | Kubernetes、Reserve Compute Resources for System Daemons | Kubernetes、Reserve Compute Resources for System Daemons | Kubernetes

hostPath

公式ドキュメントによると、hostPath のボリュームは、ホストのノードのファイルシステムにあるファイルやディレクトリを Pod にマウントします。ほとんどの Pod には必要ないものの、一部のアプリケーションには強力な抜け道(escape hatch)になる、と説明されています。ここでの抜け道は Kubernetes の仕組みを通さずに、ノードのファイルに直接触れる手段のことだと読めます。API リファレンスもホストのマシンにすでにあるファイルやディレクトリを、コンテナに直接見せるものとしています。主にシステムのエージェントなど、ホストのマシンを見ることが許された、特権を持つものに使い、ほとんどのコンテナには必要ない(Most containers will NOT need this)と書かれています。特権(privileged)は一般に、ふつうのプログラムには許されない強い権限のことです。

参考:Volumes | Kubernetes、Pod | Kubernetes API Reference

hostPath は前に見た一時的なボリュームの一覧には入っていません。この回のように Pod のマニフェストに直接書く hostPath は、第27回で扱う永続的なボリュームの仕組み(PersistentVolume)を通さずに、ノードのファイルを使います。hostPath を PersistentVolume として使う方法もあり、「注意点」の最後で触れます。データはそのノードのファイルシステムにあるので、1 つのノードに縛られます。公式ドキュメントからは hostPath を一時的と永続的のどちらに分けているかは読み取れませんでした。Pod とは別にノードにあるデータなので、Pod が消えても Kubernetes が消すものではないと考えられます。

参考:Ephemeral Volumes | Kubernetes、Volumes | Kubernetes

公式ドキュメントは hostPath について警告(Warning)を載せています。hostPath のボリュームを使うことには、多くのセキュリティのリスクがあります。hostPath を使わずに済むなら、使わないようにすべきだ(you should)と書かれています。代わりの方法の例として挙がっているのは、local の PersistentVolume を定義して使うことです。PersistentVolume は第27回で扱います。

参考:Volumes | Kubernetes

同じ警告には読み取り専用のマウントについての注意もあります。Pod を受け付けるときの検証(アドミッション。第40回)で、ノードの特定のディレクトリへのアクセスを制限している場合、その制限が効くのは、その hostPath のマウントを読み取り専用にすることもあわせて求めたときだけです。信頼できない Pod に任意のホストのパスを読み書きできる形でマウントさせると、その Pod のコンテナは、読み書きできるホストのマウントを使って、その制限をくぐり抜けられるおそれがある(may be able to subvert)と書かれています。

参考:Volumes | Kubernetes

公式ドキュメントは、読み取り専用でも読み書きできる形でも、hostPath を使うときは気を付けるよう求めています。理由は次の 3 つです。

  • ホストのファイルシステムにアクセスできると、特権を持つ認証情報(kubelet のものなど)や、特権を持つ API(コンテナランタイムのソケットなど)がさらされるおそれがある。それらはコンテナの外への脱出や、クラスタのほかの部分への攻撃に使われうる
  • 同じ設定の Pod(同じひな形から作った Pod など)でも、ノードごとにファイルが違うため、ノードによって動きが変わることがある
  • hostPath の使用量は一時的なストレージの使用量として扱われない。使いすぎるとノードのディスクが逼迫するので、使用量を自分で見張る必要がある

参考:Volumes | Kubernetes

コンテナランタイムはノードの上でコンテナを動かすソフトウェア(第4回)です。ソケットは一般に、プログラムどうしがやり取りするための窓口で、ここではコンテナランタイムを操作する API の窓口を指すと考えられます。

公式ドキュメントが挙げる hostPath の使い道は、次の 2 つです。

  • ノードのレベルのシステムのコンポーネントにアクセスする必要があるコンテナを動かす(たとえば、/var/log を読み取り専用でマウントしてシステムのログを読み、1 か所に集めるコンテナ)
  • ホストにある設定ファイルを、static Pod(第4回)に読み取り専用で見せる。static Pod はふつうの Pod と違って ConfigMap を使えない

参考:Volumes | Kubernetes

1 つ目の使い道のログを集めるコンテナは、第15回の DaemonSet と組み合わせて使うことが考えられます。公式ドキュメントも DaemonSet の典型的な使い道として、各ノードでログを集めるデーモンを動かすことを挙げています。2 つ目の使い道で触れた、static Pod が ConfigMap を使えないことは第17回で見たとおりで、Secret も同じです(第18回)。

参考:DaemonSet | Kubernetes

Kubernetes 自身のコンポーネントにも hostPath を使うものがあります。kubeadm の実装の詳細のページによると、kubeadm は etcd(第4回)の static Pod のマニフェストを作るとき、etcd のデータのディレクトリ(dataDir)から、ホストのファイルシステムへの hostPath のマウントを書きます。kind はノードを kubeadm で初期化するので(第2回)、kind のクラスタの etcd の Pod にも、hostPath のボリュームがあるはずです。後半の「手元で試す」で見ます。

参考:Implementation details | Kubernetes、Configuration | kind

hostPath の type

hostPath には必須の path に加えて、type を指定できます。type はマウントする前に、そのパスに何があるべきかを決めるものです。v1.37 時点の公式ドキュメントに沿って、type の値を次の表にまとめます。

値動き
""(既定)以前との互換のための値。マウントする前に何も確かめない
DirectoryOrCreateパスに何も無ければ、空のディレクトリを必要に応じて作る。権限は 0755 で、グループと所有者は kubelet と同じ
Directoryパスにディレクトリがなければならない
FileOrCreateパスに何も無ければ、空のファイルを必要に応じて作る。権限は 0644 で、グループと所有者は kubelet と同じ
Fileパスにファイルがなければならない
Socketパスに UNIX ソケットがなければならない
CharDevice(Linux のノードだけ)パスにキャラクターデバイスがなければならない
BlockDevice(Linux のノードだけ)パスにブロックデバイスがなければならない

参考:Volumes | Kubernetes、PersistentVolume | Kubernetes API Reference

表のことばを補います。UNIX ソケットは一般に、同じマシンの中のプログラムどうしがやり取りするための、ファイルの形をした窓口です。キャラクターデバイスとブロックデバイスは一般に、ディスクなどの装置をファイルとして扱うための特別なファイルです。API リファレンスによると、path はホストの上のディレクトリのパスで、パスがシンボリックリンク(ほかのファイルを指す特別なファイル)なら、リンクをたどった先の本当のパスが使われます。

参考:PersistentVolume | Kubernetes API Reference

公式ドキュメントは FileOrCreate について、ファイルの親のディレクトリは作らない、と注意しています。親のディレクトリが無いと、Pod は起動に失敗します。このため公式ドキュメントの例では親のディレクトリを DirectoryOrCreate で、ファイルを FileOrCreate で、別々にマウントしています。その例の説明によると、ノードにパスが無ければ、kubelet がディレクトリを作ってから Pod にマウントします。

参考:Volumes | Kubernetes、Volumes | Kubernetes

ホストの上で作られたファイルやディレクトリの中には、root(管理者のユーザー)だけがアクセスできるものがあります。公式ドキュメントによると、その場合は、特権を持つコンテナの中でプロセスを root として動かすか、ホストの側でファイルの権限を変えないと、hostPath のボリュームを読み書きできません。Pod Security Standards(後述)の説明によると、特権を持つ(privileged)Pod は、ほとんどのセキュリティの仕組みを無効にします。

参考:Volumes | Kubernetes、Pod Security Standards | Kubernetes

以下は公式ドキュメントにある、Linux のノード向けの hostPath の例です。

yaml
---
# This manifest mounts /data/foo on the host as /foo inside the
# single container that runs within the hostpath-example-linux Pod.
#
# The mount into the container is read-only.
apiVersion: v1
kind: Pod
metadata:
  name: hostpath-example-linux
spec:
  os: { name: linux }
  nodeSelector:
    kubernetes.io/os: linux
  containers:
  - name: example-container
    image: registry.k8s.io/test-webserver
    volumeMounts:
    - mountPath: /foo
      name: example-volume
      readOnly: true
  volumes:
  - name: example-volume
    # mount /data/foo, but only if that directory already exists
    hostPath:
      path: /data/foo # directory location on host
      type: Directory # this field is optional

参考:Volumes | Kubernetes

冒頭のコメントのとおり、ホストの /data/foo を、コンテナの中の /foo に読み取り専用(readOnly: true)でマウントする例です。type: Directory なので、/data/foo がすでにディレクトリとしてある場合だけマウントします。公式ドキュメントは同じ例の Windows のノード向けの版も載せていて、os と nodeSelector は、この Pod を Linux のノードで動かすための指定だと読めます。nodeSelector は第31回で扱います。

参考:Volumes | Kubernetes

hostPath は第39回で扱う Pod Security Standards(Pod の設定の安全さの基準)でも制限されています。3 つの水準のうち、知られている権限の昇格を防ぐ Baseline の水準では、hostPath のボリュームは禁止です(spec.volumes[*].hostPath は書かない状態でなければならない)。権限の昇格(privilege escalation)は一般に、本来与えられた以上の権限を手に入れることです。

参考:Pod Security Standards | Kubernetes

kind のクラスタでの「ホスト」

kind のクラスタでは「ホスト」という言葉が 2 つの意味で出てくるので、先に整理します。後半の手順では次の 3 つの層を区別します。

層何か手順で出てくるもの
手元のマシンkind と Docker を動かしているパソコン手元のマシンのディレクトリを直接見る ls /var/local/volume-demo
ノード(kind-control-plane のコンテナ)手元のマシンの Docker で動くコンテナ。hostPath の「ホスト」はここノードの /var/local/volume-demo(docker exec kind-control-plane で見る)
Pod の busybox のコンテナノードの上で動くコンテナ/container.txt、/cache、/host-data(kubectl exec で見る)

hostPath の「ホスト」は Pod が動くノードのことです。第2回で見たとおり、kind のノードは手元のマシンで動くコンテナです。kind の公式ドキュメントも、ノードは kind が作ったコンテナだと説明しています。そのため kind のクラスタでは、hostPath が指すのはノードのコンテナの中のファイルシステムで、手元のマシンのディレクトリそのものではないと考えられます。

参考:Volumes | Kubernetes、Configuration | kind

一方、kind には手元のマシンのディレクトリをノードに渡す設定(extraMounts)があります。kind の公式ドキュメントの extraMounts の説明でいう「ホスト」は手元のマシンのことで、hostPath の「ホスト」(ノード)とは別のもの です。kind の公式ドキュメントによると、extraMounts はデータを残したり、コードをマウントしたりするために、ホストのストレージを kind のノードに渡すのに使えます。設定の例のコメントでも、ホスト(手元のマシン)のパスとノードのパスは、別のものとして書き分けられています。このことからも、extraMounts を設定していなければ、ノードの中に書いたファイルは手元のマシンからは見えないと考えられます。この回の手順では extraMounts を使いません。

参考:Configuration | kind

Pod を作り直したときに消えるもの・残るもの

ここまでの内容をデータの置き場所ごとに比べます。以下の図は、コンテナのファイルシステム、emptyDir、hostPath の 3 か所にファイルを書いた Pod を消し、同じマニフェストで作り直したときの様子をコマ送りで表しています。シングルノードのクラスタで、作り直した Pod が同じノードに置かれる場合です。後半の「手元で試す」で行う手順にあたります。

(初期)Pod volume-demo(1 つ目の UID)が動いている。コンテナのファイルシステムに /container.txt、emptyDir に emptydir.txt、hostPath のディレクトリに hostpath.txt がある
(1/2)Pod を削除した。コンテナが終了して Pod がノードから消え、emptyDir のデータも消える。ノードのディレクトリは Pod の外にあるので、hostpath.txt はノードに残っていると考えられる
(2/2)同じマニフェストで Pod を作り直した(2 つ目の UID)。新しいコンテナはイメージの最初の中身から始まるので /container.txt は無く、emptyDir も新しい空のディレクトリになる。同じノードのディレクトリをマウントするので、hostpath.txt が見えると考えられる

(1/2)で hostpath.txt が残ると考えられるのは、hostPath がマウントしているのが、Pod とは別にあるノードのファイルシステムだからです。公式ドキュメントは、Pod が存在しなくなると一時的なボリュームは消す、と説明していますが、hostPath はその一時的なボリュームの一覧には入っていません。公式のチュートリアル(hostPath の PersistentVolume を使う例)では、片付けのときに Pod などを消したあとで、ノードに手で作ったファイルとディレクトリを手で消しています。チュートリアルは Pod を消したあとのファイルの扱いを直接は説明していませんが、この手順からも、Pod を消してもノードのファイルは残ると読めます。

参考:Volumes | Kubernetes、Ephemeral Volumes | Kubernetes、Configure a Pod to Use a PersistentVolume for Storage | Kubernetes

コンテナが再起動したときと、Pod を消して作り直したときに、データがどうなるかを次の表にまとめます。

置き場所コンテナが再起動したときPod を消して作り直したとき
コンテナのファイルシステム消える。kubelet はコンテナをまっさらな状態で再起動する消える。新しい Pod のコンテナは、イメージの最初の中身から始まる
emptyDir残る消える。新しい Pod には新しい空の emptyDir が作られる
hostPath残るノードのファイルなので残ると考えられる。別のノードに置かれた場合は、そのノードのファイルが見えると考えられる

参考:Volumes | Kubernetes、Volumes | Kubernetes、Volumes | Kubernetes、Volumes | Kubernetes、Pod Lifecycle | Kubernetes

表の hostPath の行の 2 つ目の文は、公式ドキュメントの「同じ設定の Pod でも、ノードごとにファイルが違うため、ノードによって動きが変わることがある」という注意にあたります。第8回で見たとおり、作り直した Pod が前と同じノードに置かれる保証はありません。マルチノードのクラスタでは、前の Pod が書いたファイルが、作り直した Pod から見えないこともあると考えられます。

参考:Volumes | Kubernetes、Pod Lifecycle | Kubernetes

コンテナの再起動で emptyDir のデータが残ることは、公式ドキュメントのボリュームの使い方のページで試されています。Redis(キーと値を保存するソフトウェア)のコンテナを 1 つ持つ Pod に emptyDir をマウントし、ファイルを書いてから、コンテナの中の Redis のプロセスを止める例です。元の端末で kubectl get pod redis --watch を実行して Pod を見ておき、別の端末でコンテナの中に入ってファイルを書き、プロセスを止めます。すると、元の端末に次のように表示されると書かれています。

NAME      READY     STATUS     RESTARTS   AGE
redis     1/1       Running    0          13s
redis     0/1       Completed  0         6m
redis     1/1       Running    1         6m

参考:Configure a Pod to Use a Volume for Storage | Kubernetes

Pod の名前は redis のままで、RESTARTS 列が 0 から 1 に増えています。公式ドキュメントによると、Pod の restartPolicy が Always なので、コンテナが終了して再起動しました(第9回)。再起動したコンテナの中で emptyDir のディレクトリを ls で見ると、書いたファイル test-file がまだあることが示されています。この回の「手元で試す」ではコンテナの再起動ではなく、Pod を作り直したときを試します。

参考:Configure a Pod to Use a Volume for Storage | Kubernetes

手元で試す

ここまでの内容を手元の kind のクラスタで試す手順を示します。emptyDir と hostPath の 2 つのボリュームを持つ Pod を作り、コンテナのファイルシステム、emptyDir、hostPath の 3 か所にファイルを書きます。hostPath のファイルがノードのコンテナの中にあることも確かめます。続けて Pod を消して同じマニフェストで作り直し、3 つのファイルのうちどれが残るかを比べます。最後に、kind のクラスタの etcd の Pod が使う hostPath を見ます。コマンドは macOS や Linux のシェル(bash や zsh)で実行する前提で書いています。Windows では WSL(Windows の中で Linux を動かす仕組み)などを使ってください。試す環境は次のとおりです。

項目内容
kindv0.33.0
Kubernetesv1.37.0(kind v0.33.0 の既定のノードイメージ)
ノード構成シングルノード(クラスタ名 kind):コントロールプレーン 1
必要なものDocker、kubectl(v1.36〜v1.38)、テキストエディタ、端末(ターミナル)2 つ

参考:Release v0.33.0 · kubernetes-sigs/kind、Version Skew Policy | Kubernetes

kind でクラスタを作る手順は、以下の記事で解説しています。この回ではシングルノードのクラスタを使います。hostPath のデータはノードごとにあるので、作り直した Pod が前と同じノードに置かれるようにするためです。

基本仕様 ・ 第2回 kind で検証用のクラスタを作るDocker のコンテナをノードにして、手元のマシンに Kubernetes のクラスタを作るツール kind の仕組みを図で説明します。kind create cluster で何が起きるかを押さえ、シングルノードとマルチノードのクラスタを作って、ノードの正体が Docker のコンテナであることを確かめる手順を紹介します。

シングルノードのクラスタを用意する

まず、前の回のクラスタが残っていないかを確かめます。

console
$ kind get clusters

kind が表示されたら、作り直さずにそのまま使えるので、クラスタを作る次のコマンドは飛ばします。表示されなければ、クラスタを作ってから、もう一度一覧します。前の回の multi-node が表示されても、この回では使いません。手元のマシンの資源(メモリなど)に余裕がなければ、kind delete cluster --name multi-node で消してから進めてください。

console
$ kind create cluster
$ kind get clusters

kind get clusters に kind が表示されれば、クラスタができています。第3回で決めたとおり、ここからのコマンドには --context kind-kind を付けて、操作するクラスタをはっきりさせます。

参考:Quick Start | kind

続けて、ノードを一覧します。

console
$ kubectl get nodes --context kind-kind

ノードが 1 つ表示され、STATUS 列が Ready になっていれば準備ができています。Ready になっていなければ、少し待ってからもう一度実行します。

参考:kubectl get | Kubernetes、Node Status | Kubernetes

2 つのボリュームを持つ Pod を作る

以下はこの回で使う Pod のマニフェストです。emptyDir のボリューム cache-volume をコンテナの /cache に、hostPath のボリューム host-volume をコンテナの /host-data にマウントします。volume-demo.yaml という名前で、コマンドを実行するディレクトリに保存します。

yaml
apiVersion: v1
kind: Pod
metadata:
  name: volume-demo
  labels:
    app: volume-demo
spec:
  containers:
  - name: busybox
    image: busybox:1.28
    command: ['sh', '-c', 'sleep 3600']
    volumeMounts:
    - name: cache-volume
      mountPath: /cache
    - name: host-volume
      mountPath: /host-data
  volumes:
  - name: cache-volume
    emptyDir: {}
  - name: host-volume
    hostPath:
      path: /var/local/volume-demo
      type: DirectoryOrCreate

参考:Volumes | Kubernetes、Volumes | Kubernetes、Pod | Kubernetes API Reference、PersistentVolume | Kubernetes API Reference

公式ドキュメントの emptyDir の例と、hostPath の FileOrCreate の例をもとに、この回に合わせて変えたマニフェストです。emptyDir には sizeLimit を書かず、第10回と同じく {}(設定を何も指定しない)にしました。hostPath は FileOrCreate の例の、/var/local/aaa を DirectoryOrCreate でマウントする部分にならい、パスを /var/local/volume-demo に変えています。公式ドキュメントの例の説明によると、ノードに /var/local/aaa が無ければ、kubelet がディレクトリとして作ってから Pod にマウントします。type の表の DirectoryOrCreate の説明も、パスに何も無ければ空のディレクトリを作る、としています。イメージは第18回〜第20回と同じ busybox:1.28 で、sleep 3600 は 3600 秒(1 時間)待つだけのコマンドです。手順を終えるまでコンテナを動かしておくためのものです。

参考:Volumes | Kubernetes、Volumes | Kubernetes

ここからは端末を 2 つ使います。第11回・第13回〜第20回と同じく、1 つ目の端末で変化を追い続け、2 つ目の端末でマニフェストを渡したり、コンテナの中でコマンドを動かしたりします。この回で 1 つ目の端末が追うのは Pod です。2 つ目の端末を開いたら、cd でマニフェストを保存したディレクトリに移動しておきます。

1 つ目の端末で、app=volume-demo のラベルを持つ Pod を監視します。第3回で見たとおり、--watch を付けると、一覧を表示したあとも変化を追い続けます。この監視は片付けの前まで止めずに続けます。

console
$ kubectl get pods --watch -l app=volume-demo --context kind-kind

参考:kubectl get | Kubernetes

Pod がまだ無いので、何も表示されないか、見つからないことを知らせる 1 行が出たあと、止まったように見えると考えられます。

2 つ目の端末で、Pod のマニフェストを渡します。

console
$ kubectl apply -f volume-demo.yaml --context kind-kind

pod/volume-demo が作られたことを知らせる 1 行が出るはずです。1 つ目の端末には volume-demo の行が書き足され、STATUS 列が Pending、ContainerCreating、Running と移っていくと考えられます。クラスタを作ったばかりなら、busybox:1.28 のイメージの取得に時間がかかるので、ContainerCreating のまましばらく止まって見えることがあります(第9回)。

参考:Pod Lifecycle | Kubernetes

3 か所にファイルを書く

1 つ目の端末で Running になったのを確かめたら、2 つ目の端末で、コンテナの中の 3 か所にファイルを書きます。第10回で見たとおり、kubectl exec はコンテナの中でコマンドを動かすコマンドで、-- の後ろがコンテナの中で動かすコマンドです。sh -c に渡した文字列は、コンテナの中のシェルが ; で区切って順に実行します(第9回)。echo は一般に文字列を書き出すコマンドで、> はその出力をファイルに書き込むシェルの記号です(第10回)。

console
$ kubectl exec volume-demo --context kind-kind -- sh -c 'echo container > /container.txt; echo emptyDir > /cache/emptydir.txt; echo hostPath > /host-data/hostpath.txt'

参考:kubectl exec | Kubernetes

書いたファイルは次の 3 つです。中身はどこに書いたかがわかる 1 語にしました。

ファイル置き場所中身
/container.txtコンテナのファイルシステム(ボリュームではない / の直下)container
/cache/emptydir.txtemptyDir のボリューム cache-volumeemptyDir
/host-data/hostpath.txthostPath のボリューム host-volume(ノードの /var/local/volume-demo)hostPath

何も表示されずに終われば、書き込めています。/host-data への書き込みでエラーになった場合は、「hostPath の type」で見た、root だけがアクセスできるファイルやディレクトリの注意にあたると考えられます。そのときは、次の節で説明する docker exec を使い、ノードの側のディレクトリの権限と所有者を見ます。ls -ld は一般に、ディレクトリの中身ではなく、ディレクトリそのものの権限と所有者を表示するコマンドです。

console
$ docker exec kind-control-plane ls -ld /var/local/volume-demo

公式ドキュメントによると、DirectoryOrCreate で新しく作られたディレクトリの権限は 0755 で、グループと所有者は kubelet と同じです。0755 は ls -ld の表示では一般に drwxr-xr-x にあたります。これと違っていたら、この手順より前に同じパスのディレクトリがノードにあったと考えられます。

参考:Volumes | Kubernetes、docker container exec | Docker Docs

続けて、3 つのファイルを読みます。cat は一般に、ファイルの中身を表示するコマンドです。

console
$ kubectl exec volume-demo --context kind-kind -- cat /container.txt
$ kubectl exec volume-demo --context kind-kind -- cat /cache/emptydir.txt
$ kubectl exec volume-demo --context kind-kind -- cat /host-data/hostpath.txt

順に container、emptyDir、hostPath と表示されるはずです。今はまだ同じ Pod なので、3 つとも読めます。

あとで比べるために、Pod の UID(第5回)をファイルに書き出しておきます。-o jsonpath は第5回で使った、フィールドを指定して取り出す出力の形式です。

console
$ kubectl get pod volume-demo -o jsonpath='{.metadata.uid}{"\n"}' --context kind-kind > uid-before.txt

参考:JSONPath Support | Kubernetes

hostPath のファイルをノードの側から見る

hostPath のファイルがノードのファイルシステムにあることを確かめます。第2回・第4回と同じく、docker exec でノードのコンテナの中でコマンドを実行します。kind の Quick Start の例では、クラスタ名 kind のノードのコンテナの名前は kind-control-plane です。名前が違うときは、docker ps の NAMES 列で確かめて置き換えてください。

console
$ docker exec kind-control-plane cat /var/local/volume-demo/hostpath.txt

参考:Quick Start | kind、docker container exec | Docker Docs

hostPath と表示されるはずです。コンテナの中で /host-data/hostpath.txt に書いたファイルが、ノードでは /var/local/volume-demo/hostpath.txt として見えています。コンテナが見つからないことを知らせるエラーになったら、ノードのコンテナの名前が docker ps の NAMES 列と合っているかを確かめます。

続けて、手元のマシンで同じパスを見ます。

console
$ ls /var/local/volume-demo

「kind のクラスタでの「ホスト」」で考えたとおりなら、手元のマシンにはこのディレクトリが無く、見つからないことを知らせるエラーの行が出るはずです。kind のクラスタでの hostPath の「ホスト」は、手元のマシンではなく、ノードのコンテナだと読めます。エラーにならずにディレクトリが見えた場合は、手元のマシンにもともと同じパスのディレクトリがあったか、extraMounts を設定したクラスタを使っていると考えられます。その中に hostpath.txt が無ければ、ノードのディレクトリとは別のものです。

Pod を消して作り直す

2 つ目の端末で、Pod を削除します。

console
$ kubectl delete pod volume-demo --context kind-kind

参考:kubectl delete | Kubernetes

kubectl delete は既定では、Pod が消えるまで待ってから終わります。Pod には終了までの猶予の時間(既定では 30 秒)があるので、終わるまで少しかかることがあります。1 つ目の端末には、volume-demo の行の STATUS 列が Terminating になった行が書き足されるはずです。第8回で見たとおり、直接作った Pod には作り直すコントローラーがいないので、新しい Pod の行は現れないはずです。

参考:kubectl delete | Kubernetes、Pod Lifecycle | Kubernetes、Pod Lifecycle | Kubernetes

2 つ目の端末の kubectl delete が終わったら、同じマニフェストで Pod をもう一度作ります。

console
$ kubectl apply -f volume-demo.yaml --context kind-kind

1 つ目の端末には、同じ名前の volume-demo の行が書き足され、STATUS 列が Running まで移っていくはずです。AGE 列は作り直した時点から数え直されると考えられます。シングルノードのクラスタなので、作り直した Pod も同じノードに置かれるはずです。置かれたノードは次のコマンドの NODE 列で確かめられます。-o wide はノードの名前などを加えて一覧する出力の形式です。このクラスタのノードは 1 つなので、kind-control-plane が表示されるはずです。

console
$ kubectl get pod volume-demo -o wide --context kind-kind

参考:kubectl get | Kubernetes

消えたファイルと残ったファイルを比べる

1 つ目の端末で Running になったのを確かめたら、2 つ目の端末で、さきほどと同じ 3 つのコマンドでファイルを読みます。

console
$ kubectl exec volume-demo --context kind-kind -- cat /container.txt
$ kubectl exec volume-demo --context kind-kind -- cat /cache/emptydir.txt
$ kubectl exec volume-demo --context kind-kind -- cat /host-data/hostpath.txt

結果は次のようになるはずです。

コマンド結果理由
cat /container.txtファイルが無いことを知らせるエラーの行新しい Pod のコンテナは、イメージの最初の中身から始まる
cat /cache/emptydir.txtファイルが無いことを知らせるエラーの行前の Pod の emptyDir は Pod と一緒に消え、新しい空の emptyDir が作られた
cat /host-data/hostpath.txthostPathノードの /var/local/volume-demo は Pod とは別にあり、同じノードの同じディレクトリをマウントした

参考:Volumes | Kubernetes、Volumes | Kubernetes、Pod Lifecycle | Kubernetes

1 行目と 2 行目でファイルが無いことを知らせるエラーが出るのは、手順の失敗ではなく、この回で確かめたい結果です。エラーの行の文面は公式ドキュメントでは確かめられませんでした。No such file or directory のような、ファイルが無いことを表す文が含まれると考えられます。kubectl exec がコンテナの中のコマンドの失敗を知らせる行も、続けて出ることがあると考えられます。

作り直した Pod の UID を、削除する前の UID と見比べます。

console
$ kubectl get pod volume-demo -o jsonpath='{.metadata.uid}{"\n"}' --context kind-kind
$ cat uid-before.txt

名前は同じ volume-demo でも、UID は違います。公式ドキュメントによると、前の Pod と同じ名前で代わりの Pod を作っても、.metadata.uid は前の Pod と違うものになります。第8回で見たとおり、作り直した Pod は同じ名前の別の Pod です。emptyDir は「その UID の Pod」と同じ期間だけ存在するので、UID が変われば emptyDir も新しくなります。一方、hostPath のディレクトリはノードにあり、どの UID の Pod とも結び付いていないので、前の Pod が書いたファイルが読めたと考えられます。

参考:Object Names and IDs | Kubernetes、Pod Lifecycle | Kubernetes、Pod Lifecycle | Kubernetes

etcd の Pod の hostPath を見る

最後に、Kubernetes 自身のコンポーネントが使う hostPath を見ます。2 つ目の端末で、kube-system の Namespace の Pod を一覧します。

console
$ kubectl get pods -n kube-system --context kind-kind

第4回で見たとおり、etcd の static Pod の名前は etcd-<ノード名> です。このクラスタでは etcd-kind-control-plane になると考えられます。一覧に出た etcd- で始まる名前を <etcd の Pod の名前> に入れて、Pod のボリュームの一覧を取り出します。

console
$ kubectl get pod <etcd の Pod の名前> -n kube-system -o jsonpath='{.spec.volumes}{"\n"}' --context kind-kind

参考:kubectl get | Kubernetes、JSONPath Support | Kubernetes、Implementation details | Kubernetes

ボリュームの一覧が JSON の形で 1 行に表示され、その中に hostPath を含む項目があるはずです。API リファレンスの形のとおりなら、1 つの項目にはボリュームの名前(name)と、hostPath の中身(path と、指定されていれば type)が組になって入っているはずです。hostPath の中の path がノードのどのディレクトリをマウントしているかを表します。

kubeadm は etcd のデータのディレクトリを hostPath でマウントします。kubeadm の設定の API リファレンスによると、etcd のデータのディレクトリ(dataDir)の既定は /var/lib/etcd です。kind が既定を変えていなければ、path が /var/lib/etcd の項目があると考えられます。hostPath の項目が 1 つとは限らないので、path の値を見比べて探します。etcd はクラスタのデータを保存するので、etcd の Pod が作り直されても、データがノードに残るようにしていると考えられます。

参考:Pod | Kubernetes API Reference、Implementation details | Kubernetes、kubeadm Configuration (v1beta4) | Kubernetes

片付け

1 つ目の端末で Ctrl+C を押して、Pod の監視を止めます。

2 つ目の端末で、作った Pod を、マニフェストを指定して削除します。

console
$ kubectl delete -f volume-demo.yaml --context kind-kind

参考:kubectl delete | Kubernetes

/var/local/volume-demo をマウントする Pod はもう無いので、ノードのディレクトリがどうなったかを見ます。

console
$ docker exec kind-control-plane ls /var/local/volume-demo

hostpath.txt が表示されるはずです。Pod を消しても、hostPath のディレクトリとファイルはノードに残っていると考えられます。公式のチュートリアルと同じく、ノードに残ったファイルは手で消します。rm -r は一般に、ディレクトリを中身ごと消すコマンドです。

console
$ docker exec kind-control-plane rm -r /var/local/volume-demo

参考:Configure a Pod to Use a PersistentVolume for Storage | Kubernetes、docker container exec | Docker Docs

書き出した UID のファイルも消します。

console
$ rm uid-before.txt

最後に、クラスタを削除し、消えたことを確かめます。

console
$ kind delete cluster
$ kind get clusters

kind delete cluster は存在しないクラスタを指定してもエラーを返しません。kind get clusters に kind が表示されなくなったことを確かめます。kubeconfig に kind-kind のコンテキストが残っていたら、第3回の片付けと同じく kubectl config delete-context kind-kind で消します。クラスタを削除するとノードのコンテナも消えるので、ノードのディレクトリを手で消し忘れても、そこにあったファイルはノードのコンテナと一緒に消えると考えられます。

参考:Quick Start | kind、kubectl config | Kubernetes

注意点

ボリュームでつまずきやすい点と、hostPath を使うときに気を付ける点、バージョンで変わる点を、次の表にまとめます。

項目内容
コンテナの中のファイルは再起動で消えるボリュームではない場所に書いたファイルは、コンテナが再起動すると失われる
emptyDir は Pod と同じ期間だけコンテナの再起動では消えないが、Pod がどんな理由でノードから消えても、データは完全に消える。同じ名前で作り直した Pod の emptyDir も新しい空のディレクトリ
Pod を超えて残すデータ永続的なボリュームは、個々の Pod の期間を超えて存在する(第27回)
medium: Memory はメモリーを使うtmpfs に置かれ、書いたファイルはコンテナのメモリーの上限に数えられる。sizeLimit もメモリーの上限も書かないと、ノードのメモリーをすべて使いかねない
sizeLimit に届く前に尽きることがある既定の記憶装置のときの容量はノードのローカルの一時的なストレージから割り当てられ、ほかの用途で埋まると上限より前に尽きることがある
hostPath は多くのセキュリティのリスクがある公式ドキュメントは、使わずに済むなら使わないよう警告している。代わりの例は local の PersistentVolume
hostPath のデータはノードごと同じ設定の Pod でも、ノードごとにファイルが違うため、動きが変わることがある
hostPath の使用量は一時的なストレージに数えられない使いすぎるとノードのディスクが逼迫するので、使用量を自分で見張る
FileOrCreate は親のディレクトリを作らない親のディレクトリが無いと Pod は起動に失敗する。ディレクトリとファイルを別々にマウントする
Pod Security Standards の Baseline では禁止Baseline の水準では hostPath のボリュームを書けない(第39回)
v1.37 時点のアルファの機能emptyDir の mode と、メモリーの上の emptyDir の sizeLimit を動いたまま変える機能は、アルファで既定では無効

参考:Volumes | Kubernetes、Pod Lifecycle | Kubernetes、Resource Management for Pods and Containers | Kubernetes、Pod Security Standards | Kubernetes

hostPath の代わりの例に挙がっている local のボリュームについて、公式ドキュメントは hostPath と比べて、Pod を手でノードに割り当てなくても、長く使えて持ち運びやすい形で使える、と説明しています。Kubernetes は PersistentVolume に書いたノードの条件(ノードアフィニティ)を見て、ボリュームがどのノードにあるかを把握します。local のボリュームは前もって作った PersistentVolume としてだけ使えます。PersistentVolume の一覧のページでも、hostPath の PersistentVolume は、シングルノードのクラスタで試すためだけのもので、マルチノードのクラスタでは動かない、と書かれています。公式のチュートリアルも本番のクラスタでは hostPath を使わない、と説明しています。PersistentVolume は第27回、ノードアフィニティは第31回で扱います。

参考:Volumes | Kubernetes、Persistent Volumes | Kubernetes、Configure a Pod to Use a PersistentVolume for Storage | Kubernetes

関連記事

Pod を超えてデータを残す PersistentVolume と PersistentVolumeClaim(PVC)、PVC を作るとボリュームが用意される動的プロビジョニングについては、以下の記事で解説しています。

基本仕様 ・ 第27回 PersistentVolume と PVC の仕組みPod の期間を超えてデータを残す PersistentVolume、PVC、StorageClass の関係を図で説明します。静的と動的のプロビジョニング、1 対 1 のバインド、アクセスモード、回収ポリシー、volumeBindingMode を押さえ、kind のクラスタで PVC とそれを使う Pod を作り、ボリュームが自動で用意される流れを観察します。

StatefulSet と PVC を組み合わせて、Pod を消しても同じボリュームにつなぎ直し、データを残す方法については、以下の記事で解説しています。

基本仕様 ・ 第28回 StatefulSet と PVC でデータを残すStatefulSet の volumeClaimTemplates が Pod ごとに PersistentVolumeClaim を作り、Pod を作り直しても同じボリュームにつなぎ直す仕組みを図で説明します。PVC の名前の付き方、消したり数を減らしたりしても PVC が残る既定の動き、persistentVolumeClaimRetentionPolicy を押さえ、kind のクラスタでデータが残ることを確かめる手順を示します。

メモリーの上の emptyDir の大きさにかかわる、コンテナのメモリーの requests と limits については、以下の記事で解説しています。

基本仕様 ・ 第29回 requests と limits の仕組みコンテナが使う CPU とメモリの量を書く requests と limits の仕組みを図で説明します。requests で Pod を置くノードが選ばれること、limits を超えようとした CPU とメモリに起きること、QoS クラスの決まり方を押さえ、kind のクラスタで OOMKilled を観察する手順を紹介します。

Kubernetes 基本仕様の目次へ