Docker でのデータ管理

コンテナ内で作成された全てのファイルは、デフォルトで 書き込み可能なコンテナ レイヤー(writable container layer) に保存されます。つまり、これが意味するのは:

  • コンテナを削除すると、データは保持されません。そして、コンテナの外から他のプロセスが必要なデータを取得するのが困難になります。
  • コンテナの書き込み可能なレイヤーは、コンテナを実行しているホストマシンと密接につながっています。データをどこかへ移動するのは簡単ではありません。
  • コンテナの書き込み可能なレイヤーに書き込むには、ファイルシステムを管理するための ストレージ ドライバ が必要です。ストレジ ドライバは Linux カーネルを使う ユニオン ファイルシステム(union filesystem) を備えています。この特別な抽象化のため、 ホスト ファイルシステムに直接書き込む「 データ ボリューム(data volume) 」に比べ、性能が劣ります。

コンテナがホストマシン上にファイルを保存するため、Docker には「 ボリューム(volume) 」と「 バインド マウント(bind mount) 」という、2つのオプションがあります。

また、 Docker はホストマシン上のメモリ内へのファイル保存もサポートしています。ですが、これらのファイルは保持されません。 Linux 上で Docker を実行している場合は、「 tmpfs マウント」がホストのシステムメモリ内への保存に使われます。Windows 上で Docker を実行している場合は、「 名前付きパイプ(named pipe) 」がホストのシステムメモリ内への保存に使われます。

メモリ内でデータを保持する利点についての情報を知るには、このまま読み進めてください。

正しいマウント形式を選択

どのマウント形式を使っても、コンテナ内からデータは同じように見えます。データはディレクトリや個々のファイルとして、コンテナのファイルシステム内に提供されます。

データが Docker ホスト上のどこに存在しているかを考えるには、ボリューム、バインド マウント、 tmpfs マウントの違いを図にすると簡単です。

マウント形式と、Docker ホスト上のどこにデータが存在するか
  • ボリューム(volume) は、 「Docker によって管理されている」ホストファイルシステム上の一部に保管します( Linux 上では /var/lib/docker/volumes )。 Docker 以外のプロセスは、このファイルシステム上の一部を変更すべきではありません。ボリュームは Docker 内のデータを保持するために一番良い方法です。
  • バインド マウント(bind mount) は、ホストシステム上の「どこにでも」保管できます。これには重要なシステムファイルやディレクトリも含みます。Docekr ホスト上の Docker 以外のプロセスも、 Docker コンテナも、常にデータを変更できます。
  • tmpfs マウント は、ホストシステムのメモリ上にのみ保管します。そして、ホストシステムのファイルシステムには一切書き込まれません。

マウント形式の詳細

  • ボリューム :Docker によって作成と管理されます。ボリュームは docker volume create コマンドを使って自明的に作成できます。また、 Docker はコンテナやサービスの作成j時にボリュームを作成できます。

    ボリュームを作成すると、Docker ホスト上のディレクトリ内に(ボリュームが)置かれます。コンテナ内にボリュームをマウントする時は、この(ホスト上に作成された)ディレクトリがコンテナ内にマウントされます。これはバインド マウントと似たような手法ですが、異なるのは、 Docker によってボリュームが管理され、ホストマシン上のコア機能からボリュームが 分離(isolate) されています。

    既定のボリュームは、複数のコンテナから同時にマウント可能です。ボリュームが実行中のコンテナから一切使われていなくても、ボリュームは Docker 上で利用可能なままであり、自動的には削除されません。使わないボリュームは docker volume prune で削除できます。

    ボリュームのマウントは 名前付き(named)無名(anonymous) です。 無名ボリューム(anonymous volume) とは、コンテナに始めてマウントする時、特定の名前が与えられません。そのため、 Dockre は ランダムな名前を割り当てます。この名前は、 Docker ホスト内で確実に使われていないユニークなものです。名前付きボリュームと無名ボリュームの呼び方こそ違いますが、挙動はどちらも同じです。

    また、ボリュームは「 ボリューム ドライバ(volume driver) 」の利用もサポートします。これは、データをリモートホスト上や、クラウドプロバイダ、その他利用可能な所にデータを保管します。

  • バインド マウント :Docker の初期から利用できます。バインド マウントはボリュームと比較すると、機能が限定的です。バインド マウントを使用する時、「ホストマシン」上のファイルやディレクトリがコンテナ内にマウントされます。ファイルやディレクトリは、ホストマシン上のフルパスによって参照されます。ファイルやディレクトリは、あらかじめ Docker ホスト上に存在する必要はありません。それらが存在しなければ、必要に応じて作成されます。バインドマウントは高性能ですが、ホストマシン上のファイルシステムが待っている、特定の利用可能なディレクトリ構造に依存します。新しい Docker アプリケーションの開発を検討しているのであれば、かわりに名前付きボリュームの利用を検討してください。Docker CLI コマンドでは、バインド マウントを直接管理できません。

    重要

    バインド マウントは機微情報を扱うファイルにもアクセス可能

    バインド マウントの効果は一方では優れていますが、劣る部分もあります。それは、 コンテナ 内で実行中のプロセスを経由して、 ホスト 側のファイルシステムも変更できる点であり、重要なシステムファイルやディレクトリの作成、変更、削除を含みます。これにはホスト上の Docker 以外のプロセスに対する影響も含む、セキュリティに懸念を与えかねない強力な能力があります。

  • tmpfs マウントtmpfs マウントはディスク上で保持されないどころか、 Docker ホストやコンテナ内にも保持されません。コンテナのライフサイクル中だけで使われるべきであり、保持できない状態や機微情報の保管には利用できません。たとえば、内部では swarm サービスが tmpfs マウントを使い、サービスコンテナ内に シークレット をマウントするために tmpfs マウントを使います。
  • 名前付きパイプ :Docker ホストとコンテナ間で通信するために npipe マウントが利用できます。一般的な使い方は、コンテナ内にサードパーティ製ツールを実行し、名前付きパイプを使って Docker Engine API に接続します。

