13
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Linkbal(リンクバル)Advent Calendar 2023

Day 19

DockerfileのENTRYPOINTとCMDの違いは何でしょうか。

Posted at

Docker では、ENTRYPOINT と CMD が Dockerfile内で使用され、両方ともコンテナー内で実行するコマンドを定義します。 コンテナ起動の際に指定したコマンドがコンテナ内で実行されることになります。

どちらも同じ用途で使われてるようですが、それぞれの違いは何だろうかこちら記事で明確にしようと思います。

ENTRYPOINT

ENTRYPOINTは、コンテナが起動されるときに実行されるコマンドを指定します。このコマンドは、docker runで--entrypointフラグを使用しない限り、実行時に上書きすることはできません。
ENTRYPOINTのベストな使い方は、イメージにおけるメインコマンドの設定することです。

# Dockerfile
FROM ubuntu
ENTRYPOINT ["echo", "Hello"]

このイメージからコンテナを実行すると、echo Helloコマンドが実行されます。

$ docker build . -t test_image
$ docker run test_image

# Output: 

Hello

CMD

一方、CMDはコンテナのデフォルトのコマンドまたはパラメータを設定します。ENTRYPOINTとは異なり、CMDが定義するコマンドは引数としてdocker runに渡すことで上書きすることができます。

# Dockerfile
FROM ubuntu
CMD ["echo", "World"]

こちらで、CMDしか利用されない場合、CMDが指定したコマンドはデフォルトコマンドとして実行されます。逆に、docker runに引数を渡すなら、このコマンドが上書きされる。

$ docker build . -t test_image
$ docker run test_image

# Output: 

World

$ docker run test_image echo Universe

# Output: 

Universe

ENTRYPOINTとCMDが結合される際に、CMDが指定しているものがENTRYPOINTのコマンドのデフォルト引数となります。

下記の定義はコンテナが起動されると、echo Hello Worldが実行されます。

ENTRYPOINTとCMDの組み合わせ:

# Dockerfile
FROM ubuntu
ENTRYPOINT ["echo", "Hello"]
CMD ["World"]
$ docker build . -t test_image
$ docker run test_image

# Output: 

Hello World

こちらの場面で、このイメージからコンテナを実行し(docker run)、Goodbyeのような引数を指定すると、コマンドはecho Hello Goodbyeになります。

$ docker build . -t test_image
$ docker run test_image Goodbye

# Output: 

Hello Goodbye

問題になるのは

ENTRYPOINTとCMDが結合される際に、CMDが指定しているコマンドを独自のコマンドとして実行したいときに、どうすれば良いでしょうか。

例えば、こちらのDockerfileのCMDにコマンドを定義したいですが、docker runを実行すると、ENTRYPOINTが指定しているEchoコマンドの引数になってしまいます。

ENTRYPOINTとCMDの組み合わせ:

# Dockerfile
FROM ubuntu
ENTRYPOINT ["echo", "Hello"]
CMD ["echo", "World"]

コンテナを起動するとき、echo Hello echo Worldコマンドが実行されてしまいます。

$ docker build . -t test_image
$ docker run test_image

# Output: 

Hello echo World

対策

CMDが指定するコマンドがENTRYPOINTのコマンドの引数に追加されることになっている前提で、
もし、ENTRYPOINTが指定するコマンドは引数部分を子コマンドのように実行できれば解決できます。

カスタマイズなbashファイルを作成。ENTRYPOINTのコマンドに入れる。

  • entrypoint.sh file
#!/bin/sh

echo "Hello"

exec "$@" # 何かのコマンドをBashシェルスクリプトの最後で実行したいとき、execを利用する。
  • Dockerfile
From ubuntu
COPY . .
RUN chmod +x entrypoint.sh # 実行権限を付与
ENTRYPOINT ["./entrypoint.sh"]
CMD ["echo", "World"]
$ docker build . -t test_image
$ docker run test_image

# Output: 

Hello
World

なぜか、こちらの結果が出てくるか調べてみます。

ENTRYPOINTとCMDの結合により、上記にDockerfileでイメージをdocker runを実行すると、./entrypoint.sh echo Worldのコマンドが実行されます。

そちらのコマンドの引数はentrypoint.shのスクリプト内で読み込める変数はこちら表となります。

$0 : entrypoint.sh
$1 : echo
$2 : World
$@ : echo World

なので、entrypoint.shのフィアルの最後に実行するexec "$@"echo Worldコマンドとなります。
echo "Hello"とecho "World"と合わせて、"Hello World"の結果を出力しました。

こちらで、Dockerfile内のENTRYPOINTとCMDの違いについて、ある程度理解できたとおもいます。ご質問やご不明な点がございましたら、お気軽にコメントください。

13
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?