CMD
(およびRUN
and ENTRYPOINT
)のjson構文は、引数をカーネルに直接exec syscallとして渡します。exec syscallには、スペース、引用符のエスケープ、IOリダイレクション、変数置換、コマンド間のパイピング、複数のコマンドの実行などによる、コマンドと引数の分離はありません。syscallは、実行する実行可能ファイルと、その実行可能ファイルに渡す引数のリストのみを受け取り、実行します。
以下のような文字$
、変数を展開するには;
、別のコマンドに
別々の引数に、(スペース)&&
と||
チェーンコマンドには、>
出力のリダイレクトに、|
などのコマンド、間のパイプに、すべてのようなシェルと必要なものの特徴である/bin/sh
か、/bin/bash
それを解釈して実装します。
の文字列構文に切り替えるとCMD
、dockerはシェルを使用してコマンドを実行します。
CMD /etc/init.d/nullmailer start ; /usr/sbin/php5-fpm
それ以外の場合、2番目の構文はまったく同じことを行います。
CMD ["sh", "-c", "/etc/init.d/nullmailer start ; /usr/sbin/php5-fpm"]
最初のコマンドが失敗した場合、特にバックグラウンドで実行された場合はエラー処理が行われないため、コンテナ内でこの方法で複数のコマンドを実行することはお勧めしません。また、コンテナー内でpid 1として実行されているシェルを残します。これにより、シグナルの処理が中断され、10秒の遅延と、Dockerによるコンテナーの不適切な強制終了が発生します。信号処理は、シェルexec
コマンドを使用して軽減できます。
CMD /etc/init.d/nullmailer start ; exec /usr/sbin/php5-fpm
ただし、バックグラウンドでサイレントに失敗するプロセスを処理するには、supervisordのような何らかのマルチプロセスマネージャーに切り替えるか、できればアプリケーションを複数のコンテナーに分割して、docker-composeなどでデプロイする必要があります。
exec
形式は推奨形式なので、この形式を引き続き使用する必要がありますか?なぜそれが好ましいのですか?または、よりシンプルなshell
フォームを使用する必要がありますか?