docker runを介してシェルスクリプトに引数を渡す方法


131

私はドッカーの世界に不慣れです。dockerコンテナーを介してコマンドライン引数を取るシェルスクリプトを呼び出す必要があります。例:シェルスクリプトは次のようになります。

#!bin/bash
echo $1

Dockerfileは次のようになります。

FROM ubuntu:14.04
COPY ./file.sh /
CMD /bin/bash file.sh

コンテナの実行中に引数を渡す方法がわかりません

回答:


61

同じを使用 file.sh

#!/bin/bash
echo $1

既存のDockerfileを使用してイメージをビルドします。

docker build -t test .

引数abcなどをxyz使用してイメージを実行します。

docker run -ti test /file.sh abc

docker run -ti test /file.sh xyz

27
エンドユーザーにfile.shについて直接知らせたくない場合は、ENTRYPOINTが適しています。
greg.kindel 2016年

このようなスクリプトを開始するにはどうすればよいですかdocker run -ti test /file.sh abc。スクリプトが実行されるはずなので、実行されないと思いますdocker run -ti test sh /file.sh abc。shまたは/ bin / shで正しく実行されます。
Vamsidhar Muggulla 2016年

1
ここに来る他の人のために。/ usr / bin / envトリックはオプションのスタイル設定であり、これを機能させるための要件ではありません。また、#!行は、デフォルトの購入を使用するインタープリターを示します。したがって、スクリプトを呼び出すだけで実行できます。
wheredidthatnamecome 18/01/05の

163

このスクリプトで file.sh

#!/bin/bash
echo Your container args are: "$@"

この Dockerfile

FROM ubuntu:14.04
COPY ./file.sh /
ENTRYPOINT ["/file.sh"]

次のことができるはずです。

% docker build -t test .
% docker run test hello world
Your container args are: hello world

9
「/file.sh」の前後の「」を忘れた場合は機能しません。
kev

6
何らかの理由で、これは動作しENTRYPOINT ./file.sh
ません

6
chmod +x file.sh実行可能フラグを設定することを忘れないでください。
topskip

1
@kev、どうしてそんな感じなのか知ってる?["/file.sh"]and /file.shまたはor の違いは何[/file.sh]
ですか

1
@Nitzankinは、適切なjsonフォーマットが必要な理由について私の答えを参照してください。
BMitch 2018

60

Dockerでは、この種の情報を渡す適切な方法は、環境変数を使用することです。

同じDockerfileで、スクリプトを次のように変更します

#!/bin/bash
echo $FOO

ビルド後、次のdockerコマンドを使用します。

docker run -e FOO="hello world!" test

20
なぜこれが最も投票数の多い回答なのですか?環境変数は情報を渡す別の方法ですが、OPが要求するものではありません。そしてもちろん、コンテナに引数を渡したいというOPの欲求については、絶対に不適切なことは何もありません。
曇り

8
@PartlyCloudy明らかに間違っているにもかかわらず、「適切な」答えを与えると主張しているので、私はこのような人が好きだと思います。Dockerの主要な設計原則は、常識よりもドグマを優先することです。
オーグラ2017年

1
@augurar:この回答を改善するために、この回答が「明らかに間違っている」と思う理由を説明してください。
EmilStenström18年

2
SOに尋ねるXY問題はたくさんあります。OPがDockerを初めて使用することを述べたので、目標を達成するための推奨される方法を示す回答は完全に合理的です。したがって、これは素晴らしい答えになります。
colm.anseo

1
ビルド引数としてすべての変数を渡す代わりに、変数を渡す代わりに、ジョブを実行する最も簡単な方法。シークレットを環境変数として渡すのに非常に役立ちます。
Arvind Sridharan

32

ここにはいくつかの相互作用があります:

  1. docker run your_image arg1 arg2値を置き換えますCMDとをarg1 arg2。これは、CMDの完全な置き換えであり、CMDにさらに値を追加するものではありません。これがdocker run some_image /bin/bash、コンテナーでbashシェルを実行することがよくある理由です。

  2. ENTRYPOINTとCMDの両方の値が定義されている場合、dockerは2つを連結し、連結されたコマンドを実行することでコンテナーを開始します。したがって、エントリポイントをに定義するとfile.sh、引数としてに渡される追加の引数を使用してコンテナを実行できるようになりますfile.sh

  3. dockerのエントリポイントとコマンドには、シェルを起動する文字列構文と、execを実行するjson構文の2つの構文があります。シェルは、IOリダイレクション、複数のコマンドのチェーン(など&&)、変数の置換などの処理に役立ちます。ただし、シェルは信号処理の邪魔になります(10秒の停止の遅延を見たことがある場合)。コンテナー、これが原因であることがよくあります)、エントリーポイントとコマンドを連結します。エントリポイントを文字列として定義すると、が実行されますが/bin/sh -c "file.sh"、それだけで問題ありません。ただし、コマンドを文字列としても定義している場合は/bin/sh -c "file.sh" /bin/sh -c "arg1 arg2"、コンテナ内でコマンドが起動されているように見えますが、あまり良くありません。これら2つのオプションの相互作用の詳細については、こちらの表をご覧ください

  4. シェル-cオプションは単一の引数のみを受け取ります。それ以降はすべて、その単一の引数$1$2、などとして渡されますが、引数を明示的に渡さない限り、埋め込みシェルスクリプトには渡されません。つまりは/bin/sh -c "file.sh $1 $2" "arg1" "arg2"動作しますが、/bin/sh -c "file.sh" "arg1" "arg2"ではないであろうからfile.sh引数なしで呼び出されます。

