Docker ENTRYPOINT と CMD — あなたのコンテナーが嘘をついた
あなたはDockerfileでENTRYPOINTとCMDを組み合わせました。そのため、コンテナが誤ったもので開始され、今ここにいます。以下に完全な解説を示します——すべての組み合わせ、シェルとexec形式のトラップ、実際に機能するパターン。
エラーは午前2時ごろに発生します。コンテナを開始すると、APIサーバーではなくシェルプロンプトが表示されます。あるいはまったく表示されません。あるいはプロセスが幽霊に包まれて実行されます。 sh それはキャンディのように食べられます SIGTERM —— グラディアントシャットダウンは、10秒間Dockerが待ってから失敗し、送信されます SIGKILL.
原因は、ほぼすべてのケースで、あなたが誤解した ENTRYPOINT と CMD。あるいは、Dockerが静かに受け入れるが、あなたが期待した通りではない方法で組み合わせたものです。
CMD: リプレース可能なデフォルト
CMD コンテナを開始するときに実行されるものを設定しますが、これは提案でありルールではありません。イメージ名の後に何らかのものを指定すると、それが完全に置き換えられます:
FROM ubuntu
CMD ["echo", "hello from CMD"]
$ docker run myimage
hello from CMD
$ docker run myimage echo goodbye
goodbye
それは人々を混乱させます。2つの選択肢があります:キーワードまたは度数の角度です。 echo goodbye 追加しなかった——それは置き換えました。あなたのすべての CMD は消えました。これは設計上です: CMD はデフォルトの動作であり、強制された動作ではありません。どの実行時の引数も勝ちます。
ENTRYPOINT: いつでも実行される部分
ENTRYPOINT 実行される可执行ファイルを設定します。実行時の引数はそれを置き換えるのではなく、それを渡します:
FROM ubuntu
ENTRYPOINT ["echo"]
CMD ["hello"]
$ docker run myimage
hello
$ docker run myimage goodbye
goodbye
$ docker run --entrypoint cat myimage /etc/hostname
mycontainer-abc123
両方設定されている場合、 ENTRYPOINT は実行ファイルであり、 CMD はそのデフォルト引数になります。を自由に上書きできます。 CMD を自由に上書きできます。 ENTRYPOINT を明示的に渡す場合に限り、上書きできます。 --entrypoint.
すべてのENTRYPOINT + CMD組み合わせ、説明
Dockerドキュメントにはこの表が含まれていますが、問題を引き起こす行についてはあまり触れていません:
| オプション。CMDがのみ引数を提供する場合に使用します。 | コンテナが開始されるときのデフォルトプロセス。 | 実際に実行されるもの |
|---|---|---|
| HTTPSでのみ送信 | HTTPSでのみ送信 | エラー — コンテナはどこかからコマンドが必要です |
| HTTPSでのみ送信 | ["cmd", "arg"] exec形式 | cmd arg |
| HTTPSでのみ送信 | cmd arg shell形式 | /bin/sh -c "cmd arg" |
["entry"] exec形式 | HTTPSでのみ送信 | entry |
["entry"] exec形式 | ["arg1", "arg2"] exec形式 | entry arg1 arg2 ✓ |
["entry"] exec形式 | cmd arg shell形式 | entry /bin/sh -c "cmd arg" — ほぼ間違いです |
entry shell形式 | ["arg1"] exec形式 | /bin/sh -c "entry" — CMDが静かに無視されます |
entry shell形式 | cmd arg shell形式 | /bin/sh -c "entry" — CMDが静かに無視されます |
「CMDが静かに無視される」という2行は、Dockerデバッグセッションの大きな割合を占めています。Shell形式 ENTRYPOINT は CMD — それを完全に無視します。Dockerはこれについて警告しません。
Shell形式とExec形式:シグナル処理の罠
両方の指示は2つの形式を受け入れ、選択は多くのDockerfileチュートリアルが認めるほど重要です。
Exec形式 (配列形式):
ENTRYPOINT ["nginx", "-g", "daemon off;"]
あなたのバイナリが直接実行されます。それはPID 1になります。Dockerが SIGTERM を送信してコンテナを停止するとき、あなたのプロセスがそれを受信します。グレードなシャットダウンが機能し、ログがフラッシュされ、接続がきれいに閉じられます。
CMD (シンプルな文字列):
ENTRYPOINT nginx -g "daemon off;"
Dockerはこれを /bin/sh -c "nginx -g daemon off;"として実行します。シェルがPID 1になります。が到着すると、 SIGTERM がそれを受信し、 sh 子プロセスにシグナルを転送しません。あなたのコンテナは10秒間止まり、を受信し、クリーンアップせずに死んでしまいます。すべてのケースでそうなります。 sh exec形式を使用してください。常に。どちらの形式も。 SIGKILL3つの実際に機能するパターン
パターン1: 固定された実行ファイル、上書き可能なデフォルト ENTRYPOINT と CMD.
ほとんどのプロダクションコンテナに適したパターンです。バイナリは固定され、フラグは実行時で交換可能です:
パターン2: execを使用したラッパースクリプト
初期化ロジックをメインプロセスの前に必要とする場合(マイグレーション、シークレット注入、シグナルトラップなど)、ラッパースクリプトを使用します。重要な行は
ENTRYPOINT ["/app/server"]
CMD ["--port", "8080", "--env", "production"]
# Use defaults
docker run myimage
# Override at deploy time
docker run myimage --port 9090 --env staging
の終わりにある——それはシェルプロセスをあなたのCMDに置き換え、バイナリがPID 1になります:
をスキップすると、シェルがPID 1となり、シグナル処理の問題に戻ります。 exec "$@" パターン3: CMDのみ、ENTRYPOINTなし
#!/bin/sh
set -e
echo "Running migrations..."
/app/migrate
# Hand off to CMD — exec replaces shell, so /app/server becomes PID 1
exec "$@"
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
CMD ["/app/server", "--port", "8080"]
開発イメージや環境に同じ設定を適用するためのツールコンテナに適しています: exec "$@"プロダクションでは、パターン1またはパターン2がより安全です——誤ったデプロイスクリプトが誤って実行され、サーバーをシェルセッションに置き換えることを避けたいのです。
docker exec との関係
何も関係ありません。
FROM python:3.12-slim
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
CMD ["python", "app.py"]
すでに実行中のコンテナにコマンドを実行します。それは docker run myimage bash を完全にバイパスします。あなたは
を実行するときにまったく考えなくてよいです。
デバッグ時に docker exec を使用して問題が解決され、その後 ENTRYPOINT が異なるように見えると不思議に思う人々は、これらはまったく別のコードパスです。 ENTRYPOINT 事前チェックリスト docker exec mycontainer bash exec形式(配列形式、単純な文字列ではない)を使用します
ラッパースクリプトを持っている場合は、それが終了する最後に docker exec をテストし、両方のパスが正常に機能することを確認します docker run 2秒以内に完了する(10秒なら、シグナル問題があります)
Dockerfileがレジストリに近づく前に自動フィードバックを必要とする場合、
- どちらも
ENTRYPOINTとCMDIO Tools’ Dockerfile Linter - shell形式の使用、entrypointスクリプト内の欠落、および実行時における静かな誤動作を引き起こすパターンを検出します。
exec "$@" - Docker ENTRYPOINT と CMD — コンテナがあなたに嘘をついた 2
docker run myimageとdocker run myimage --your-flagDocker ENTRYPOINT と CMD — コンテナがあなたに嘘をついた 1 docker stop mycontainerDockerfileにENTRYPOINTとCMDを組み合わせた結果、コンテナが間違ったもので開始され、今、ここにいます。ここに完全な分解を示します——すべての組み合わせ、shellとexec形式の罠、そして実際に機能するパターン。
Dockerfileがレジストリに近づく前に自動フィードバックを望む場合 IO Tools’ Dockerfile リンター シェル形式の使用やエントリポイントスクリプトにおける欠落 exec 実行時における静的誤動作を引き起こすパターンを検出します。
