source

다른 조건이 있는 경우 도커 파일(외부 인수 포함)

manycodes 2023. 10. 8. 09:59
반응형

다른 조건이 있는 경우 도커 파일(외부 인수 포함)

도커 파일이 있습니다.

FROM centos:7
ENV foo=42

그 다음에 짓습니다.

docker build -t my_docker .

실행합니다.

docker run -it -d  my_docker

명령줄에서 인수를 전달하여 도커 파일에서 if와 함께 사용할 수 있습니까?제 말은 마치

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

이 논쟁으로 구축합니다.

 docker build -t my_docker . --my_arg=42

깨끗해 보이지는 않지만 다음과 같이 도커 파일(조건부)을 가질 수 있습니다.

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=45

아니면

docker build -t my_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}"

도커 파일에 대한 설명:

우리는 먼저 A를 받습니다.basecentos:7당신의 경우), 그리고 그것을 그것만의 단계로 집어넣습니다.base무대는 조건 전에 하고 싶은 것들을 포함해야 합니다.그 며,다,두가 더 .branch-version-1그리고.branch-version-2. 우리가 둘 다 짓는다니까요.final보다,합니다에 을 둔 이 중 하는 단계.my_arg 도커 조건부 도커 파일입니다.여기 있습니다.

실행 시 출력:

(이것을 조금 줄여서...)

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_arg==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

이 놀라운 아이디어를 주신 티 õ니스 씨께 감사드립니다!

가능한 경우 다른 답변에 설명된 빌드 아르그를 사용하지 마십시오.이것은 오래된 지저분한 해결책입니다.이 문제는 도커의 대상 속성에서 해결합니다.

대상 예제

도커파일

FROM foo as base

RUN ...

# Build dev image
FROM base as image-dev

RUN ...
COPY ...

# Build prod image
FROM base as image-prod

RUN ...
COPY ...
docker build --target image-dev -t foo .
version: '3.4'

services:

  dev:
    build:
      context: .
      dockerfile: Dockerfile
      target: image-dev

리얼 월드

실제 세계에서는 도커 파일이 복잡해집니다. &용 & COPY --from보다 빠르고 유지보수가 가능한 Docker 파일:

  • 도커는 상속 여부에 관계없이 대상 위의 모든 단계를 구축합니다.빌드킷을 사용하여 상속된 스테이지만 빌드합니다.도커는 v19+까지 해야 합니다.이것이 곧 기본 기능이 되기를 바랍니다.
  • 대상이 빌드 단계를 공유할 수 있습니다. 사용COPY --from상속을 간소화할 수 있습니다.
FROM foo as base
RUN ...
WORKDIR /opt/my-proj

FROM base as npm-ci-dev
# invalidate cache
COPY --chown=www-data:www-data ./package.json /opt/my-proj/package.json
COPY --chown=www-data:www-data ./package-lock.json /opt/my-proj/package-lock.json
RUN npm ci

FROM base as npm-ci-prod
# invalidate cache
COPY --chown=www-data:www-data ./package.json /opt/my-proj/package.json
COPY --chown=www-data:www-data ./package-lock.json /opt/my-proj/package-lock.json
RUN npm ci --only=prod

FROM base as proj-files
COPY --chown=www-data:www-data ./ /opt/my-proj

FROM base as image-dev
# Will mount, not copy in dev environment
RUN ...

FROM base as image-ci
COPY --from=npm-ci-dev /opt/my-proj .
COPY --from=proj-files /opt/my-proj .
RUN ...

FROM base as image-stage
COPY --from=npm-ci-prod /opt/my-proj .
COPY --from=proj-files /opt/my-proj .
RUN ...

FROM base as image-prod
COPY --from=npm-ci-prod /opt/my-proj .
COPY --from=proj-files /opt/my-proj .
RUN ...

실험 모드를 활성화합니다.

sudo echo '{"experimental": true}' | sudo tee /etc/docker/daemon.json

빌드킷이 활성화된 상태에서 빌드합니다. -드에서 - 로 설정--build-arg BUILDKIT_INLINE_CACHE=1

CI 빌드 작업.

DOCKER_BUILDKIT=1 \
    docker build \
    --build-arg BUILDKIT_INLINE_CACHE=1 \
    --target image-ci\
    -t foo:ci
    .

과 같이 --cache-from

Prod build 작업

docker pull foo:ci
docker pull foo:stage

DOCKER_BUILDKIT=1 \
    docker build \
    --cache-from foo:ci,foo:stage \
    --target image-prod \
    -t prod
    .

어떤 이유에서인지 대부분의 답변이 도움이 되지 않았습니다(도커 파일의 FROM 이미지와 관련이 있을 수 있음).

