Dockerfile if else 조건 외부 인수 포함


130

나는 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

@ Зелёный 그것은 올바르지 않습니다. 아래 답변을 참조하십시오. --build-arg
devnul3

수락 된 답변은 질문의 "다른 경우 조건"부분을 다루지 않습니다. 조건 검사가 요구 사항이 아니라면 "외부 인수가있는 Dockerfile"로 이름을 바꾸는 것이 좋습니다.
Ruslan Kabalin

@RuslanKabalin-허용되는 답변에는 "then"및 "else"절이 모두 있습니다. 유일한 차이점은 "if 조건"에서 테스트되는 입니다. 문제에 표시된 코드의 경우 : RUN if [ "$arg" == "42" ]; then ENV=TRUE; else ENV=FALSE; fi. 또는 인수가 누락 된 경우 : RUN if [ "x$arg" == "x42" ]; then ...
ToolmakerSteve

답변:


192

깨끗하게 보이지 않을 수도 있지만 다음과 같이 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

4
여기서 삼항은 특정 인수를 확인하는 대신 인수가 제공되었는지 확인하는 것입니다. 재 작성하면 더 분명해 보일 것입니다. if [ $arg != "" ] ;하지만 제가 잘
모르는 부분이 있다고 확신합니다

21
if [[ -n "$arg" ]]PARAM이 비어 있지 않은 경우는 true, if [[ -z "$arg" ]]PARAM은 빈에 해당하는 경우
acumartini

6
여러 줄의 if 문을 작성하는 방법?
Ashutosh Chamoli

12
@Quannt-아니요, 왜 쉘 스크립트를 사용합니까? [ "x$arg" = "x" ] 따옴표로 묶인 두 문자열을 비교하는 것처럼 보이지만 따옴표는 제거됩니다. 이것은 정확한 구문을 유지합니다. 견적 스트리핑 후 : 좋음 : 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) FROM 이전의 ARG는 빌드 외부에 있습니다.

2) 기본 셸은 / bin / sh입니다. 즉, if else가 도커 빌드에서 약간 다르게 작동 함을 의미합니다. 예를 들어 문자열을 비교하려면 "=="대신 "="하나만 필요합니다.

그래서 당신은 내부에서 이것을 할 수 있습니다 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 .


17

제안 된 솔루션에 대한 흥미로운 대안이 있습니다. 단일 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단계는 조건 전에하고 싶은 일을 포함해야합니다. 그 후, 조건의 분기를 나타내는 두 단계가 더 있습니다 : branch-version-1branch-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

이 작업을 수행하려면 "test"바이너리를 직접 사용하십시오. 또한 "else"조건을 지정하지 않으려면 noop 명령 ":"을 사용해야합니다. 따라서 docker는 0이 아닌 반환 값 오류로 중지되지 않습니다.

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 apr

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"
Brandt

5

다른 사람들이 말했듯이 쉘 스크립트가 도움이 될 것입니다.

추가 사례 인 IMHO는 언급 할 가치가 있습니다 (여기에서 우연히 발견 한 다른 사람에게 더 쉬운 사례를 찾고 있음), 그것은 환경 교체 입니다.

환경 변수 ( ENV문으로 선언 됨 )는 특정 명령어에서 Dockerfile.

${variable_name}구문은 아래에 지정된 몇 가지 표준 bash 수정 자도 지원합니다.

  • ${variable:-word}variable가 설정되면 결과가 해당 값이 됨을 나타냅니다 . variable이 설정되지 않은 경우 word결과가됩니다.

  • ${variable:+word}variable가 설정 word되면 결과가되고 그렇지 않으면 결과가 빈 문자열 임을 나타냅니다 .


5

허용 대답은 문제를 해결할 수 있지만, 여러 원하는 경우 ifdockerfile의 조건을, 당신은 배치 할 수 있습니다 \(당신이 쉘 스크립트에서하는 방식과 유사) 각 라인의 끝과 각 명령 끝에서 ;. set -eux첫 번째 명령 과 같이 someting을 정의 할 수도 있습니다 .

예:

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.