ようへいの日々精進XP

よかろうもん

Dockerfile で VOLUME を使う際の注意点 〜 VOLUME 指定したパスではファイルを更新出来ない 〜

あけましておめでとうございます

今年も宜しくお願い致します。

tl;dr

WordPress の公式 Docker イメージを利用して Dockerfile を書いていたら、コンテナ内の /var/www/html 以下でファイルの操作が出来なかったので、なぜだろうと思って調べたのでメモしておきます。

Dockerfile

あれーっ

以下のような Dockerfile を書いていました。

FROM wordpress:5.6.0

ADD test.txt /var/www/html/test.txt
RUN echo "xxxxxxxxxxxxxxxxxxxxxxxxx" >> /var/www/html/test.txt

ビルドしてコンテナを起動すると、以下のような結果となることを期待していました。

$ docker build -t docker-sandbox . && echo "-------" && docker run --rm docker-sandbox:latest cat /var/www/html/test.txt
(ビルドの様子)
-------
xxxxxxxxxxxxxxxxxxxxxxxxx

実際に実行してみると、以下のように出力されました。

$ docker build -t docker-sandbox . && echo "-------" && docker run --rm docker-sandbox:latest cat /var/www/html/test.txt
Sending build context to Docker daemon   2.56kB
Step 1/3 : FROM wordpress:5.6.0
 ---> bc5f6567b763
Step 2/3 : ADD test.txt /var/www/html/test.txt
 ---> Using cache
 ---> 271e40aceba6
Step 3/3 : RUN echo "xxxxxxxxxxxxxxxxxxxxxxxxx" >> /var/www/html/test.txt
 ---> Using cache
 ---> 5d26f3ec24c6
Successfully built 5d26f3ec24c6
Successfully tagged docker-sandbox:latest
-------

あれーっと思って、docker history でコマンドのビルド履歴を見てみると、以下のように xxxxxxxxxxxxxxxxxxxxxxxxx の書き込みで SIZE が 0B となっていることに気づきました。

$ docker history docker-sandbox:latest | less
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
5d26f3ec24c6        6 minutes ago       /bin/sh -c echo "xxxxxxxxxxxxxxxxxxxxxxxxx" …   0B
271e40aceba6        6 minutes ago       /bin/sh -c #(nop) ADD file:bd8c9270f5699bc59…   0B
bc5f6567b763        2 weeks ago         /bin/sh -c #(nop)  CMD ["apache2-foreground"]   0B
<missing>           2 weeks ago         /bin/sh -c #(nop)  ENTRYPOINT ["docker-entry…   0B
()

おお。

なんだろう、/var/www/html ディレクトリに何か特殊なことをしているのだろうか... ということで、WordPress コンテナイメージの Dockerfile を見てみました。

WordPress コンテナイメージの Dockerfile を見てみる

github.com

以下のように、/var/www/html パスが VOLUME 指定されていました。

()
    chmod -R 777 wp-content

VOLUME /var/www/html

COPY docker-entrypoint.sh /usr/local/bin/

ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["%%CMD%%"]

ほうほう、VOLUME 指定していると、そのパスは何か特殊なことが起きるようです。

VOLUME を指定すると

ドキュメント

Dockerfile のリファレンスを見てみましょう。

docs.docker.com

Changing the volume from within the Dockerfile

以下のように記述されていました。

If any build steps change the data within the volume after it has been declared, those changes will be discarded.

日本語訳すると、以下の通りです。

ビルドステップでボリューム内のデータが宣言された後に変更された場合、その変更は破棄されます。

なるほど、なるほど。

今回だと、すでに WordPress コンテナをビルドする際に VOLUME /var/www/html が指定されている為、Dockerfile 内で /var/www/html 以下のファイルを操作 (ファイルに文字列を上書き) しようとしても操作が出来なったというオチですね。

完全に理解した... というわけではありません... なぜ、Dockerfile 内で VOLUME を指定した以降、その指定されたパスでの変更が破棄されるのか、その理由を知りたくて、ドキュメントを漁ったり、Docker のソースコード (buildkitmoby) をななめ読みしてみたりしましたが、理由は解らず、自分の Docker 力の無さに凹みました。

とりあえず、今は、これは仕様ということで理解しておきます。

参考

docs.docker.com

docs.docker.com

www.lewuathe.com