こんにちは、masm11 です。
最近、コンテナ関係でちょっとハマったことがあったので、ご紹介したいと思います。
非コンテナ
luna:t % mkdir vol1 vol2 luna:t % touch vol1/foo
ディレクトリを2つ作って、 片方のディレクトリにファイルを作ります。
luna:t % ls -li vol1/foo 1024572 -rw-r--r-- 1 masm masm 0 4月 2 13:22 vol1/foo
ls に -i
を付けると、i-node 番号を表示できます。
i-node とは、ファイルの属性を格納したディスク中領域の番号で、
同一ファイルシステムのファイルなら重複しません。
今回は 1024572 です。
luna:t % mv vol1/foo vol2/
そして、vol2 へ移動します。
luna:t % ls -li vol2/foo 1024572 -rw-r--r-- 1 masm masm 0 4月 2 13:22 vol2/foo
i-node 番号は変わっていません。
これは、ディレクトリの書き換えだけが行われた、ということですね。 ディレクトリには、ファイル名と i-node 番号の組が格納されていて、 この組を別のディレクトリに移動させるだけで、ファイルの移動が 完了します。高速です。今回はこの方法が使われたようです。
コンテナボリューム その1
次にコンテナ内から同じことを試してみます。
luna:t % docker pull alpine:latest
Alpine が小さくて便利ですかね。
luna:t % docker run --rm -ti --volume ./vol1:/t alpine /bin/sh
コンテナを起動します。先程作った vol1 をコンテナ内では /t
に見えるように
しています。
/ # df -k Filesystem 1K-blocks Used Available Use% Mounted on zroot/root/50de6be7ffbfcd66419b9730e0a5aaeaccebe153261fd0df5e7171ff59022d49 4192896 6528 4186368 0% / tmpfs 65536 0 65536 0% /dev shm 65536 0 65536 0% /dev/shm zroot/home 58449664 32261248 26188416 55% /t ...
df で mount 状況を確認しました。ちゃんと mount できています。
/ # mkdir t/t1 t/t2 / # touch t/t1/foo
ボリュームの中に、先ほどと同じようにディレクトリを2つ作って、ファイルを作ります。
/ # ls -li t/t1/foo 1024912 -rw-r--r-- 1 root root 0 Apr 2 04:40 t/t1/foo
i-node 番号を確認します。1024912 ですね。
/ # mv t/t1/foo t/t2/ / # ls -li t/t2/foo 1024912 -rw-r--r-- 1 root root 0 Apr 2 04:40 t/t2/foo
mv した後、i-node 番号を確認しました。変化ありませんでした。
コンテナ別ボリューム
次です。
luna:t % docker run --rm -ti --volume ./vol1:/t/t1 --volume ./vol2:/t/t2 alpine /bin/sh
/t/t1
と /t/t2
を別のボリュームにしました。
この状態で同じことをやってみます。
/ # touch /t/t1/bar / # ls -li /t/t1/bar 1024698 -rw-r--r-- 1 root root 0 Apr 2 04:45 /t/t1/bar / # mv /t/t1/bar /t/t2/ / # ls -li /t/t2/bar 1024585 -rw-r--r-- 1 root root 0 Apr 2 04:45 /t/t2/bar
なんと、i-node 番号が変わってしまいました。 これは、今までのようにディレクトリの書き換えだけでは済まず、 ファイルがコピーされたことを示しています。
まとめ
ボリューム間のファイルの移動は、コピーが発生しました。
考えてみれば当然です。 コンテナ内 mv コマンドから見れば、別のファイルシステムなので、 i-node を管理している場所も違うかもしれず、 i-node 番号を別ファイルシステムに持っていっても意味はないからです。
ただ、今回の場合はホスト側では同じボリュームであり、 ホスト側の都合も考慮されるのかと思っていましたが、 そんなことはありませんでした。
さて、コピーになったということは、 一瞬ですがファイルが中途半端(or 空)である、ということです。 ファイルサイズによっては一瞬じゃないかもしれません。 例えば inotify などで監視して処理する場合には要注意ですね (今回、IN_CREATE を受け取って即処理をしていたので、 ファイルの中身がまだないことがあって、ハマりました)。
おまけ
さて、上記のように mv コマンドは、同じファイルシステムであれば 移動し、別ファイルシステムであればコピーして削除します。 が、昔の Unix では、別ファイルシステムの場合はエラーでした。 移動できないからですね。
勝手にコピーして削除してくれるようになったのは便利ですが、 時々その裏側を忘れてしまって、今回のようにハマることがあります。 注意しましょう...