コンテンツにスキップ

ENTRYPOINT vs CMD in Docker: Difference and Use Cases

チェック

  • [ ] 本文を確認した
  • [ ] 概要を確認した
  • [ ] タグを確認した
  • [ ] inbox/ 直下へ移行した

概要

Dockerfile の ENTRYPOINTCMD の違いを、上書き挙動、exec form/shell form、実用例で整理した記事。 ENTRYPOINT はコンテナの主実行ファイルを定義し、CMD はデフォルト引数またはデフォルトコマンドを定義する。 両方を組み合わせると、実行ファイルを固定しつつ、引数だけを docker run で差し替えられる。

本文

Dockerfile には、コンテナ起動時に実行されるコマンドを指定するために ENTRYPOINTCMD がある。 どちらも似て見えるが、役割と上書き方法が違う。

CMD の役割

CMD は、コンテナ起動時のデフォルトコマンドまたはデフォルト引数。 docker run の後ろにコマンドを指定すると、CMD は上書きされる。

FROM node:alpine
WORKDIR /app
COPY . .
RUN npm install

CMD ["node", "index.js"]

この image を普通に起動すると、node index.js が実行される。

docker run myimage

しかし、コマンドを指定すると CMD は置き換わる。

docker run myimage sh

この場合は node index.js ではなく sh が実行される。

ENTRYPOINT の役割

ENTRYPOINT は、コンテナの主実行ファイルを定義する。 docker run の後ろに引数を付けても、通常は ENTRYPOINT 自体は置き換わらず、その引数が entrypoint に渡される。

FROM node:alpine
WORKDIR /app
COPY . .
RUN npm install

ENTRYPOINT ["node", "index.js"]

この image では、コンテナは基本的に node index.js を実行するものとして扱われる。 別の entrypoint を使いたい場合は、--entrypoint で明示的に上書きする。

docker run --entrypoint sh myimage

ENTRYPOINT と CMD の組み合わせ

よく使うのは、ENTRYPOINT で実行ファイルを固定し、CMD でデフォルト引数を与える形。

FROM node:alpine
WORKDIR /app
COPY . .
RUN npm install

ENTRYPOINT ["node"]
CMD ["index.js"]

この image を普通に起動すると、node index.js が実行される。

docker run myimage

別のファイルを実行したい場合は、CMD 部分だけを上書きできる。

docker run myimage app.js

この場合は node app.js になる。 つまり、entrypoint は固定、引数は差し替え可能。

CLI ツールの container image では、この形が使いやすい。 たとえば ENTRYPOINT ["terraform"]CMD ["--help"] のようにすれば、デフォルトでは help を出し、docker run image planterraform plan を実行できる。

exec form と shell form

ENTRYPOINTCMD には exec form と shell form がある。

exec form は JSON 配列で書く。

ENTRYPOINT ["node"]
CMD ["index.js"]

この形式では、シェルを介さず直接プロセスが実行される。 PID 1 と signal handling の観点で安全。 コンテナ停止時の SIGTERM がアプリケーションへ届きやすい。

shell form は文字列で書く。

ENTRYPOINT node
CMD index.js

この場合、実際には /bin/sh -c 経由で実行される。 シェルが PID 1 になり、signal がアプリケーションへ届きにくくなることがある。 また、CMD との組み合わせや引数の扱いも直感的でない場合がある。

原則として、コンテナの主プロセスには exec form を使うのがよい。

wrapper script を ENTRYPOINT にする

ENTRYPOINT に script を指定することもある。 起動前に環境変数を確認したり、設定ファイルを生成したり、マイグレーションを実行したり、最後にアプリケーションを exec する。

COPY docker-entrypoint.sh /usr/local/bin/
ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["node", "index.js"]

script 側では、最後に exec "$@" とする。

#!/bin/sh
set -e

# 起動前処理

exec "$@"

exec を使うことで、最終的なアプリケーションプロセスが PID 1 になり、signal を正しく受け取れる。

使い分け

アプリケーション image で、常に同じアプリを起動したいなら ENTRYPOINT に主プロセス、CMD にデフォルト引数を置く。

デバッグや一時的なコマンド実行をしやすくしたいなら、CMD だけにする選択もある。 ただし、docker run image bash で簡単に上書きできるため、image の用途が曖昧になることもある。

CLI ツール image では、ENTRYPOINT にツール名、CMD--help やデフォルト引数を置くと使いやすい。

要点

  • CMD はデフォルトコマンドまたはデフォルト引数で、docker run のコマンド指定で上書きされる。
  • ENTRYPOINT はコンテナの主実行ファイルで、通常の引数指定では置き換わらない。
  • ENTRYPOINT ["node"]CMD ["index.js"] を組み合わせると、node は固定しつつ引数だけ差し替えられる。
  • exec form は signal handling の観点で推奨。
  • shell form は /bin/sh -c 経由になり、PID 1 と signal の問題が起きやすい。
  • wrapper script を使う場合は最後に exec "$@" する。

タグ

docker #container #entrypoint #cmd #devops