これらすべてをまとめると、一般的な設計は次のとおりです。

FROM ubuntu:14.04
COPY ./file.sh /
RUN chmod 755 /file.sh
# Note the json syntax on this next line is strict, double quotes, and any syntax
# error will result in a shell being used to run the line.
ENTRYPOINT ["file.sh"]

そして、あなたはそれを次のように実行します:

docker run your_image arg1 arg2

これについてはかなり詳細があります:


1
私はエントリポイントを["bash", "--login", "-c"]に設定してイメージ内の/ etc / profileソースを取得する実験をしましたが、後でdocker runに渡されるシェルスクリプトに引数が渡されないのではないかと疑問に思われました...あなたの答えはそれをクリアしました、ありがとう!
Apteryx

23

私が持っているのは、実際に実行するスクリプトファイルです。このscripファイルは比較的複雑な場合があります。それを「run_container」と呼びましょう。このスクリプトは、コマンドラインから引数を取ります。

run_container p1 p2 p3

単純なrun_containerは次のようになります。

#!/bin/bash
echo "argc = ${#*}"
echo "argv = ${*}"

私がやりたいのは、これを「ドッキング」した後、次のようなdockerコマンドラインのパラメーターを使用してこのコンテナーを起動できるようにすることです。

docker run image_name p1 p2 p3

そして、run_containerスクリプトをパラメーターとしてp1 p2 p3で実行します。

これは私の解決策です:

Dockerfile:

FROM docker.io/ubuntu
ADD run_container /
ENTRYPOINT ["/bin/bash", "-c", "/run_container \"$@\"", "--"]

7
ENTRYPOINT配列の3番目の値を、"/run_container \"$@\""スペースを含む引数が正しく処理されることで置き換えます(例:)docker run image_name foo 'bar baz' quux
davidchambers 2017

switch / caseステートメントをbashファイルに追加した後、ENTRYPOINT ["run_container.sh"]は機能しなくなりましたが、ENTRYPOINT ["sh"、 "-c"、 "run_container.sh"]はパラメーターを受け入れなくなりました。このソリューション(@davidchambersの提案を使用)は私にとってうまくいきました。
ラミルトン2018

10

@build timeで実行したい場合:

CMD /bin/bash /file.sh arg1

@run timeで実行したい場合:

ENTRYPOINT ["/bin/bash"]
CMD ["/file.sh", "arg1"]

次に、ホストシェルで

docker build -t test .
docker run -i -t test

2
ENTRYPOINTランタイムが欲しかったと思うOPにとって良い答えですが、ビルド時間変数が本当に必要な場合、この答えはうまくいきません。使用ARGしてdocker build --build-arg docs.docker.com/engine/reference/builder/#arg
greg.kindel

0

別のオプション...

これを機能させるには

docker run -d --rm $IMG_NAME "bash:command1&&command2&&command3"

dockerfile

ENTRYPOINT ["/entrypoint.sh"]

entrypoint.sh

#!/bin/sh

entrypoint_params=$1
printf "==>[entrypoint.sh] %s\n" "entry_point_param is $entrypoint_params"

PARAM1=$(echo $entrypoint_params | cut -d':' -f1) # output is 1 must be 'bash' it     will be tested    
PARAM2=$(echo $entrypoint_params | cut -d':' -f2) # the real command separated by     &&

printf "==>[entrypoint.sh] %s\n" "PARAM1=$PARAM1"
printf "==>[entrypoint.sh] %s\n" "PARAM2=$PARAM2"

if [ "$PARAM1" = "bash" ];
then
    printf "==>[entrypoint.sh] %s\n" "about to running $PARAM2 command"
    echo $PARAM2 | tr '&&' '\n' | while read cmd; do
        $cmd
    done    
fi

いくつかの注意と制限.... ":"を含むコマンドは、cut -d ':'の変更が必要で、docker run -d --rm $ IMG_NAME "bash:echo $ PATH"のようなコマンドは、ホストではなくホストパスの値を表示します1つ
ワグネルマルク
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.