バインド マウントとボリュームは、どちらも -v--volume フラグを使ってコンテナにマウントできますが、それぞれの構文には若干の違いがあります。 tmpfs マウントでは --tmpfs フラグが使えます。バインド マウント、ボリューム、 tmpfs マウントを、コンテナとサービスの両方で使う場合、構文がより明確な --mount フラグの利用を推奨します。

ボリュームの上手な使い方

Docker コンテナとサービスでデータを保持するには、ボリュームの利用が完璧な方法です。ボリュームには以下の用途もあります。

  • 実行中の複数コンテナ間でデータを共有します。明示的に作成しなくても、コンテナ内に初めてマウントするときにボリュームが作成されます。コンテナが停止もしくは削除されても、ボリュームは残り続けます。読み書き可能な状態だけでなく、読み込み専用としても、複数のコンテナで同じディレクトリを同時にマウントできます。
  • 特定のディレクトリやファイル構造に対して、 Docker ホストが権限を与えられていない場合。ボリュームはコンテナ ランタイムから Docker ホスト設定を切り離すのに役立ちます。
  • ローカルではなく、リモートホストやクラウドプロバイダ上のコンテナに、データを保管したい場合。
  • ある Docker ホストから別の場所へ、バックアップ、修復、データ移行が必要な場合、ボリュームは良い選択です。ボリュームを使っているコンテナを停止後、ボリューム用ディレクトリ( /var/lib/docker/volumes/<ボリューム名> のような)のバックアップが行えます。
  • Docker Desktop 上で、アプリケーションが高性能な I/O を必要とする場合。ボリュームはホスト上ではなく Linux VM に保管されます。これが意味するのは、読み書きが、より低レイテンシかつ高スループットになります。
  • Docker Desktop 上で、アプリケーションが完全にネイティブなファイルシステムの挙動を必要とする場合。たとえば、データベースエンジンであれば、トランザクションの 永続性(durability) を確保するため、緻密なディスクのフラッシュ制御を必要とします。バインド マウントがリモートの macOS や Windows のファイルシステムを扱うのとわずかに異なり、ボリュームは Linux VM 内にデータを保管しますので、これら(永続性や性能)を確保します。

バインド マウントの上手な使い方

一般的に、可能であればボリュームを使うべきです。バインド マウントは、以下の用途での使用に適切です。

  • ホストマシン上の設定ファイルをコンテナに共有する場合。これがまさに、 Docker がコンテナに DNS 名前解決を提供するデフォルトの仕組みとして、ホストマシン上の /etc/resolv.conf をコンテナ内にマウントします。
  • Docker ホスト上の開発環境とコンテナ間で、ソースコードや 構築結果(artifact) を共有する場合。たとえば、 Maven target/ ディレクトリをコンテナ内にマウントすると、それから、 Docker ホスト 上の Maven プロジェクトで毎回構築するたびに、構築結果にコンテナからアクセスできます。

    この手法を Docker の開発で使うには、本番環境用の Dockerfile はバインド マウントに依存するのではなく、本番用の構築結果を直接イメージにコピーする場合です。

  • バインド マウントするコンテナが、Docker ホスト上のファイルやディレクトリ構造と一貫する保証を必要な場合。

tmpfs マウントの上手な使い方

tmpfs マウントの最も上手い利用方法は、ホストマシン上とコンテナ内のどちらでも、データをの保持を必要としない場合です。可能性としては、セキュリティ上の理由や、アプリケーションが状態を保持しない大きな容量の書き込みを必要とする場合に、コンテナの性能を維持するためです。

バインド マウントやボリュームを使うコツ

バインド マウントやボリュームを使う場合は、以下のことを覚えておいてください。

  • ファイルやディレクトリが存在しているコンテナ内のディレクトリに対し、 空っぽのディレクトリ をマウントする場合は、ファイルやディレクトリがボリューム内に 伝搬(propagate) (コピー)されます。同様に、コンテナの起動時に指定したディレクトリが存在していなければ、使用するために空っぽのボリュームを作成します。これは、他のコンテナが必要とするデータを事前に見積もるために良い方法です。
  • バインド マウントや空っぽではないボリューム をコンテナ内のディレクトリにマウントする場合、既にファイルやディレクトリが存在していると、これらのファイルやディレクトリはマウントによって隠されます。これは、 Linux ホスト上の /mnt にファイルを保存していても、 USB ドライブで /mnt にマウントするような状態です。 USB ドライブをアンマウントするまで、/mnt の内容は USB ドライブの内容によって隠されます(訳者注:ファイル等は存在しますが、一時的に見えなくなります)。

次のステップ

参考

Manage data in Docker
https://docs.docker.com/storage/