Dockerfileの場合、外部引数を使用した条件


129

私はdockerfileを持っています

FROM centos:7
ENV foo=42

それから私はそれを構築します

docker build -t my_docker .

そしてそれを実行します。

docker run -it -d  my_docker

コマンドラインから引数を渡し、Dockerfileで他の場合にそれを使用することは可能ですか?私のようなものを意味します

FROM centos:7
if (my_arg==42)
     {ENV=TRUE}
else:
     {ENV=FALSE}

この引数を使用してビルドします。

 docker build -t my_docker . --my_arg=42

1
これはおそらくビルドスクリプトから処理する必要があります。
Snps 2017

@Зелёный不正解です。以下の回答を参照してください。これは--build-arg
devnul3 2018

受け入れられた回答は、質問の「if else条件」の部分をカバーしません。条件チェックが必須ではない場合は、「外部引数を使用したDockerfile」に名前を変更することをお勧めします。
ルスランカバリン

@RuslanKabalin-受け入れられた回答には「then」節と「else」節の両方があります。唯一の違いは、「if条件」でテストされるものです。問題のコードの場合:RUN if [ "$arg" == "42" ]; then ENV=TRUE; else ENV=FALSE; fi。または、argが欠落している可能性がある場合: RUN if [ "x$arg" == "x42" ]; then ...
ToolmakerSteve

回答:


191

きれいに見えないかもしれませんが、次のようにDockerfile(条件付き)を使用できます。

FROM centos:7
ARG arg
RUN if [ "x$arg" = "x" ] ; then echo Argument not provided ; else echo Argument is $arg ; fi

次にイメージを次のようにビルドします。

docker build -t my_docker . --build-arg arg=45

または

docker build -t my_docker .


20
[ "$arg" = "x" ]代わりにすべきではない[ "x$arg" = "x" ]ですか?
Quannt 2018年

4
ここでは、特定の引数をチェックするのではなく、引数が指定されているかどうかをチェックしています。次のようにif [ $arg != "" ] ;
書き直せ

21
if [[ -n "$arg" ]]paramが空でない場合はif [[ -z "$arg" ]]true、paramが空の場合はtrue
acumartini

6
複数行のifステートメントを書く方法は?
Ashutosh Chamoli

12
@Quannt-いいえ、「シェルスクリプトを実行する理由 」を参照してください[ "x$arg" = "x" ]。引用符で囲まれた2つの文字列を比較しているように見えますが、引用符は取り除かれています。これにより、正しい構文が維​​持されます。引用ストリッピング後:良い: if x = x ..。悪い:if = 。ただし、パラメーターの存在を確認するより良い方法があります入力引数の存在を確認します
ToolmakerSteve

20

いくつかの理由から、ここでの答えのほとんどは私を助けませんでした(おそらくそれはDockerfileの私のFROMイメージに関連しています)

したがって、Dockerのビルド中に引数が空かどうかをチェックしてifステートメントを処理するために、bash scriptと組み合わせてワークスペースにを作成することを選択しました--build-arg

Bashスクリプト:

#!/bin/bash -x

if test -z $1 ; then 
    echo "The arg is empty"
    ....do something....
else 
    echo "The arg is not empty: $1"
    ....do something else....
fi

Dockerfile:

FROM ...
....
ARG arg
COPY bash.sh /tmp/  
RUN chmod u+x /tmp/bash.sh && /tmp/bash.sh $arg
....

Dockerビルド:

docker build --pull -f "Dockerfile" -t $SERVICE_NAME --build-arg arg="yes" .

備考:これはbashスクリプトのelse(false)に移動します

docker build --pull -f "Dockerfile" -t $SERVICE_NAME .

備考:これはif(true)に移動します

編集1:

何度か試した後、私は次の記事とこれを見つけました 1を 2つの物事を理解するために私を助けました:

1)FROMの前のARGはビルドの外にあります

2)デフォルトのシェルは/ bin / shです。これは、Dockerビルドでif elseが少し異なって機能していることを意味します。たとえば、文字列を比較するには、「==」ではなく「=」が1つだけ必要です。

だからあなたはこれを Dockerfile

ARG argname=false   #default argument when not provided in the --build-arg
RUN if [ "$argname" = "false" ] ; then echo 'false'; else echo 'true'; fi

とでdocker build

docker build --pull -f "Dockerfile" --label "service_name=${SERVICE_NAME}" -t $SERVICE_NAME --build-arg argname=true .


16

提案されたソリューションの興味深い代替手段があり、単一のDockerfileで動作し、条件付きビルドごとにdocker ビルドへの単一の呼び出しのみを必要とし、bash回避しますます。

解決:

以下はDockerfileその問題を解決します。コピーして貼り付けて、自分で試してみてください。

ARG my_arg

FROM centos:7 AS base
RUN echo "do stuff with the centos image"

FROM base AS branch-version-1
RUN echo "this is the stage that sets VAR=TRUE"
ENV VAR=TRUE

FROM base AS branch-version-2
RUN echo "this is the stage that sets VAR=FALSE"
ENV VAR=FALSE

FROM branch-version-${my_arg} AS final
RUN echo "VAR is equal to ${VAR}"

Dockerfileの説明:

まずbase画像(centos:7あなたの場合)を取得し、それを独自のステージに配置します。baseステージは、あなたが条件の前にやりたい事を含める必要があります。その後、さらに2つのステージがあり、条件のブランチを表します:branch-version-1およびbranch-version-2。それらの両方を構築します。final基づいて、これらの段階の選択のものより段階、my_arg。条件付きDockerfile。どうぞ。

