チームのDockerfileを作成するときに…

Dockerfile

畑田です。
チームのDockerfileを作成するときに、できるだけdocker社の意図したものに近いわかりやすいものを作りたくてドキュメントを紐解いています。
一次情報の旨味を消さないように気をつけて書いています。

DockerfileのRUNCMDENTRYPOINTについて

RUN

RUNはビルド時(docker buildのとき)にコンテナ内で実行されます。
一つのDockerfileは複数のRUNを持ち、ビルドステップに応じて呼び出されます。
RUNの数だけレイヤー(中間生成コンテナ)が生成されるので少ないに越したことはないです。

CMD

CMDは完成したイメージからコンテナを作成するときに実行されます。
つまりdocker runの時に実行されます。
1つのDockerfileにつき1つのCMDが呼び出され、複数書いてあったとしても最後に書かれたものが実行されます。
ただし、docker runの引数としてcommandが指定されていた場合、これが最後のコマンドと捉えられ、これに上書きされてしまいます。

ENTRYPOINT

ENTRYPOINTCMD同様、イメージからコンテナを作成するときに実行されるのですが、ENTRYPOINTdocker runの引数のcommandに上書きされません。
ENTRYPOINTCMDと組み合わせて使います。
ENTRYPOINTCMDが両方書かれているとき、書く順番によらずENTRYPOINTを実行するコマンドとして、CMDをそのコマンドのargumentとして、実行されます。
ENTRYPOINTdocker container runの引数やdocker-compose.yml- commandに上書きされないがCMDは上書きされるという性質を利用して、引数のみを上書き可能にしたコマンドを用意することもできます。

DockerfileのVOLUMEについて

まず、Dockerfile内ではコンテナ側のdirectoryしか指定することができません。
これはいかなる環境においても同様の挙動をさせたいというDockerの設計思想による仕様です。
開発のためにボリュームをマウントしたい場合はdocker-composeを使うしかないようです。
おそらくdocker-composeを使っていないプロジェクトはあまりないのでそれほど問題にはならないですが、deployのときなどには気をつける必要があるかもしれません。

DockerfileのADDCOPYについて

ADDCOPYは機能が似ていますが、COPYが単にlocalのファイルをcontainerにコピーするだけなのに対して、ADDはtarファイルの展開やremote URLからのデータの取得をサポートしています。
したがって、localファイルのコピーを意図しているときにはより限定的な意味のCOPYを用いることがdockerによって推奨されています。
さらに、ADDによってremote URLを用いてリソースを取得することは非推奨とされており、curlwgetRUNコマンドによって実行することが推奨されます。
このため、ADDコマンドはtar展開を含んだcontainerへのリソース追加に適用することが推奨されていると考えられます。
この性質を知っていると、Dockerfileの可読性がぐんと上がりますが、そもそもこれを意識せず書かれたDockerfileが世に溢れており、却って生きづらくなるかもしれません。

DockerfileのCOPYにおける注意点

上の項目でも推奨しているCOPYについて、directoryをコピーするときに注意する必要があります。
まず、以下のようにファイルをコピーするときにはなんら問題は生じません。

COPY ./package*.json ./

しかし、次のようにdirectory自体をコピーしようとするときに問題は生じます。

COPY ./src/ ./

このように書いてしまうと、host machineの./src/の中身がcontainer machineの./のなかに展開されてコピーされてしまいます。(イメージはJavaScriptの[...data]です。違うか。)
つまり、container machineの./が空であれば、container machineの./はhost machineの./src/と全く同じものになるし、もともと中身が入っていればmergeされてしまうということです。
展開せずにcontainer machineの./の下に./srcとしてコピーしたい場合は以下のように記述してください。

COPY ./src/ ./src/

この仕様に若干の違和感があるのは、Linux系共通コマンドである以下のものと仕様が異なるからだと思います。

$ cp -r DIRECTORY_NAME DESTINATION

おすすめ

人気の投稿

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です