dockerエントリポイントスクリプトに対してset-eとexec“ $ @”は何をしますか?


95

dockerの多くのentrypoint.shスクリプトが次のようなことをしていることに気づきました。

#!/bin/bash
set -e

... code ...

exec "$@"

どのようなものset -eexec "$@"するために?


2
BashFAQ#105 re:を参照してください。なぜset -e、手書きのエラー処理よりもはるかにエラーが発生しやすいと考えられているのですか。(急いでいる場合は、以下の演習の上部にある類推をスキップしてください)。
チャールズ・ダフィー

回答:


71

基本的にentrypoint.sh、渡されたコマンドライン引数を受け取り、それらをコマンドとして実行します。基本的には、「この.shスクリプトですべてを実行してから、同じシェルでユーザーがコマンドラインで渡したコマンドを実行する」ことを目的としています。

見る:


1
またexec "$@"、現在実行中のプロセスが、渡された引数に対して生成された新しいプロセスに置き換えられることにも注意してください。ドッカーシグナリングのための重要:stackoverflow.com/a/32261019/99717
ホークアイパーカー

35

set -e実行中のコマンドがゼロ以外の終了コードで終了した場合にすぐに終了するようにシェルオプションを設定します。スクリプトは、失敗したコマンドの終了コードとともに戻ります。bashのmanページから:

セット-e:

パイプライン(単一の単純なコマンドで構成されている場合があります)、リスト、または複合コマンド(上記のSHELL GRAMMARを参照)がゼロ以外のステータスで終了した場合は、すぐに終了します。失敗したコマンドがwhileまたはuntilキーワードの直後のコマンドリストの一部、ifまたはelifの予約語に続くテストの一部、&&または||で実行されるコマンドの一部である場合、シェルは終了しません。最後の&&または||に続くコマンド、パイプライン内の最後以外のコマンド、またはコマンドの戻り値が!で反転されている場合を除くリスト。-eが無視されている間にコマンドが失敗したために、サブシェル以外の複合コマンドがゼロ以外のステータスを返した場合、シェルは終了しません。ERRのトラップが設定されている場合は、シェルが終了する前に実行されます。

-eが無視されている状況で複合コマンドまたはシェル関数が実行される場合、-eが設定され、コマンドがaを返しても、複合コマンドまたは関数本体内で実行されるコマンドはいずれも-e設定の影響を受けません。障害ステータス。-eが無視されるコンテキストで実行中に複合コマンドまたはシェル関数が-eを設定した場合、その設定は、複合コマンドまたは関数呼び出しを含むコマンドが完了するまで効果がありません。


exec "$@"通常、エントリポイントをパススルーしてdockerコマンドを実行するために使用されます。現在実行中のシェルを、を"$@"指しているコマンドに置き換えます。デフォルトでは、その変数はコマンドライン引数を指します。

entrypoint.shを指すエントリポイントを持つイメージがあり、コンテナをとしてdocker run my_image server start実行entrypoint.sh server startすると、コンテナでの実行に変換されます。exec行entrypoint.shで、pid1として実行されているシェルはそれ自体をコマンドに置き換えますserver start

これは、信号処理にとって重要です。を使用しない場合execserver start上記の例のは別のpidとして実行され、終了した後、シェルスクリプトに戻ります。pid 1のシェルでは、SIGTERMはデフォルトで無視されます。つまりdocker stop、コンテナに送信する正常な停止信号は、serverプロセスによって受信されることはありません。10秒後(デフォルト)、docker stop正常なシャットダウンをあきらめてSIGKILLを送信すると、アプリは強制的に終了しますが、データが失われたり、ネットワーク接続が閉じられたりすると、アプリ開発者はシグナルを受信した場合にコードを記述できます。また、コンテナが停止するまでに常に10秒かかることも意味します。

shiftおよびのようなシェルコマンドを使用するとset --、の値を変更できることに注意してください"$@"。たとえば/bin/sh -c "..."、次の場合にdockerのシェル構文を使用した場合に表示される可能性のあるコマンドからを削除するスクリプトの短い部分を次に示しますCMD

# convert `/bin/sh -c "server start"` to `server start`
if [ $# -gt 1 ] && [ x"$1" = x"/bin/sh" ] && [ x"$2" = x"-c" ]; then
  shift 2
  eval "set -- $1"
fi

....

exec "$@"

1
陳腐化を示すPOSIXtest仕様を参照してください-a[ "$#" -gt 1 ] && [ "$1" = /bin/sh ]は正しい置換です(x"$1"廃止されていない構文のみを使用する場合は、ハッカーは必要ありません)。
チャールズ・ダフィー

また、文字列の解析shift 2; set -- $1方法evalとはまったく同じではありません。考えてみましょう/bin/sh -c 'printf "%s\n" "hello world" "goodbye world"'あなたは、具体的なテストケースをしたい、と見た場合、引数に文字列を変換する際のBashが解析引用符ません
チャールズダフィー

@CharlesDuffy廃止されたオプションのヒントをありがとう、私はこの間違いをもう一度犯すと確信しています、古い習慣は一生懸命に死にます。を使用するeval/bin/sh -c、文字列での動作を反映したいと思いますが、何かが足りない場合はお知らせください。
BMitch

30

set -e -コマンドが失敗した場合はスクリプトを終了します(ゼロ以外の値)

exec "$@"-入力変数をリダイレクトします。詳細はこちらをご覧ください


「入力変数をリダイレクトしますか?」え?exec確かに、リダイレクトを実行する使用モードがありますが、これはそのモードではありません。
チャールズ・ダフィー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.