저는 했습니다.bash script에서와 된 제 입니다.--build-arg 있는지 문을 if 문을 하려면, if안

배시 스크립트:

#!/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

도커 파일:

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

도커 빌드:

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

비고: 이것은 배시 스크립트의 다른 것(거짓)으로 갈 것입니다.

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

비고: if(true)로 이동합니다.

편집 1:

몇번의 시도 끝에 저는 다음의 기사와 이 기사를 발견했습니다. 두가지를 이해하는데 도움이 된 기사입니다.

1) ARG FROM이 빌드 외부에 있기 전의 ARG

2) 기본 셸은 /bin/sh이며, 이는 if가 도커 빌드에서 조금 다르게 작동하고 있음을 의미합니다.예를 들어 문자열을 비교하려면 "==" 대신 "=" 하나만 필요합니다.

죠 할 수 있습니다.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 .

승인된 답변을 통해 질문이 해결될 수도 있지만, 만약 당신이 멀티라인을 원한다면if건,다를 할 수 .\(쉘 각 각을 함)합니다.;. 당신은 심지어 다음과 같은 것을 정의할 수 있습니다.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

이것을 하려면 "test" 이진법을 직접 사용하면 됩니다.또한 "다른" 조건을 지정하지 않으려면 noop 명령 ":"을 사용하여 도커가 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" && :

명령어에 대한 문서에 따르면 이라는 매개 변수가 있습니다.

사용 예시:

docker build --build-arg HTTP_PROXY=http://10.20.30.2:1234 .

IMO 그것이 당신에게 필요한 것입니다 :)

다른 사람들이 말한 것처럼 셸 스크립트가 도움이 될 것입니다.

단지 추가적인 사례일 뿐입니다. IMHO는 (여기서 우연히 발견하여 더 쉬운 사례를 찾고 있는 다른 사람에게) 환경 교체에 대해 언급할 가치가 있습니다.

환경 변수(와 함께 선언됨)ENV가 특정 에 의해 .다.Dockerfile.

${variable_name}몇 표준 준 bash합니다.

  • ${variable:-word}다인 경우를 .variable가 설정되면 결과는 해당 값이 됩니다. 만약variable설정되어 있지 않습니다.word결과가 될 것입니다.

  • ${variable:+word}다인 경우를 .variable다음에 설정됩니다.word결과가 됩니다. 그렇지 않으면 결과는 빈 문자열입니다.

Bash 스크립트 및 Alpine/Centos 사용

도커파일

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

arg 없음: 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
....

Windows 기반 이미지를 구축하려는 사용자의 경우 다음과 같은 인수에 액세스해야 합니다.%%

# Dockerfile Windows
# ...
ARG SAMPLE_ARG
RUN if %SAMPLE_ARG% == hello_world ( `
    echo hehe %SAMPLE_ARG% `
    ) else ( `
    echo haha %SAMPLE_ARG% `
)
# ...

그건 그렇고.ARG다 .FROM그렇지 할 수 .

# The ARGs in front of FROM is for image
ARG IMLABEL=xxxx \
    IMVERS=x.x

FROM ${IMLABEL}:${IMVERS}

# The ARGs after FROM is for parameters to be used in the script
ARG  condition-x

RUN if [ "$condition-x" = "condition-1" ]; then \
      echo "$condition-1"; \
    elif [ "$condition-x" = "condition-1" ]; then \
      echo "$condition-2"; \
    else
      echo "$condition-others"; \
    fi

build -t --build-arg IMLABEL --build-arg IMVERS --build-arg condition-x -f Dockerfile -t image:version .

컨테이너에 프록시 서버를 설정하는 것과 비슷한 문제가 있었습니다.

제가 사용하고 있는 솔루션은 엔트리 포인트 스크립트와 환경 변수 구성을 위한 또 다른 스크립트입니다.RUN을 사용하면 구성 스크립트가 빌드에서 실행되고 컨테이너를 실행할 때 ENTERPOINT가 실행됩니다.

--build-arg는 명령줄에서 프록시 사용자 및 암호를 설정하는 데 사용됩니다.

컨테이너 시작 시 동일한 환경 변수가 필요하기 때문에 파일을 사용하여 빌드부터 실행까지 "지속"했습니다.

진입점 스크립트는 다음과 같습니다.

#!/bin/bash
# Load the script of environment variables
. /root/configproxy.sh
# Run the main container command
exec "$@"

configproxy.sh

#!/bin/bash

function start_config {
read u p < /root/proxy_credentials

export HTTP_PROXY=http://$u:$p@proxy.com:8080
export HTTPS_PROXY=https://$u:$p@proxy.com:8080

/bin/cat <<EOF > /etc/apt/apt.conf 
Acquire::http::proxy "http://$u:$p@proxy.com:8080";
Acquire::https::proxy "https://$u:$p@proxy.com:8080";
EOF
}

