DockerfileでENTRYPOINT、CMDの挙動を動かしながら理解する

Docker,Kubernetes

はじめに

Dockerfile内で指定可能なコマンドはいくつかありますが、 ENTRYPOINT コマンドと CMD コマンドは初見ではわかりくいコマンドとなっています。

この2つのコマンドが、Dockerコンテナの実行にどのように影響するか、実行させながら理解していきたいと思います。

検証環境

$ uname -moi
x86_64 MacBookPro16,1 Darwin

$ docker --version
Docker version 19.03.13-beta2, build ff3fbc9d55

Dockerイメージ実行時の実行コマンドの組み立てロジック

今回はいきなり結論から入ります。

Dockerイメージ内で実行されるコマンドは、以下の3つの要素を使って組み立てられます。

  1. Dockerfile内の ENTRYPOINTの設定値
  2. docker run IMAGE_NAME コマンド実行時の コマンドライン引数
  3. Dockerfile内の CMDの設定値

2と3の両方が設定されている場合は、 2が優先され、3は無視 されます。

<ENTRYPOINTの設定値> <コマンドライン引数|CMDの設定値>

ちょっと分かりにくいと思うので、具体的な例を見ていきたいと思います。

Dockerfileに ENTRYPOINTCMD の両方が指定されている場合

ENTRYPOINTCMD の両方が指定されたDockerfileから、Dockerイメージを作成してみます。

# Dockerfileを作成
$ cat <<'EOF' >Dockerfile
FROM alpine:3.11.3

ENTRYPOINT ["seq"]

CMD ["1", "5"]
EOF

# my_docker_image_01 という名前のDockerイメージを作成
$ docker build -t my_docker_image_01 .

Dockerイメージを実行 (コマンドライン引数なし)

まずは作成されたDockerイメージを、イメージ名の後方に引数をつけずに実行してみます。

$ docker run my_docker_image_01
1
2
3
4
5

<ENTRYPOINTの設定値> <コマンドライン引数|CMDの設定値> という実行コマンド組み立てルールから、 seq 1 5 が実行されています。

Dockerイメージを実行 (コマンドライン引数あり)

今度はイメージ名の後方に引数を付与して実行してみます。

$ docker run my_docker_image_01 2 4
2
3
4

<ENTRYPOINTの設定値> <コマンドライン引数|CMDの設定値> という実行コマンド組み立てルールから、 seq 2 4 が実行されています。

CMD の設定値は無視され、 コマンドライン引数 のほうが優先されました。

Dockerfileに ENTRYPOINT だけが指定されている場合

ENTRYPOINT だけが指定されたDockerfileから、Dockerイメージを作成してみます。

# Dockerfileを作成
$ cat <<'EOF' >Dockerfile
FROM alpine:3.11.3

ENTRYPOINT ["seq"]
EOF

# my_docker_image_02 という名前のDockerイメージを作成
$ docker build -t my_docker_image_02 .

Dockerイメージを実行 (コマンドライン引数なし)

$ docker run my_docker_image_02
BusyBox v1.31.1 () multi-call binary.

Usage: seq [-w] [-s SEP] [FIRST [INC]] LAST

Print numbers from FIRST to LAST, in steps of INC.
FIRST, INC default to 1.

        -w      Pad to last with leading zeros
        -s SEP  String separator

<ENTRYPOINTの設定値> <コマンドライン引数|CMDの設定値> という実行コマンド組み立てルールから、 seq が実行されています。

seqコマンドは引数が必須のため、エラーが発生したというわけです。

Dockerイメージを実行 (コマンドライン引数あり)

今度はイメージ名の後方に引数を付与して実行してみます。

$ docker run my_docker_image_02 2 3
2
3

<ENTRYPOINTの設定値> <コマンドライン引数|CMDの設定値> という実行コマンド組み立てルールから、 seq 2 3 が実行されています。

Dockerfileに CMD だけが指定されている場合

CMD だけが指定されたDockerfileから、Dockerイメージを作成してみます。

ただし、今回は先程のCMDの設定とは異なる値としています。

# Dockerfileを作成
$ cat <<'EOF' >Dockerfile
FROM alpine:3.11.3

CMD ["seq", "1", "5"]
EOF

# my_docker_image_03 という名前のDockerイメージを作成
$ docker build -t my_docker_image_03 .

Dockerイメージを実行 (コマンドライン引数なし)

$ docker run my_docker_image_03
1
2
3
4
5

<ENTRYPOINTの設定値> <コマンドライン引数|CMDの設定値> という実行コマンド組み立てルールから、 seq 1 5 が実行されています。

ENTRYPOINTの設定値 が空なので、CMDだけで実行コマンドが組み立てられました。

Dockerイメージを実行 (コマンドライン引数あり)

コマンドライン引数を付与して実行してみますが、こちらも先程までと少し異なっている点に注意しましょう。( seq の文字が含まれています。 )

$ docker run my_docker_image_03 seq 2 3
2
3

<ENTRYPOINTの設定値> <コマンドライン引数|CMDの設定値> という実行コマンド組み立てルールから、 seq 2 3 が実行されています。

やはり ENTRYPOINTの設定値 が空なので、 コマンドライン引数 だけで実行コマンドが組み立てられました。

ひとこと

この仕組みは、 Docker ComposeKubernetes の設定時にも理解しておく必要があります。

Docker,Kubernetes