JSONArgsRecommended
出力
JSON arguments recommended for ENTRYPOINT/CMD to prevent unintended behavior related to OS signals
(訳: ENTRYPOINT/CMD に対する JSON 引数は OS シグナルを起こすような意図しない動作は避けるべきです)
内容説明
ENTRYPOINT
および CMD
は、引数に関して 2 つの文法をサポートしています。
- シェル形式:
CMD my-cmd start
- exec 形式:
CMD ["my-cmd", "start"]
シェル形式を用いた場合、実行モジュールはシェルに対する子プロセスとして実行されます。
これはシグナルを送信しません。
これが何を意味するかと言えば、コンテナー内において実行されるプログラムが SIGTERM
や SIGKILL
といった OS シグナルを検出できないため、それらに適切に対処できないということです。
例
❌ 不可: ENTRYPOINT
コマンドは OS シグナルを受け取りません。
FROM alpine
ENTRYPOINT my-program start
# entrypoint は /bin/sh -c my-program start となります
実行ファイルが OS シグナルを受け取れるようにするには、CMD
やENTRYPOINT
では exec 形式を使ってください。
これはコンテナー内においてメインプロセス (PID 1
) として、シェルの親プロセスをうまく避けながら実行ファイルを実行します。
✅ 可: ENTRYPOINT
は OS シグナルを受け取ります。
FROM alpine
ENTRYPOINT ["my-program", "start"]
# entrypoint は my-program start となります
PID 1 としてプログラム起動を行うということは、Linux 上の PID 1 に求められるそれ相応の責任と動作が求められます。 たとえば子プロセスの終了を検出することなどです。
回避策
シェルの元でコンテナーを実行したいというケースがあるかもしれません。
exec 形式を用いた場合、シェル機能として変数展開、パイプ (|
)、コマンド連結 (&&
, ||
, ;
) は利用できません。
そういった機能を利用したいならシェル形式を用いなければなりません。
以下に示すのはそれを実現する方法です。 これは、シェルの子プロセスとして実行ファイルを実行することに変わりはありません。
ラッパースクリプトの生成
エントリーポイント用のスクリプトを用意して、起動コマンドをラップするようにします。
そしてそのスクリプトを実行しつつ ENTRYPOINT
コマンドは JSON 形式とします。
✅ 可: ENTRYPOINT
は JSON 形式を使っています。
FROM alpine
RUN apk add bash
COPY --chmod=755 <<EOT /entrypoint.sh
#!/usr/bin/env bash
set -e
my-background-process &
my-program start
EOT
ENTRYPOINT ["/entrypoint.sh"]
シェルの明示的な指定
Dockerfile の命令として SHELL
があります。
利用したいシェルを明示的に指定するものです。
SHELL
命令を利用するということは、シェル形式を意図的に利用することを表しているため、警告メッセージは出力されなくなります。
✅ 可: シェルが明示的に定義されています。
FROM alpine
RUN apk add bash
SHELL ["/bin/bash", "-c"]
ENTRYPOINT echo "hello world"