Dockerfile에서 조건부 복사 / 추가?


103

내 Dockerfiles 내부에 파일이 있으면 내 이미지에 복사하고 싶습니다 .pip에 대한 requirements.txt 파일은 좋은 후보처럼 보이지만 어떻게 이룰 수 있습니까?

COPY (requirements.txt if test -e requirements.txt; fi) /destination
...
RUN  if test -e requirements.txt; then pip install -r requirements.txt; fi

또는

if test -e requirements.txt; then
    COPY requiements.txt /destination;
fi
RUN  if test -e requirements.txt; then pip install -r requirements.txt; fi

여기를 참조하십시오 : docs.docker.com/reference/builder
Tuan

4
@Tuan-그 링크에서 특별히 도움이되는 것은 무엇입니까?
ToolmakerSteve

답변:


24

이것은 현재 지원되지 않습니다 (동일한 Dockerfile이 파일의 존재에 따라 파일을 복사하거나 복사하지 않기 때문에 재현 불가능한 이미지로 이어질 것이라고 생각합니다).

이는 여전히 문제 13045 에서 와일드 카드 " COPY foo/* bar/" not work if no file in foo"(2015 년 5 월)를 사용하여 요청 됩니다.
현재 (2015 년 7 월) Docker에서 구현되지는 않지만 bocker 와 같은 다른 빌드 도구 가이를 지원할 수 있습니다.


32
좋은 대답이지만 도커 논리 인 IMO에는 결함이 있습니다. 다른 빌드 컨텍스트로 동일한 dockerfile을 실행하면 다른 이미지가 표시됩니다. 그것은 예상됩니다. 동일한 빌드 컨텍스트를 사용하면 동일한 이미지가 제공됩니다. 동일한 빌드 컨텍스트에 조건부 COPY / ADD 명령을 삽입하면 동일한 이미지를 얻을 수 있습니다. 그래서 체크 아웃합니다. 그래도 내 2 센트입니다.
nathan g

Docker는 불변 인프라에 관한 것입니다. 환경 개발, 스테이징 및 제품은 동일하지 않은 경우 가능한 한 99.99 % 가까워 야합니다. 환경 변수를 사용하십시오.
AndrewMcLagan

3
@AndrewMcLagan 예를 들어 프런트 엔드 dev환경이 웹팩 개발 서버로 실행되고 동등한 prod환경이 /dist정적 폴더 와 함께 작동한다면 어떻게 될까요? 이것은 대부분의 프런트 엔드 설정 오늘의 경우, 분명 dev하고 prod여기 같을 수 없습니다. 그럼 어떻게 처리할까요?
Jivan

노드 프런트 엔드를 개발하는 데 도커를 사용하지 않습니다. 일반 웹팩 localhost : 3000 등 ... 여전히 로컬 도커 개발 환경을 부팅하므로 노드 / 반응 / 각 프런트 엔드가 일반 도커 컨테이너 환경에서 실행중인 모든 항목과 통신합니다. 예 : API, redis, MySQL, mongo, 탄력적 검색 및 기타 마이크로 서비스. 컨테이너에서 웹팩 개발 환경을 .. 실행할 수 있습니다. 그러나 나는 그것이 ... 너무 느낀다
AndrewMcLagan

@Jivan onbuild 이미지를 사용하여 공통 지침을 정의한 다음 dev 및 prod를위한 특정 이미지를 빌드하는 방법은 무엇입니까? Docker Hub Node 리포지토리는 각 노드 버전에 대한 onbuild 이미지를 포함하는 것으로 보입니다 : hub.docker.com/_/node . 아니면 직접 굴릴 수도 있습니다.
david_i_smith nov.

83

다음은 간단한 해결 방법입니다.

COPY foo file-which-may-exist* /target

하나 이상의 유효한 소스가 필요 foo하므로 존재 하는지 확인하십시오 COPY.

있는 경우 file-which-may-exist복사됩니다.

참고 : 복사하지 않으려는 다른 파일을 와일드 카드가 선택하지 않도록주의해야합니다. 더 조심하려면 file-which-may-exist?대신 사용할 수 있습니다 ( ?단일 문자 만 일치).

또는 더 나은 방법은 다음과 같은 문자 클래스를 사용하여 하나의 파일 만 일치시킬 수 있도록합니다.

COPY foo file-which-may-exis[t] /target

1
폴더로 똑같은 일을 할 수 있습니까?
Benjamin Toueg

1
@BenjaminToueg : 예, 문서 에 따라 파일과 폴더를 복사 할 수 있습니다.
jdhildeb

