Dockerfilesには、CMD
とENTRYPOINT
という似たような2つのコマンドがあります。しかし、これらの間には(微妙な?)違いがあると思います。そうでなければ、全く同じことをするために2つのコマンドを用意する意味がありません。
ドキュメントによると、CMD
は
gt; CMDの主な目的は、実行中のコンテナにデフォルトを提供することです。
また、ENTRYPOINT
についても書かれています。
ENTRYPOINTは、実行可能なコンテナを設定するためのものです。
では、この2つのコマンドの違いは何でしょうか?
Dockerには、デフォルトのエントリーポイントとして/bin/sh -c
がありますが、デフォルトのコマンドはありません。
次のようにdockerを実行すると、次のようになります。
docker run -i -t ubuntu bash。 のように実行すると、エントリーポイントはデフォルトの
/bin/sh -cで、イメージは
ubuntu、コマンドは
bash` となります。
コマンドはエントリーポイント経由で実行されます。つまり、実際に実行されるのは /bin/sh -c bash
です。これにより、Dockerはシェルのパーサーに頼ることで、RUN
を素早く実装することができました。
その後、これをカスタマイズできるようにしてほしいという要望が出てきたので、ENTRYPOINT
と--entrypoint
が導入されました。
上の例では、ubuntu
以降がコマンドで、エントリポイントに渡されます。CMDという命令を使うと、まさに
docker run -i -t ubuntu とやっているのと同じです。<cmd>
はエントリポイントのパラメータになります。
また、代わりにこのコマンド docker run -i -t ubuntu
を入力しても同じ結果になります。ubuntu Dockerfile]1ではデフォルトのCMDとしてCMD ["bash"]
を指定しているので、コンテナ内でbashシェルを起動することになります。
エントリポイントにすべてが渡されるので、イメージから非常に素晴らしい動作を得ることができます。@Jiriの例は、画像を「バイナリ」として使用する方法を示しています。エントリポイントとして["/bin/cat"]を使い、
docker run img /etc/passwdとすると、
/etc/passwdがコマンドとなり、エントリポイントに渡されるので、最終的な実行結果は単純に
/bin/cat /etc/passwd`となります。
他の例としては、任意の cli をエントリポイントにすることができます。例えば、Redisのイメージがある場合、docker run redisimg redis -H something -u toto get key
を実行する代わりに、ENTRYPOINT ["redis", "-H", "something", "-u", "toto"]
を設定し、以下のように実行すると、同じ結果が得られます: docker run redisimg get key
.
ENTRYPOINT`では、コンテナの起動時に必ず実行されるコマンドを指定します。
CMDでは、
ENTRYPOINT`に与える引数を指定します。
特定のコマンド専用のイメージを作成したい場合は、ENTRYPOINT ["/path/dedicated_command"]
を使用します。
また、汎用的なイメージを作りたい場合には、ENTRYPOINT
を指定せずに、CMD ["/path/dedicated_command"]
を使用します。
例えば、Dockerfileが次のような場合。
FROM debian:wheezy
ENTRYPOINT ["/bin/ping"]
CMD ["localhost"]
このイメージを引数なしで実行すると、localhostにpingを行います。
$ docker run -it test
PING localhost (127.0.0.1): 48 data bytes
56 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.096 ms
56 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.088 ms
56 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.088 ms
^C--- localhost ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.088/0.091/0.096/0.000 ms
ここで、引数を指定してイメージを実行すると、その引数にpingが実行されます。
$ docker run -it test google.com
PING google.com (173.194.45.70): 48 data bytes
56 bytes from 173.194.45.70: icmp_seq=0 ttl=55 time=32.583 ms
56 bytes from 173.194.45.70: icmp_seq=2 ttl=55 time=30.327 ms
56 bytes from 173.194.45.70: icmp_seq=4 ttl=55 time=46.379 ms
^C--- google.com ping statistics ---
5 packets transmitted, 3 packets received, 40% packet loss
round-trip min/avg/max/stddev = 30.327/36.430/46.379/7.095 ms
比較のために、あなたのDockerfileが
FROM debian:wheezy
CMD ["/bin/ping", "localhost"]
このイメージを引数なしで実行すると、ローカルホストにpingを行います。
$ docker run -it test
PING localhost (127.0.0.1): 48 data bytes
56 bytes from 127.0.0.1: icmp_seq=0 ttl=64 time=0.076 ms
56 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.087 ms
56 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.090 ms
^C--- localhost ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.076/0.084/0.090/0.000 ms
しかし、引数を指定してイメージを実行すると、引数を実行します。
docker run -it test bash
root@e8bb7249b843:/#
さらに詳しくは、Brian DeHamer氏のこの記事をご覧ください。 https://www.ctl.io/developers/blog/post/dockerfile-entrypoint-vs-cmd/
はい、それはいい質問ですね。まだ完全には理解していませんが。
ENTRYPOINT`が実行されているバイナリであることは理解しています。--entrypoint=""でentrypointを上書きすることができます。
docker run -t -i --entrypoint="/bin/bash" ubuntu
CMDはコンテナのデフォルト引数です。エントリポイントがない場合、デフォルトの引数は実行されるコマンドです。エントリポイントがある場合、cmdは引数としてエントリポイントに渡されます。エントリポイントでコマンドをエミュレートできます。
# no entrypoint
docker run ubuntu /bin/cat /etc/passwd
# with entry point, emulating cat command
docker run --entrypoint="/bin/cat" ubuntu /etc/passwd
つまり、主な利点は entrypoint でコンテナに引数 (cmd) を渡すことができることです。これを実現するには、両方を使用する必要があります。
# Dockerfile
FROM ubuntu
ENTRYPOINT ["/bin/cat"]
と
docker build -t=cat .
であれば、使用することができます。
docker run cat /etc/passwd
# ^^^^^^^^^^^
# CMD
# ^^^
# image (tag)- using the default ENTRYPOINT