🐷

Docker のオフィシャル・イメージから CMD と ENTRYPOINT の使い分け学ぶ

2022/09/11に公開

Dockerhub に掲載されているオフィシャル・イメージから、CMD と ENTRYOINT がどのように使われているか学びましょう。

オフィシャル・イメージの Dockerfile を見て構築方法を理解したい!

こちらのリンクをクリックして、さらに各オフィシャル・イメージのページに飛び、 そこに下の画像のようにDockerfile links とか書かれているセクションがあれば、リンク先の Dockerfile に飛べます。

(以下は画像です、クリックできません。)

Supported-Dockerfile-links.png

本記事の内容がわかりづらい場合、「コピペで学ぶチュートリアル: Dockerfile の CMD と ENTRYPOINT の違い」に沿って、自分でコピペしながら CMD と ENTRYPOINT の動作確認をすると、わかりやすくなるかもしれません。その後でも本記事がわかりづらければ、私の責任です。ごめんなさい。

nginx

以下のコマンドを実行してください
docker pull nginx
docker inspect nginx
コマンド実行結果
"Cmd": [
    "nginx",
    "-g",
    "daemon off;"
],
"Entrypoint": [
    "/docker-entrypoint.sh"
],

CMD はデフォルト引数だけではなく、nginxコマンド自体も指定している CMD ["executable", "param1", "param2"…] という形式なので、Docker 公式ドキュメントの Best practices for writing Dockerfilesに従っています。

The CMD instruction should be used to run the software contained in your image, along with any arguments. CMD should almost always be used in the form of CMD ["executable", "param1", "param2"…].

ENTRYPOINT はdocker-entrypoint.shというシェルスクリプトであり、nginx を実行する前の configuration を行っているようです。docker runに追加の引数を何も与えなければ、ENTRYPOINT と CMD の組み合わせにより /docker-entrypoint.sh nginx -g daemon off;というコマンドが実行され、configuration の後に nginx が立ち上がります。

httpd

以下のコマンドを実行してください
docker pull httpd
docker inspect httpd
"Cmd": [
    "httpd-foreground"
],
"Entrypoint": null,

CMD はhttpd-foregroundコマンド自体を指定している CMD ["executable", "param1", "param2"…] という形式なので、Docker 公式ドキュメントの Best practices for writing Dockerfilesに従っています。

The CMD instruction should be used to run the software contained in your image, along with any arguments. CMD should almost always be used in the form of CMD ["executable", "param1", "param2"…].

そして ENTRYPOINT は null です。こちらもBest practicesのとおり、「イメージのユーザーが ENTRYPOINT の仕様を熟知していると期待できない場合、CMD ["param", "param"] と ENTRYPOINT の組み合わせを使わない」に従っていると従っていると言えます。

CMD should rarely be used in the manner of CMD ["param", "param"] in conjunction with ENTRYPOINT, unless you and your expected users are already quite familiar with how ENTRYPOINT works.

python

以下のコマンドを実行してください
docker pull python
docker inspect python
"Cmd": [
    "python3"
],
"Entrypoint": null,

CMD はインタラクティブなシェルを立ち上げるpython3コマンドなので、Docker 公式ドキュメントの Best practices for writing Dockerfilesに従っています。

In most other cases, CMD should be given an interactive shell, such as bash, python and perl. For example, CMD ["perl", "-de0"], CMD ["python"], or CMD ["php", "-a"].

ENTRYPOINT は null です。こちらもBest practicesのとおり、「イメージのユーザーが ENTRYPOINT の仕様を熟知していると期待できない場合、CMD ["param", "param"] と ENTRYPOINT の組み合わせを使わない」に従っていると従っていると言えます。

CMD should rarely be used in the manner of CMD ["param", "param"] in conjunction with ENTRYPOINT, unless you and your expected users are already quite familiar with how ENTRYPOINT works.

golang

以下のコマンドを実行してください
docker pull golang
docker inspect golang
"Cmd": [
    "bash"
],
"Entrypoint": null,

ENTRYPOINT は null です。

興味深いことに、golang のイメージは何も引数を与えずにdocker run golangすると、CMD に指定されたbashを実行して、即時終了します。Go のインタラクティブなシェルは立ち上げません。先程の Python のイメージとは流儀が異なっています。Go でインタラクティブなシェルを使うにはgoコマンドではなく、 https://github.com/x-motemen/gore のようなツールを使うからでしょうか?

golang イメージ自体を直接docker run golangする想定ではなく、下記のようにベースイメージとして golang を使い、ビルドコンテナとしてgo buildを行った後、CMD(もしくは ENTRYPOINT)を指定することを前提としていると考えると良さそうです。

FROM golang
...
RUN go build -o /some-exec-path
CMD ["/some-exec-path", "param1", "param2"]

golang イメージを使った Go のビルド方法は、公式ドキュメントの Build your Go image ページに説明があります。

openjdk

以下のコマンドを実行してください
docker pull openjdk
docker inspect openjdk
"Cmd": [
    "jshell"
],
"Entrypoint": null,

ENTRYPOINT は null です。

CMD はインタラクティブなシェルを立ち上げるjshellコマンドなので、Docker 公式ドキュメントの Best practices for writing Dockerfilesに従っています。

In most other cases, CMD should be given an interactive shell, such as bash, python and perl. For example, CMD ["perl", "-de0"], CMD ["python"], or CMD ["php", "-a"].

以下のコマンドを実行してください
docker run --rm oepnjdk
INFO: Created user preferences directory.
|  Welcome to JShell -- Version 18.0.2.1
|  For an introduction type: /help intro

jshell> %

openjdk イメージは Java のビルドに使えますが、先程の golang とは違って CMD の形式になっているのが興味深いですね。