2
이것은 훌륭하게 작동합니다. 대상이 여러 개인 파일의 경우 임시 디렉터리에 복사 한 다음 필요한 위치로 이동했습니다. COPY --from=docker /usr/bin/docker /usr/lib/libltdl.so* /tmp/docker/ RUN mv /tmp/docker/docker /usr/bin/docker RUN mv /tmp/docker/libltdl.so.7 /usr/lib/libltdl.so.7 || true(공유 라이브러리는 알 수없는 개체입니다.)
Adam K Dean

여러 개의 기존 파일을 복사 할 때 대상은 디렉토리 여야합니다. foo와 파일이 존재할 수있는 * 존재하는 경우 어떻게 작동합니까?
melchoir55

1
그래서 대답은 '파일이 있는지 확인하십시오'와 COPY 연산자를 사용하는 방법에 대한 데모입니다. 나는 이것이 원래 질문과 어떻게 관련되는지 알지 못합니다.
-09-23 derrend

27

이 주석 에서 언급했듯이 Santhosh Hirekerur의 답변은 여전히 ​​파일을 복사하므로 실제 조건부 사본을 보관하기 위해이 방법을 사용할 수 있습니다.

ARG BUILD_ENV=copy

FROM alpine as build_copy
ONBUILD COPY file /file

FROM alpine as build_no_copy
ONBUILD RUN echo "I don't copy"

FROM build_${BUILD_ENV}
# other stuff

ONBUILD지침은에서 "분기"를 선택한 경우에만 파일이 복사되도록합니다 BUILD_ENV. 호출하기 전에 약간의 스크립트를 사용하여이 변수를 설정하십시오.docker build


2
이 답변은 매우 편리한 ONBUILD뿐만 아니라 BUILD_ENV를 기반으로 태그를 설정하거나 일부 상태를 저장하려는 경우 전달 된 다른 변수와 통합하는 것이 가장 쉬운 것 같습니다. ENV.
DeusXMachina

방금 그런 식으로 시도해 보니 다음과 같은 결과가 있습니다. 데몬의 오류 응답 : Dockerfile 구문 분석 오류 줄 52 : 빌드 단계에 대한 잘못된 이름 : "site_builder _ $ {host_env}", 이름은 숫자로 시작하거나 기호를 포함 할 수 없습니다.
paulecoyote

9

해결 방법

ENV 변수를 기반으로 FOLDER를 서버에 복사해야합니다. 빈 서버 이미지를 가져 왔습니다. 로컬 폴더에 필요한 배포 폴더 구조를 생성했습니다. 그런 다음 DockerFile에 줄 아래에 추가 하여 폴더를 컨테이너에 복사하십시오. 나는 고정 표시기 서버를 시작하기 전에 n은 마지막 줄에 추가 엔트리 포인트는 초기화 file.sh을 실행합니다.

#below lines added to integrate testing framework
RUN mkdir /mnt/conf_folder
ADD install /mnt/conf_folder/install
ADD install_test /mnt/conf_folder/install_test
ADD custom-init.sh /usr/local/bin/custom-init.sh
ENTRYPOINT ["/usr/local/bin/custom-init.sh"]

그런 다음 아래와 같은 스크립트를 사용하여 로컬 에서 custom-init.sh 파일을 만듭니다.

