Docker の CMD と ENTRYPOINT の違い
さまざまな環境でのソフトウェアと依存関係の管理に関しては、Docker コンテナーが標準になっています。実際のアプリケーションで作業する場合は、アプリケーションコンテナイメージをビルドする前に、Docker ファイルを作成する必要があります。
Docker ファイルは、イメージをアセンブルするときに呼び出される一連の命令を含む、単なる読み取り専用のテキストドキュメントです。これらのコマンドには、RUN
、CMD
、および ENTRYPOINT
が含まれます。
この記事では、これらのコマンドの使用法について説明します。Docker の学習の初期段階にあると思われるほとんどの開発者は、これらのコマンドを同じ意味で使用する傾向があり、問題が発生する可能性があります。
Docker の CMD
コマンド
このコマンドは、dockerRUN
コマンドが実行されるたびに実行される命令を指定します。ただし、これには、引数を指定せずに dockerRUN
コマンドを実行する必要があります。
引数を指定すると、このコマンドは上書きされます。一方、コマンドライン引数が指定されていない場合、CMD
コマンドが実行されます。
ECHO
コマンドは実行時に同じ目的を果たすために使用できるため、CMD
コマンドは Docker コンテナーが正しく機能するために必須ではありません。ただし、コンテナが起動するたびに実行可能ファイルを実行する場合は、CMD
コマンドが便利です。
CMD
コマンドを使用して実行時に実行可能ファイルを実行する方法を示すために、メッセージを出力する単純なフラスコプログラムを使用して単純な Docker コンテナーを作成します。これは、必ずしも Python でなくても、任意の言語で複製できることに注意してください。
まず、メインアプリケーションを作成します。これは、以下に示すように単純なものにする必要があります。
from flask import Flask
app = Flask(__name__)
def hello():
print("Hello, this is a simple Flask application")
hello()
同じフォルダ内で、コマンド touch Dockerfile
を使用して Dockerfile を作成します。
Dockerfile は、ベースイメージ、作業ディレクトリ、およびインストールする必要のあるパッケージのみを指定します。
最後の行で、CMD
コマンドに注意する必要があります。この場合、コンテナの起動時に CMD
コマンドを使用して app.py
ファイルを実行しています。
# base image
FROM python
# Set your working directory
WORKDIR /var/www/
# Copy the necessary files
COPY ./app.py /var/www/app.py
COPY ./requirements.txt /var/www/requirements.txt
# Install the necessary packages
RUN pip install -r /var/www/requirements.txt
# Run the app
CMD python3 app.py
requirements.txt
は次のように表示されます。
click==8.0.4
Flask==2.0.3
gunicorn==20.1.0
itsdangerous==2.1.0
Jinja2==3.0.3
MarkupSafe==2.1.0
Werkzeug==2.0.3
すべての準備が整ったので、Docker イメージを作成できます。その前に、プログラムが保存されているのと同じフォルダーにいることを確認する必要があります。
この例では、以下に示すように、イメージをビルドする前に、cd
を my-app
フォルダーに入れます。
~/my-app$ docker build -t isaactonyloi_image .
出力:
=> [internal] load build context 0.9s
=> => transferring context: 320B 0.1s
=> [2/5] WORKDIR /var/www/ 5.1s
=> [3/5] COPY ./app.py /var/www/app.py 3.2s
=> [4/5] COPY ./requirements.txt /var/www/requirements.txt 3.2s
=> [5/5] RUN pip install -r /var/www/requirements.txt 53.9s
=> exporting to image 6.9s
=> => exporting layers 5.8s
=> => writing image sha256:5847e4777754d9d576accd929076bfbee633ca71f049ebe1af6e9bae161f3e96 0.1s
=> => naming to docker.io/library/isaactonyloi_image 0.2s
isaac@DESKTOP-HV44HT6:~/my-app$
以前の docker ファイルに基づいてイメージを正常に構築しました。以下で確認できます。
~/my-app$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
isaactonyloi_image latest 5847e4777754 7 minutes ago 929MB
このイメージに基づいて dockerrun
コマンドを使用して、最終的に docker コンテナーを作成できます。また、CMD
コマンドを実行するための引数を渡さずにこれを行うことに注意してください。
~/my-app$ docker run isaactonyloi_image
Hello, this is a simple Flask application
これに加えて、CMD
コマンドを使用すると、実行時に簡単にオーバーライドできる引数を作成することもできます。
以下の例では、CMD
コマンドに変更を加えました。他のファイルはそのまま残り、新しいイメージを再構築しました。
# base image
FROM python
# Set your working directory
WORKDIR /var/www/
# Copy the necessary filesls
COPY ./app.py /var/www/app.py
COPY ./requirements.txt /var/www/requirements.txt
# Install the necessary packages
RUN pip install -r /var/www/requirements.txt
# Run the app
CMD ["echo", "Hello, Developer"]
これは、Dockerfile への変更から再構築した新しいイメージです。
~/my-app$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
new_image latest 73f323be0d2f 25 minutes ago 929MB
引数を渡さずに新しい Docker コンテナを再度作成すると、CMD
コマンドでメッセージが表示されます。
isaac@DESKTOP-HV44HT6:~/my-app$ docker run new_image
Hello, Developer
ただし、実行時に引数を渡すと、CMD
コマンドが自動的に上書きされるため、新しい引数が優先されます。したがって、以下に示すように、実行時に新しい引数を追加する柔軟性が得られます。
~/my-app$ docker run new_image hostname
da0a832888cb
上記の出力は、CMD
コマンドが実行されず、新しいホスト名引数によってオーバーライドされないことを示しています。
Docker の ENTRYPOINT
コマンド
docker の ENTRYPOINT
コマンドは CMD
コマンドと類似していますが、完全に同じというわけではありません。
CMD
コマンドを使用する場合、実行時に引数を渡すことで簡単にオーバーライドできますが、ENTRYPOINT
コマンドの場合はそうではありません。
したがって、ENTRYPOINT
を使用して、実行時にエントリポイント命令を上書きしないようにすることができます。
以下に示すように、Dockerfile で CMD
コマンドを ENTRYPOINT
コマンドに置き換えるだけで、このコマンドがどのように機能するかを調べることができます。Docker ファイルへの変更に基づいて新しいイメージを作成します。
isaac@DESKTOP-HV44HT6:~/my-app$ docker build -t tonyloi_newimage .
[+] Building 42.7s (10/10) FINISHED
出力:
=> [internal] load build definition from Dockerfile 2.0s
=> => transferring dockerfile: 365B 0.7s
=> [internal] load .dockerignore 1.6s
=> => transferring context: 2B 0.4s
=> [internal] load metadata for docker.io/library/python:latest 35.4s
=> [1/5] FROM docker.io/library/python@sha256:c90e15c86e2ebe71244a2a51bc7f094554422c159ce309a6faadb6debd5a6df0 0.3s
=> [internal] load build context 1.2s
=> => transferring context: 63B 0.1s
=> CACHED [2/5] WORKDIR /var/www/ 0.0s
=> CACHED [3/5] COPY ./app.py /var/www/app.py 0.0s
=> CACHED [4/5] COPY ./requirements.txt /var/www/requirements.txt 0.0s
=> CACHED [5/5] RUN pip install -r /var/www/requirements.txt 0.0s
=> exporting to image 2.1s
=> => exporting layers 0.0s
=> => writing image sha256:15fb8e4e3ff58ed529b11342bba75b029fd4323beb24aac70ca36b178d04cb34 0.2s
=> => naming to docker.io/library/tonyloi_newimage 0.1s
isaac@DESKTOP-HV44HT6:~/my-app$
この出力は、新しいイメージの作成に成功したことの証です。これで、このイメージに基づいて新しい Docker コンテナを作成できます。
イメージ名またはイメージ ID を使用してコンテナーを作成することを選択できます。どちらも、docker images
コマンドを使用してアクセスできます。これにより、以前に作成したイメージも表示されます。
~/my-app$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tonyloi_newimage latest 15fb8e4e3ff5 48 minutes ago 929MB
new_image latest 73f323be0d2f 48 minutes ago 929MB
isaactonyloi_image latest 5847e4777754 48 minutes ago 929MB
引数を追加せずに Docker コンテナを構築すると、次のような出力が得られるはずです。
isaac@DESKTOP-HV44HT6:~/my-app$ docker run tonyloi_newimage
Hello, Developer
このイメージに基づいて別のコンテナーを作成するときに引数を渡そうとすると、CMD
コマンドの場合とは異なり、これらの新しい引数は ENTRYPOINT
コマンドをオーバーライドしないことに注意してください。
これは以下で確認できます。
isaac@DESKTOP-HV44HT6:~/my-app$ docker run tonyloi_newimage Welcome to ADC
Hello, Developer Welcome to ADC
まとめ
これらの 2つのコマンドは非常に似ていると言えます。ただし、それらの違いは、CMD
コマンドは実行時にオーバーライドできますが、ENTRYPOINT
コマンドはオーバーライドできないことです。
また、状況によっては、2つのコマンドを同時に使用する必要がある場合があります。
Isaac Tony is a professional software developer and technical writer fascinated by Tech and productivity. He helps large technical organizations communicate their message clearly through writing.
LinkedIn