docker

overlayfsをさわってみる

コンテナを使うだけでなく少しでもいいので中身も理解していく

overlayfsが気になったきっかけ

はてブにノミネートされていた2021年に今更コンテナ入門した僕の最初の一歩という記事タイトルを見て、よくあるdockerコマンドの使い方を説明するだけの初心者向け記事かと思ったらこれが大間違い。Rustでコンテナランタイムを自作するというハイレベルな内容で腰を抜かした。

その記事の中で紹介されていたのが徳永さんのイラストでわかるDockerとKubernetesという本。この本の存在自体は以前から認知していたが、他にもコンテナ入門系の書籍は何冊か読んでいたのでスルーしていた。

まだ読んでいる途中ではあるが、なるほど元記事で言及されているとおり内部の動く仕組みに言及されていて素晴らしい本だと感じた。

この本の素晴らしいところはDockerの使い方だけではなく、コンテナの仕組みを説明してくれているところでした。

もう察しはついたと思うが、とどのつまり本の中でoverlayfsについての言及があったのでそこをちゃんと理解したいと思った次第である。

今回は、書籍より少しだけ詳しくoverlayfsについて調べてみる。

overlayfsとは

コンテナを使うシーンでは往々にして同一のコンテナを複数立ち上げるということをやる。

コンテナの利点に、1つ1つのコンテナが互いに影響を及ぼさない隔離性が挙げられるが、とはいえベースが全く同じ複数のコンテナに対して重複する部分を個別に持っているとダブりが多すぎて効率が悪い。

そのため、複数のディレクトリを多層的に重ね合わせて、差分管理を実現するという対応が取られる。

この差分管理に利用するのがLinuxカーネルのイチ機能であるoverlayfsというわけだ。

どう差分管理するのか

動かす前にザックリと仕組みを理解しておく。

オーバーレイでは、読み取り専用の下層レイヤーの上に読み書き可能な上層レイヤ―を重ね合わせることができる。

このときの下層レイヤーをlowerdir、上層レイヤーをupperdirと呼ぶ。つまり、実際には複数のディレクトリを指定して重ね合わせることになる。

動きとしては、下層レイヤーに含まれるファイルに書き込みがあった場合、そのファイルを上層レイヤーにコピーしてから書き込みを行う。ファイルを読み取る際には、上層レイヤーのものを優先するというルールで扱うことで、共通部分は保持したまま差分管理が可能となるわけだ。

このような仕組みをCopy on Write、略してCoWと呼んでいるらしい。

この他に必要なディレクトリとしてoverlayfsが作業を行うためのworkdirと、lowerdirupperdirが重ね合わされた結果として利用するためのmergedがある。

実際にコマンドを叩く

overlayfsにはmountコマンドを使う。

mkdir lower upper work merged
sudo mount -t overlay overlay -o lowerdir=lower,upperdir=upper,workdir=work merged

overlayを2回書いているのが不思議な感じなので、man mountしてみる。すると、使い方はmount -t type device dirとあり、overlayタイプを指定し、mergedをマウント先としてoverlayをマウントしているということがわかる。

ちなみに、以下のように:で連結すれば、lowerdirの部分に複数のディレクトリをまとめて下層レイヤーとして指定することもできる。

mkdir lower1 lower2 upper work merged
sudo mount -t overlay overlay -o lowerdir=lower1:lower2,upperdir=upper,workdir=work merged

ちなみにman mount | grep overlayすると、以下が返る。上記の使い方と同じだ。

Mount options for overlay
    Since Linux 3.18 the overlay pseudo filesystem implements a union mount for other filesystems.
    An overlay filesystem combines two filesystems - an upper filesystem and a lower filesystem.  When a  name  exists
    filesystem  can  even  be  another overlayfs.  The upper filesystem will normally be writable and if it is it must
    A  read-only  overlay of two read-only filesystems may use any filesystem type.  The options lowerdir and upperdir
          mount -t overlay  overlay  \

また、単にmountコマンドを打つと現在マウントされているもののリストを得ることができる。mount | grep overlayすると先ほどマウントしたmergedを含む行が返ってくるはずだ。

$ mount | grep overlay
overlay on <YOUR-WORKING-DIR>/merged type overlay (rw,relatime,lowerdir=lower/,upperdir=upper/,workdir=work/)

さて、mountコマンドを打ったあとの流れは書籍でもほぼ同じ内容で解説されているため割愛してもよいのだが、それもあんまりなので書籍より少し詳しい程度に紹介する。

まず、mountコマンドの直後では、共有ファイルへの書き込みがないのでどのフォルダの中身も空である。

$ ls upper/
$ ls lower/
$ ls merged/

結合層であるmergedディレクトリにファイルを新規作成すると上層レイヤーにnewfile.txtが見えるようになる。

$ touch merged/newfile.txt
$ ls upper/
newfile.txt

一方で下層レイヤーに変更はない。

$ ls lower/

せっかくなので下層レイヤーに直接ファイルを作成してどうなるかも見てみよう。

$ echo 'lower' > lower/secondfile.txt
$ ls lower/
secondfile.txt
$ ls merged/
newfile.txt  secondfile.txt

下層レイヤーにsecondfile.txtが作成され、mergedディレクトリから透過的に見えているのが分かる。

それでは、mergedディレクトリを通してlowerにあるsecondfile.txtをいじってみよう。

$ echo 'edit from merged' > merged/secondfile.txt
$ cat merged/secondfile.txt
edit from merged
$ cat lower/secondfile.txt
lower
$ cat upper/secondfile.txt
edit from merged

このように下層レイヤーのファイルに変更は加えられず、 上層レイヤーにCoWされていることがわかる。

アンマウントして終了する

挙動を確認できたところで、最後にマウントを解除してハンズオンを終える。

解除にはumountコマンドを利用する。

sudo umount ./merged

以上でoverlayfsの簡単な検証を終わりにする。