CMDとENTRYPOINTの違い

DockerfileCMD指令とENTRYPOINT指令は、コンテナ起動時に実行されるプログラム(コマンド)を指定する。(RUNはビルド時に実行される。)

両方を併用する場合、単独で使用する場合、コンテナ作成時にコマンド引数を渡す場合(docker createの後端のコマンド部分)、shell形式とexec形式の違いなどと、ケースによって動作が異なる。

結果として実行されるコマンドは、下記2や3のように組み合わせになるケースもある。以下の優先順で決まる。

  1. ENTRYPOINT(shell形式): (他はあっても無視)
  2. ENTRYPOINT(exec形式)の引数として、コンテナ作成時コマンド引数を付加
  3. ENTRYPOINT(exec形式)の引数として、CMDを付加
  4. ENTRYPOINT(exec形式)
  5. コンテナ作成時コマンド
  6. CMD

また、ENTRYPOINT--entrypointで変更可能。CMDENTRYPOINTも、複数回使っても最後の一つがそれぞれ有効。

これらを目的でこのように分類するとわかりやすい。


CMD単独

CMDは、コンテナ作成時に渡すコマンド引数で変更できるので、「変更可能なデフォルトコマンド」を指定したいときに単独で使う。

例としては、Linuxのベースイメージ(centos:7debian:9ubuntu:18.04など)ではCMD単独でbashが指定されていることが多い。

Dockerfile

FROM ubuntu:18.04

# コンテナ起動時のデフォルトのコマンドをdashにしたいとき
CMD ["/bin/dash"]

ビルド

docker build --tag test --no-cache .

コマンド付けずに起動

docker run --rm -it test
# コンテナシェルで
# どのシェルか確認
echo $0
/bin/dash

コマンド付加して起動

# bashに変更
docker run --rm -it test bash
# コンテナシェルで
# どのシェルか確認
echo $0
bash

ENTRYPOINT(shell形式)単独

ENTRYPOINTのshell形式を使うと、CMDやコンテナ作成時に渡すコマンド引数はあっても無視される。変更できないので、「実行必須コマンド」にしたいときに(単独で)使う。ただし--entrypointで変更可能。

Dockerfile

FROM ubuntu:18.04

# shell形式でdateコマンド
ENTRYPOINT date

# 下記はコンテナ起動時に無視される
CMD cat /etc/passwd

ビルド、起動

docker build -t test --no-cache .

# 別コマンドを付加しても無視され、dateが実行される
docker run --rm -it test cat /etc/passwd
Sun May 20 06:45:49 UTC 2018

# ただし、--entrypointなら変更できる
docker run --rm -it --entrypoint=grep test root /etc/passwd
root:x:0:0:root:/root:/bin/bash

ENTRYPOINT(exec形式)単独

ENTRYPOINTのexec形式を単独で使うと、コンテナ作成時に渡すコマンド引数があれば追加の引数として扱われるので、「引数を追加可能な実行必須コマンド」にしたいときに(単独で)使う。--entrypointで変更可能。

Dockerfile

FROM ubuntu:18.04

# exec形式でgrepコマンド
ENTRYPOINT ["grep", "root", "/etc/passwd"]

ビルド、起動

docker build -t test --no-cache .

# /etc/groupはgrepコマンドの追加引数になる
docker run --rm -it test /etc/group
/etc/passwd:root:x:0:0:root:/root:/bin/bash
/etc/group:root:x:0:

# --entrypointなら変更できる
docker run --rm -it --entrypoint=head test -1 /etc/os-release
NAME="Ubuntu"

CMDとENTRYPOINT(exec形式)併用

CMDENTRYPOINTのexec形式を併用した場合は、CMDENTRYPOINTの引数として扱われる。この引数は、コンテナ作成時に渡すコマンド引数で変更可能なので、「引数を変更可能な実行必須コマンド」にしたいときに使う。

この併用の場合はどちらもexec形式にすること。

Dockerfile

FROM ubuntu:18.04

# exec形式でgrepコマンド
ENTRYPOINT ["grep", "root"]

# ENTRYPOINTの引数扱い
CMD ["/etc/passwd"]

ビルド、起動

docker build -t test --no-cache .

# コマンド引数付加なし: CMDがデフォルトの引数
docker run --rm -it test
root:x:0:0:root:/root:/bin/bash

# コマンド引数付加: CMDは無視される
docker run --rm -it test /etc/group
root:x:0:

# --entrypointなら変更できる
docker run --rm -it --entrypoint=head test -1 /etc/os-release
NAME="Ubuntu"