#!/bin/bash
if [ "${BUILD_EVN}" = "TEST" ]; then
    cp -avr /mnt/conf_folder/install_test/* /mnt/wso2das-3.1.0/
else
    cp -avr /mnt/conf_folder/install/* /mnt/wso2das-3.1.0/
fi;

고정 표시기-작성 선 아래 파일.

환경 :-BUILD_EVN = TEST

이러한 변경 사항은 Docker 빌드 중에 폴더를 컨테이너에 복사합니다. docker-compose up 을 실행할 때 서버가 시작되기 전에 실제 필요한 폴더를 서버에 복사하거나 배포합니다.


8
그러나 도커 이미지는 계층화되어 있습니다. ADD는 ... 당신이 언급 한 if 문에 관계없이 이미지에이를 복사합니다
MyUserInStackOverflow

@MyUserInStackOverflow-이 "해결 방법"의 아이디어는 install과 install_test가 모두 이미지에 복사되지만 이미지가 실행되면 해당 폴더 중 하나만 최종 위치에 복사된다는 것입니다. 둘 다 이미지의 어딘가에 있어도 괜찮다면 합리적인 기술이 될 수 있습니다.
ToolmakerSteve

4

모든 파일을 일회용 디렉토리에 복사하고 원하는 파일을 손으로 선택하고 나머지는 버립니다.

COPY . /throwaway
RUN cp /throwaway/requirements.txt . || echo 'requirements.txt does not exist'
RUN rm -rf /throwaway

cp조건부 복사를 사용하여 동일한 솔루션에 의존하는 빌드 단계를 사용하여 유사한 작업을 수행 할 수 있습니다 . 빌드 단계를 사용하면 최종 이미지에 초기 COPY.

FROM alpine as copy_stage
COPY . .
RUN mkdir /dir_for_maybe_requirements_file
RUN cp requirements.txt /dir_for_maybe_requirements_file &>- || true

FROM alpine
# Must copy a file which exists, so copy a directory with maybe one file
COPY --from=copy_stage /dir_for_maybe_requirements_file /
RUN cp /dir_for_maybe_requirements_file/* . &>- || true
CMD sh

이것은 기술적으로 문제를 해결하지만 이미지의 크기를 줄이지는 않습니다. 딥 네트워크 모델과 같이 거대한 것을 조건부로 복사하려는 경우 오버레이 fs가 작동하는 방식으로 인해 이미지 크기가 여전히 부풀어집니다.
DeusXMachina

@DeusXMachina, 어떤 버전의 도커를 사용하고 있습니까? 문서는 docs.docker.com/develop/develop-images/multistage-build/… 라는 말과 모순 됩니다. 최종 빌드 단계가 아닌 경우 레이어를 유지해서는 안됩니다.
cdosborn

@cdosburn-18.09에 이것을 관찰했습니다. 나는 주로 첫 번째 예에 대해 이야기하고 있었는데, 단계적 빌드는 그 문제를 피해야합니다. 그리고 저는 모든 FROM 스테이지가 이제 압축되었다고 생각합니다.하지만 당신은 제 기억을 추측하게합니다. 몇 가지 실험을해야합니다.
DeusXMachina

@DeusXMachina, 두 번째 솔루션 만이 이미지 크기를 줄입니다.
cdosborn

내 경우에 좋은 해결 방법입니다. 나는 복사하고 cache그것이 무엇인지에 따라 스크립트 파일에서 할 일을 선택하는 캐시입니다!
Paschalis

1

다른 아이디어를 시도했지만 우리의 요구 사항을 충족하지 못했습니다. 아이디어는 하위 정적 웹 애플리케이션을위한 기본 nginx 이미지를 만드는 것입니다. 보안, 최적화 및 표준화 이유로, 기본 이미지는 할 수 있어야 RUN자식 이미지에 의해 추가 된 디렉토리에서 명령. 기본 이미지는 하위 이미지에 의해 추가되는 디렉토리를 제어하지 않습니다. 가정 아동 이미지가 뜻 COPY에서 자원 곳 COMMON_DEST_ROOT.

이 방법은 해킹이지만, 아이디어는 기본 이미지가 지원입니다 COPY자식 이미지를 추가 한 N에 디렉토리에 대한 지시를. ARG PLACEHOLDER_FILE그리고 ENV UNPROVIDED_DEST만족하는 데 사용됩니다 <src><dest>모든 요구 사항 COPY명령이 없습니다 필요합니다.

#
# base-image:01
#
FROM nginx:1.17.3-alpine
ENV UNPROVIDED_DEST=/unprovided
ENV COMMON_DEST_ROOT=/usr/share/nginx/html
ONBUILD ARG PLACEHOLDER_FILE
ONBUILD ARG SRC_1
ONBUILD ARG DEST_1
ONBUILD ARG SRC_2
ONBUILD ARG DEST_2
ONBUILD ENV SRC_1=${SRC_1:-PLACEHOLDER_FILE}
ONBUILD ENV DEST_1=${DEST_1:-${UNPROVIDED_DEST}}
ONBUILD ENV SRC_2=${SRC_2:-PLACEHOLDER_FILE}
ONBUILD ENV DEST_2=${DEST_2:-${UNPROVIDED_DEST}}

ONBUILD COPY ${SRC_1} ${DEST_1}
ONBUILD COPY ${SRC_2} ${DEST_2}

ONBUILD RUN sh -x \
    #
    # perform operations on COMMON_DEST_ROOT
    #
    && chown -R limited:limited ${COMMON_DEST_ROOT} \
    #
    # remove the unprovided dest
    #
    && rm -rf ${UNPROVIDED_DEST}

#
# child image
#
ARG PLACEHOLDER_FILE=dummy_placeholder.txt
ARG SRC_1=app/html
ARG DEST_1=/usr/share/nginx/html/myapp
FROM base-image:01

이 솔루션에는 PLACEHOLDER_FILE지원되는 더미 및 하드 코딩 된 수의 COPY 명령과 같은 명백한 단점이 있습니다 . 또한 COPY 명령어에 사용되는 ENV 변수를 제거 할 방법이 없습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.