実行時の出力:

(これを少し省略しました...)

my_arg==2

docker build --build-arg my_arg=2 .
Step 1/12 : ARG my_arg
Step 2/12 : ARG ENV
Step 3/12 : FROM centos:7 AS base
Step 4/12 : RUN echo "do stuff with the centos image"
do stuff with the centos image
Step 5/12 : FROM base AS branch-version-1
Step 6/12 : RUN echo "this is the stage that sets VAR=TRUE"
this is the stage that sets VAR=TRUE
Step 7/12 : ENV VAR=TRUE
Step 8/12 : FROM base AS branch-version-2
Step 9/12 : RUN echo "this is the stage that sets VAR=FALSE"
this is the stage that sets VAR=FALSE
Step 10/12 : ENV VAR=FALSE
Step 11/12 : FROM branch-version-${my_arg}
Step 12/12 : RUN echo "VAR is equal to ${VAR}"
VAR is equal to FALSE

my_var==1

docker build --build-arg my_arg=1 .
...
Step 11/12 : FROM branch-version-${my_arg}
Step 12/12 : RUN echo "VAR is equal to ${VAR}"
VAR is equal to TRUE

この素晴らしいアイデアを提供してくれたTõnisに感謝します。


これまでのところ、最善のアプローチ。
Felipe Desiderati

私もここに投稿したのはそのためです。ニュース@FelipeDesiderati
User12547645

1
これは、スクリプト/ bashで回避策を使用する必要がなく、Dockerfileの知識のみを含む方法を使用するため、ここで提示されているすべての中で最良のソリューションです。すばらしい答えです。
Akito

「ARG ENV」とは何ですか?これに光を当てることができますか?ありがとう。
最大

@Maxに指摘してくれてありがとう。必須ではありません
User12547645

12

これを行うには、「テスト」バイナリを直接使用するだけです。また、「else」条件を指定したくない場合は、noopコマンド「:」を使用して、Dockerがゼロ以外の戻り値エラーで停止しないようにする必要があります。

RUN test -z "$YOURVAR" || echo "var is set" && echo "var is not set"
RUN test -z "$YOURVAR" && echo "var is not set" || :
RUN test -z "$YOURVAR" || echo "var is set" && :

2
と同じようにRUN [ -z "$YOURVAR" ] && ... || :
OneCricketeerは

4
次のステートメントでは、varが設定されている場合、両方のエコーが実行されます。RUN test -z "$YOURVAR" || echo "var is set" && echo "var is not set"
Harshad Vyawahare

確かに。彼らは入れて、逐次実行し、それらの分岐していないされ、条件付きブロックを覚えて&&目の前に||test ! -z "$YOURVAR" && echo "var is set" || echo "var is not set"
ブラント

5

他の人が言ったとおり、シェルスクリプトが役立ちます。

ほんの追加のケース、私見それは言及する価値があります(ここで偶然見つけて、より簡単なケースを探している他の人にとって)、それは環境置換です。

ENVステートメントで宣言された)環境変数は、特定の命令で、変数によって解釈される変数としても使用できます。Dockerfileます。

${variable_name}下記の指定された構文は、標準のbash修飾子の数をサポートしています。

  • ${variable:-word}variableが設定されている場合、結果はその値になることを示します。variable設定されていない場合はword、結果になります。

  • ${variable:+word}variableが設定されている場合はword結果になることを示し、それ以外の場合は結果は空の文字列になります。


5

受け入れ答えは質問を解決することがありますが、複数行したい場合ifdockerfileで条件を、あなたが置くことを行うことができます\(あなたはシェルスクリプトで行うだろうかと同様)、各行の終わりにして各コマンドを終了します;。何かをset -eux最初のコマンドとして定義することもできます。

例:

RUN set -eux; \
  if [ -f /path/to/file ]; then \
    mv /path/to/file /dest; \
  fi; \
  if [ -d /path/to/dir ]; then \
    mv /path/to/dir /dest; \
  fi

あなたの場合:

FROM centos:7
ARG arg
RUN if [ -z "$arg" ] ; then \
    echo Argument not provided; \
  else \
    echo Argument is $arg; \
  fi

次に、次のようにビルドします:

docker build -t my_docker . --build-arg arg=42

4

BashスクリプトとAlpine / Centosの使用

Dockerfile

FROM alpine  #just change this to centos 

ARG MYARG=""
ENV E_MYARG=$MYARG

ADD . /tmp
RUN chmod +x /tmp/script.sh && /tmp/script.sh

script.sh

#!/usr/bin/env sh

if [ -z "$E_MYARG" ]; then
    echo "NO PARAM PASSED"
else
    echo $E_MYARG
fi

引数を渡す: docker build -t test --build-arg MYARG="this is a test" .

....
Step 5/5 : RUN chmod +x /tmp/script.sh && /tmp/script.sh
 ---> Running in 10b0e07e33fc
this is a test
Removing intermediate container 10b0e07e33fc
 ---> f6f085ffb284
Successfully built f6f085ffb284

引数なし: docker build -t test .

....
Step 5/5 : RUN chmod +x /tmp/script.sh && /tmp/script.sh
 ---> Running in b89210b0cac0
NO PARAM PASSED
Removing intermediate container b89210b0cac0
....
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.