gradle

以下のコマンドを実行してください
docker pull gradle
docker inspect gradle
"Cmd": [
    "gradle"
],
"Entrypoint": null,

CMD はgradleコマンド自体を指定している CMD ["executable", "param1", "param2"…] という形式なので、Docker 公式ドキュメントの Best practices for writing Dockerfilesに従っています。

The CMD instruction should be used to run the software contained in your image, along with any arguments. CMD should almost always be used in the form of CMD ["executable", "param1", "param2"…].

gradleコマンドはビルドを実行すると終了するので、インタラクティブなシェルを立ち上げるコマンドではありません。

golang, openjdk, gradle と、Dockerfile のFROMで指定するベースイメージとして、ソースコードをビルドする際に使えるオフィシャル・イメージを見てきましたが、CMD の指定については三者三様ですね。

ubuntu

以下のコマンドを実行してください
docker pull ubuntu
docker inspect ubuntu
"Cmd": [
    "bash"
],
"Entrypoint": null,

Dockerfile のFROMで指定するベースイメージとしての利用が一番多いと思われるので、CMD としてbashのみが指定されています。イメージを使うユーザーが CMD や ENTRYPOINT を上書きすることが前提と考えてよいでしょう。

centos

以下のコマンドを実行してください
docker pull centos
docker inspect centos
"Cmd": [
    "/bin/bash"
],
"Entrypoint": null,

ubuntu 同様、Dockerfile のFROMで指定するベースイメージとしての利用が一番多いと思われるので、CMD としてbashのみが指定されています。イメージを使うユーザーが CMD や ENTRYPOINT を上書きすることが前提と考えてよいでしょう。

mysql

以下のコマンドを実行してください
docker pull mysql
docker inspect mysql
"Cmd": [
    "mysqld"
],
"Entrypoint": [
    "docker-entrypoint.sh"
],

CMD はデフォルト引数だけではなく、mysqldコマンド自体を指定している CMD ["executable", "param1", "param2"…] という形式なので、Docker 公式ドキュメントの Best practices for writing Dockerfilesに従っています。

The CMD instruction should be used to run the software contained in your image, along with any arguments. CMD should almost always be used in the form of CMD ["executable", "param1", "param2"…].

ENTRYPOINT はdocker-entrypoint.shというシェルスクリプトであり、内容が難しくてよくわからなかったのですが… mysqld を実行する前の事前準備を行っているのでは?と私は思っています。docker runに追加の引数を何も与えなければ、ENTRYPOINT と CMD の組み合わせにより docker-entrypoint.sh mysqldというコマンドが実行され、docker-entrypoint.sh(による事前準備と思われる処理)の後にmysqldが立ち上がります。

postgres

以下のコマンドを実行してください
docker pull postgres
docker inspect postgres
"Cmd": [
    "postgres"
],
"Entrypoint": [
    "docker-entrypoint.sh"
],

CMD はデフォルト引数だけではなく、postgresコマンド自体を指定している CMD ["executable", "param1", "param2"…] という形式なので、Docker 公式ドキュメントの Best practices for writing Dockerfilesに従っています。

The CMD instruction should be used to run the software contained in your image, along with any arguments. CMD should almost always be used in the form of CMD ["executable", "param1", "param2"…].

ENTRYPOINT はdocker-entrypoint.shというシェルスクリプトであり、内容が難しくてよくわからなかったのですが… postgres を実行する前の事前準備を行っているのでは?と私は思っています。docker runに追加の引数を何も与えなければ、ENTRYPOINT と CMD の組み合わせにより docker-entrypoint.sh postgresというコマンドが実行され、docker-entrypoint.sh(による事前準備と思われる処理)の後にpostgresサーバーが立ち上がります。

memcached

以下のコマンドを実行してください
docker pull memcached
docker inspect memcached
"Cmd": [
    "memcached"
],
"Entrypoint": [
    "docker-entrypoint.sh"
],

CMD はデフォルト引数だけではなく、memcachedコマンド自体を指定している CMD ["executable", "param1", "param2"…] という形式なので、Docker 公式ドキュメントの Best practices for writing Dockerfilesに従っています。

The CMD instruction should be used to run the software contained in your image, along with any arguments. CMD should almost always be used in the form of CMD ["executable", "param1", "param2"…].

ENTRYPOINT はdocker-entrypoint.shというほぼ何もしていない?シェルスクリプトで、与えられたコマンドを実行するのみのようです。docker runに追加の引数を何も与えなければ、ENTRYPOINT と CMD の組み合わせにより docker-entrypoint.sh memcachedというコマンドが実行され、memcachedサーバーが立ち上がります。

wordpress

以下のコマンドを実行してください
docker pull wordpress
docker inspect wordpress
"Cmd": [
    "apache2-foreground"
],
"Entrypoint": [
    "docker-entrypoint.sh"
],

CMD はデフォルト引数だけではなく、apache2-foregroundコマンド自体を指定している CMD ["executable", "param1", "param2"…] という形式なので、Docker 公式ドキュメントの Best practices for writing Dockerfilesに従っています。

The CMD instruction should be used to run the software contained in your image, along with any arguments. CMD should almost always be used in the form of CMD ["executable", "param1", "param2"…].

ENTRYPOINT はdocker-entrypoint.shというシェルスクリプトで、おそらくは WordPress 立ち上げに必要は PHP の設定などを行っていると私は思っています。docker runに追加の引数を何も与えなければ、ENTRYPOINT と CMD の組み合わせにより docker-entrypoint.sh apache2-foregroundというコマンドが実行され、apache2-foregroundサーバーが立ち上がります。

GitHubで編集を提案

Discussion