【Docker】Volumeを使わない場合のデータ書き込みの仕組み

Dockerのcontainer上にS3等の外部サービスからファイルをダウンロードできないか考えたが、そもそもVolumeを使わない場合にContainer上で書き込みを行うとどこに保存されるのかよくわかっていなかったので、ドキュメントに当たり直してみた。

まずimageとcontainerの関係を整理すると、ドキュメントに載っている以下の画像のようになる。

docs.docker.com

f:id:Udomomo:20200528091512p:plain

imageはいくつかのlayerからなっており、Dockerfileで定義したそれぞれのコマンドが1つのlayerを作っていく。新しいlayerが古いlayerの上に積み上がっていくことで、layerの再利用が可能な仕組みになっている。
このimageからcontainerが作られるとき、最後に薄いreadable/writable layer (container layer)が追加される。image layerはすべてread onlyであるため、container実行中の変更(ファイルのダウンロード・編集・削除など)は全てcontainer layerに記録される。このため、同じimageをもとに複数のcontainerが作られ、それぞれが別の変更をしても、その変更がcontainerを波及して共有されることはない。
containerが取り除かれると、container layerも消えるため、変更も消える。imageはread onlyなので変更されておらず、最初と同じ状態の新しいcontainerを作ることができる。このように、取り除かれたら変更が消えて特定の状態に戻るようなresourceを ephemeral resource という。

仮にimage内に同梱されたファイルを変更したい場合、containerのstorage driverがimage layerからファイルを探し、readable/writable layerにコピーしてくる。この処理の詳細はstorage driverの実装によって異なるが、このようなオペレーションをCoW(Copy on Write)という。この方法の利点は、container起動時にreadable/writable layerにファイルを含めておく必要がないこと。これにより、readable/writable layerを最小限の大きさに保ち、containerの起動速度への影響を抑えている。
ただし、storage driverはI/Oに最適化されているわけではない。もしcontainer上でデータのwriteを頻繁に行う場合、パフォーマンスに影響が生じてくる恐れがあるため、その場合はContainerから独立したVolumeの使用を検討する方が良い。