if [ -s "/root/proxy_credentials" ]
then
start_config
fi

그리고 Docker 파일에서 다음을 구성합니다.

# Base Image
FROM ubuntu:18.04

ARG user
ARG pass

USER root

# -z the length of STRING is zero
# [] are an alias for test command
# if $user is not empty, write credentials file
RUN if [ ! -z "$user" ]; then echo "${user} ${pass}">/root/proxy_credentials ; fi

#copy bash scripts
COPY configproxy.sh /root
COPY startup.sh .

RUN ["/bin/bash", "-c", ". /root/configproxy.sh"]

# Install dependencies and tools
#RUN apt-get update -y && \
#    apt-get install -yqq --no-install-recommends \
#    vim iputils-ping

ENTRYPOINT ["./startup.sh"]
CMD ["sh", "-c", "bash"]

프록시 설정 없이 빌드

docker build -t img01 -f Dockerfile . 

프록시 설정으로 빌드

docker build -t img01 --build-arg user=<USER> --build-arg pass=<PASS> -f Dockerfile . 

여기 좀 보세요.

간단한 체크만 추가하면 됩니다.

RUN [ -z "$ARG" ] \
    && echo "ARG argument not provided." \
    && exit 1 || exit 0

가능한 해결책을 많이 보았지만, 오늘 제가 직면한 문제에 적합한 사람은 아무도 없습니다.그래서, 저는 제게 효과가 있었던 또 다른 가능한 해결책을 가지고 질문에 답하는 시간을 갖고 있습니다.

내 경우에는 잘 알려진 것을 이용했습니다.if [ "$VAR" == "this" ]; then echo "do that"; fi. 주의할 점은, 도커가 왜 이 사건에 대한 이중 평등을 좋아하지 않는지 설명할 수 없습니다.그래서 이렇게 써야 돼요.if [ "$VAR" = "this" ]; then echo "do that"; fi.

제 경우에 효과가 있었던 완전한 예가 있습니다.

FROM node:16

# Let's set args and envs
ARG APP_ENV="dev"
ARG NPM_CMD="install"
ARG USER="nodeuser"
ARG PORT=8080
ENV NPM_CONFIG_PREFIX=/home/node/.npm-global
ENV PATH=$PATH:/home/node/.npm-global/bin
ENV NODE_ENV=${APP_ENV}

# Let's set the starting point
WORKDIR /app

# Let's build a cache
COPY package*.json .
RUN date \
 # If the environment is production or staging, omit dev packages
 # If any other environment, install dev packages
 && if [ "$APP_ENV" = "production" ]; then NPM_CMD="ci --omit=dev"; fi \
 && if [ "$APP_ENV" = "staging" ]; then NPM_CMD="ci --omit=dev"; fi \
 && npm ${NPM_CMD} \
 && usermod -d /app -l ${USER} node

# Let's add the App
COPY . .

# Let's expose the App port
EXPOSE ${PORT}

# Let's set the user
USER ${USER}

# Let's set the start App command
CMD [ "node", "server.js" ]

따라서 사용자가 적절한 빌드 인수를 통과하면docker buildcommand는 제작을 위한 app의 이미지를 만듭니다.그렇지 않으면 devNode.js 패키지로 앱 이미지를 만듭니다.

작동하려면 다음과 같이 전화를 걸 수 있습니다.

# docker build --build-arg APP_ENV=production -t app-node .

저는 파이썬과 같은 구문을 기반으로 도커 파일 생성을 위한 저만의 프레임워크를 작성하게 되었습니다.

이제 오픈 소스가 되었으니 여기서 시도해 보세요: https://github.com/gkpln3/sand

당신의 글을 쓰셔도 됩니다.Sandfile다음과 같이:

# Sandfile
from sand import *

From("ubuntu", Tag="20.04")
Run([
    "apt-get update",
    "apt-get install ffmpeg python3"
])

# Install python debugger on debug images.
if config.DEBUG:
    Run("pip3 install pdb")

Copy("app", "/app")
Entrypoint("python3 /app/app.py")

그리고 이것으로 전환될 것입니다.

# Auto-generated by Sand, do not edit!
FROM ubuntu:20.04
RUN apt-get update
RUN apt-get install ffmpeg python3
RUN pip3 install pdb
COPY app /app
ENTRYPOINT python3 /app/app.py

를 할 수 .-D아니면--set깃발을 올리다

$ sand config -DDEBUG=True

또는 YAML 파일을 사용합니다.

# sand.yaml
DEBUG: True
$ sand config --values sand.yaml

언급URL : https://stackoverflow.com/questions/43654656/dockerfile-if-else-condition-with-external-arguments

반응형