빌드 중에 Dockerfile의 Docker 컨테이너에 호스트 볼륨을 마운트하는 방법


236

원래 질문 : Dockerfile에서 VOLUME 명령을 사용하는 방법은 무엇입니까?

실제로 해결하려는 질문은 빌드 중에 Dockerfile의 docker 컨테이너에 호스트 볼륨을 마운트하는 방법, 즉 docker run -v /export:/export기능을 갖는 방법 docker build입니다.

그 뒤에 이유는 Docker에서 물건을 만들 때 apt-get install단일 도커에 캐시 ( )를 잠그고 싶지 않고 공유 / 재사용하기를 원하기 때문입니다. 이것이 제가이 질문에 대해 묻는 주된 이유입니다.

최근 업데이트:

docker v18.09 이전의 정답은 다음으로 시작해야합니다.

빌드 중에 볼륨을 마운트하는 방법이 있지만 Dockerfile은 포함하지 않습니다.

그러나 그것은 잘못 언급되고 체계적이며 지원되는 답변이었습니다. 도커에 포함 된 내용을 다시 설치할 때 다음 기사를 우연히 발견했습니다.

apt-cacher-ng 서비스도 커화
https://docs.docker.com/engine/examples/apt-cacher-ng/

이것이 직간접 적이 아닌이 질문에 대한 도커의 솔루션입니다. 도 커가 우리에게 제안하는 정통 방식입니다. 그리고 나는 내가 여기에 물어 보던 것보다 낫다는 것을 인정합니다.

또 다른 방법은 새로 승인 된 답변입니다 (예 : v18.09의 Buildkit).

당신에게 맞는 것을 고르세요.


: Docker가 아닌 Rocker라는 해결책이 있었지만 이제 Rocker가 중단되었으므로 대답을 다시 "불가능"으로 되돌립니다 .


이전 업데이트 : 답변은 "불가"입니다. https://github.com/docker/docker/issues/3156 에서 문제가 광범위하게 논의되었다는 것을 알고 답변으로 받아 들일 수 있습니다 . 이식성이 도커 개발자에게 가장 중요한 문제라는 것을 이해할 수 있습니다. 도커 사용자 로서이 누락 된 기능에 대해 매우 실망했다고 말해야합니다. 앞서 언급 한 논의에서 인용 한 인용문을 인용 하겠습니다 . " 젠투를 기본 이미지로 사용하고 싶지만 일단 이미지가 만들어진 후에는 1GB 이상의 포티지 트리 데이터를 어떤 레이어에도 포함하고 싶지 않습니다. 설치 중에 이미지에 거대한 포티지 트리가 나타나지 않으면 컴팩트 한 컨테이너를 가질 수 있습니다."네, wget이나 curl을 사용하여 필요한 것을 다운로드 할 수 있지만, 단지 이식성 만 고려하면 Gentoo 기본 ​​이미지를 만들 때마다> 1GB의 포티지 트리를 다운로드해야한다는 사실이 효율적이거나 사용자 친화적이지 않습니다. 더욱이 패키지 저장소는 항상 / usr / portage 아래에 있으므로 Gentoo에서는 항상 이식 가능합니다. 다시 한 번, 결정을 존중하지만 그 동안 실망을 표현할 수있게 해주세요. 감사합니다.


세부적인 원래 질문 :

에서

볼륨을 통한 디렉토리 공유
http://docker.readthedocs.org/en/v0.7.3/use/working_with_volumes/

데이터 볼륨 기능은 "Docker Remote API 버전 1부터 사용 가능합니다"라고 말합니다. 내 도커 버전은 1.2.0이지만 위 기사에서 제공된 예제가 작동하지 않는 것을 발견했습니다.

# BUILD-USING:        docker build -t data .
# RUN-USING:          docker run -name DATA data
FROM          busybox
VOLUME        ["/var/volume1", "/var/volume2"]
CMD           ["/usr/bin/true"]

Dockerfile에서 VOLUME 명령을 통해 호스트 마운트 볼륨을 도커 컨테이너에 마운트하는 올바른 방법은 무엇입니까?

$ apt-cache policy lxc-docker
lxc-docker:
  Installed: 1.2.0
  Candidate: 1.2.0
  Version table:
 *** 1.2.0 0
        500 https://get.docker.io/ubuntu/ docker/main amd64 Packages
        100 /var/lib/dpkg/status

$ cat Dockerfile 
FROM          debian:sid

VOLUME        ["/export"]
RUN ls -l /export
CMD ls -l /export

$ docker build -t data .
Sending build context to Docker daemon  2.56 kB
Sending build context to Docker daemon 
Step 0 : FROM          debian:sid
 ---> 77e97a48ce6a
Step 1 : VOLUME        ["/export"]
 ---> Using cache
 ---> 59b69b65a074
Step 2 : RUN ls -l /export
 ---> Running in df43c78d74be
total 0
 ---> 9d29a6eb263f
Removing intermediate container df43c78d74be
Step 3 : CMD ls -l /export
 ---> Running in 8e4916d3e390
 ---> d6e7e1c52551
Removing intermediate container 8e4916d3e390
Successfully built d6e7e1c52551

$ docker run data
total 0

$ ls -l /export | wc 
     20     162    1131

$ docker -v
Docker version 1.2.0, build fa7b24f

분명히 더 많은 최신 기능 요청 (구현이 아니라 예상되는 경우) : docker / docker # 14080
Jesse Glick

실제로 빌드 도중 호스트 디렉토리와 컨테이너 디렉토리를 링크해서는 안된다는 광범위한 논의가있다 VOLUME ~/host_dir ~/container_dir. 토론은 매우 광범위합니다. 이유가 무엇인지 요약 할 수있는 짧은 방법이 있습니까?
Charlie Parker

답변:


34

먼저 "왜 작동하지 VOLUME않습니까?" 당신이 정의 할 때 VOLUMEDockerfile에, 당신은 단지 대상이 아닌 볼륨의 소스를 정의 할 수 있습니다. 빌드 중에는 익명 볼륨 만 얻을 수 있습니다. 해당 익명 볼륨은 모든 RUN명령에 마운트되고 이미지의 내용으로 미리 채워진 다음 RUN명령 끝에 폐기됩니다 . 컨테이너의 변경 사항 만 저장되며 볼륨 변경은 저장되지 않습니다.


이 질문이 제기 된 이후 도움이 될만한 몇 가지 기능이 릴리스되었습니다. 첫 번째 단계는 비효율적 인 첫 번째 단계 인 디스크 공간을 구축하고 필요한 출력 만 배송 한 최종 단계로 복사 할 수있는 다단계 빌드입니다. 두 번째 기능은 Buildkit으로, 이미지 제작 방식을 크게 바꾸고 새로운 기능을 빌드에 추가하고 있습니다.

다단계 빌드 FROM의 경우 각각 별도의 이미지 작성을 시작하는 여러 줄 이 있습니다 . 기본적으로 마지막 이미지에만 태그가 지정되지만 이전 단계에서 파일을 복사 할 수 있습니다. 표준 용도는 바이너리 또는 기타 응용 프로그램 아티팩트를 빌드하기위한 컴파일러 환경과 해당 아티팩트를 복사하는 두 번째 단계로 런타임 환경을 갖는 것입니다. 당신은 가질 수 있습니다 :

FROM debian:sid as builder
COPY export /export
RUN compile command here >/result.bin

FROM debian:sid
COPY --from=builder /result.bin /result.bin
CMD ["/result.bin"]

결과적으로 전체 / export 디렉토리가 아닌 결과 바이너리 만 포함하는 빌드가 생성됩니다.


Buildkit은 18.09에서 실험적으로 나왔습니다. 프론트 엔드 파서를 변경하는 기능을 포함하여 빌드 프로세스를 완전히 재 설계했습니다. 이러한 구문 분석기 변경 중 하나가 RUN --mount실행 명령에 대한 캐시 디렉토리를 마운트 할 수 있는 옵션을 구현했습니다 . 예를 들어 다음은 데비안 디렉토리 중 일부를 마운트하는 디렉토리입니다 (데비안 이미지를 재구성하면 패키지 재설치 속도가 빨라질 수 있습니다).

# syntax = docker/dockerfile:experimental
FROM debian:latest
RUN --mount=target=/var/lib/apt/lists,type=cache \
    --mount=target=/var/cache/apt,type=cache \
    apt-get update \
 && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
      git

maven의 경우 $ HOME / .m2, golang의 경우 /root/.cache와 같이 응용 프로그램 캐시에 관계없이 캐시 디렉토리를 조정합니다.


TL; DR : 대답은 여기 있습니다 :RUN --mount구문을 사용하면 빌드 컨텍스트에서 마운트 읽기 전용 디렉토리를 바인딩 할 수도 있습니다. 폴더는 빌드 컨텍스트에 존재해야하며 호스트 또는 빌드 클라이언트에 다시 맵핑되지 않습니다.

# syntax = docker/dockerfile:experimental
FROM debian:latest
RUN --mount=target=/export,type=bind,source=export \
    process export directory here...

디렉토리는 컨텍스트에서 마운트되므로 읽기 전용으로 마운트되며 변경 사항을 호스트 나 클라이언트로 다시 푸시 할 수 없습니다. 빌드 할 때 18.09 이상을 설치하고로 빌드 킷을 활성화하십시오 export DOCKER_BUILDKIT=1.

mount 플래그가 지원되지 않는다는 오류가 발생하면 위의 변수로 buildkit을 활성화하지 않았거나 Dockerfile 상단의 구문 줄에서 실험 구문을 활성화하지 않았 음을 나타냅니다. 주석을 포함한 다른 모든 행. buildkit를 토글하는 변수는 docker 설치에 buildkit 지원 기능이 내장되어 있으며 클라이언트와 서버 모두에서 Docker의 버전 18.09 이상이 필요한 경우에만 작동합니다.


2
불행히도 Windows Buildkit은 아직 버전 18.09에서 지원되지 않습니다
Wesley

1
"armhf"도 "mount"를 지원하지 않는 것 같습니다.
Mike

2
나는 "Dockerfile 구문 분석 오류 라인 XX : 데몬에서 오류 응답을 알 수없는 플래그 : 마운트"얻고 OSX에
ChristoKiwi

1
docker-compose 지원은 아직 없지만 이미지를 작성하기 위해 작성하지 않아도됩니다. 추적 할 문제 : github.com/moby/buildkit/issues/685
BMitch


116

사용할 수 없습니다 VOLUME고정 표시기 말할 지시를 어떻게 마운트 할 수 있습니다. 이식성이 심각하게 손상 될 수 있습니다. 이 명령은 docker에게 해당 디렉토리의 내용이 이미지로 들어 가지 않으며 --volumes-from명령 줄 매개 변수를 사용하여 다른 컨테이너에서 액세스 할 수 있음을 알려줍니다 . -v /path/on/host:/path/in/container호스트에서 디렉토리에 액세스하려면을 사용하여 컨테이너를 실행 해야합니다.

빌드 중에 호스트 볼륨을 마운트 할 수 없습니다. 특권 빌드가 없으며 호스트를 마운트하면 이식성이 심각하게 저하됩니다. wget 또는 curl을 사용하여 빌드에 필요한 모든 것을 다운로드하여 배치하려고 할 수 있습니다.


2
감사. 질문이 수정되었습니다. 실제로 해결하려는 질문은 빌드 중에 Dockerfile의 docker 컨테이너에 호스트 볼륨을 마운트하는 방법입니다. 고마워.
xpt

2
불가능합니다. 수정 된 답변을 참조하십시오.
Andreas Steffan

3
이식성에 대한 "잠재적 인"부작용은 인정할 수 있지만이 옵션을 사용하는 데 유효한 사용 사례도 있습니다. 필자의 경우, 일부 컨테이너 디렉토리에 $ (PWD)가 마운트 된 "디렉토리로 이동하고 'docker run'명령을 실행하십시오"라고 사용자에게 알리고 싶습니다. $ (PWD)는 이식성을 유지합니다. 이것은 모퉁이 수 있지만 사용자 제공 스크립트를 위해 런타임 환경을 배포하는 위치에 크게 도움이 될 것입니다.
ntwrkguru

64

업데이트 : 누군가가 대답으로 받아들이지 않을 것이며, 특히이 특정 질문에 매우 좋아합니다.

좋은 소식, 지금 방법이 있습니다.

해결책은 로커입니다 : https://github.com/grammarly/rocker

존 야니는 말했다 , "IMO, 그것은 개발에 적합하다, Dockerfile의 모든 단점을 해결합니다."

흔들리는 것

https://github.com/grammarly/rocker

Rocker는 새로운 명령을 도입하여 다음과 같은 유스 케이스를 해결하는 것을 목표로합니다.

  1. 재사용 가능 볼륨을 빌드 단계에 마운트하여 종속성 관리 도구가 빌드간에 캐시를 사용할 수 있습니다.
  2. 결과 이미지에 키를 남기지 말고 ssh 키를 빌드 (개인 리포지토리 등을 당기는 데 사용)와 공유하십시오.
  3. 다른 이미지로 응용 프로그램을 빌드하고 실행하여 하나의 이미지에서 다른 이미지로 쉽게 아티팩트를 전달할 수 있으며 이상적으로 단일 논리에이 논리가 있습니다.
  4. Dockerfiles에서 바로 이미지에 태그 / 푸시를 입력하십시오.
  5. 쉘 빌드 명령에서 변수를 전달하여 Dockerfile로 대체 할 수 있습니다.

그리고 더. Grammarly에서 Docker를 채택하지 못하게하는 가장 중요한 문제입니다.

업데이트 : Github의 공식 프로젝트 저장소에 따라 로커가 중단되었습니다.

2018 년 초 현재, 컨테이너 생태계는이 프로젝트가 시작된 3 년 전보다 훨씬 성숙되었습니다. 이제 로커의 독특하고 뛰어난 기능 중 일부는 도커 빌드 또는 기타 잘 지원되는 도구로 쉽게 덮을 수 있지만 일부 기능은 로커 고유의 기능을 유지합니다. 자세한 내용은 https://github.com/grammarly/rocker/issues/199 를 참조하십시오.


로커를 사용하여 문제 번호 1을 해결하려고하는데 mount 명령이 작동하지 않으며 작성된 이미지에 호스트 폴더가 없습니다. 내 Dockerfile 마운트 명령은 다음과 같습니다. MOUNT ~/code/docker-app-dev/new-editor/:/src/그리고 내 Rocker 빌드 명령은 다음과 같습니다 rocker build -f Dockerfile .. 내가 뭘 잘못하고 있니?
Yaron Idan

실제 호스트 경로를 사용해보십시오. ~Bourne 쉘 메타 문자입니다.
Jesse Glick

Rocker build허용하지 않는 docker run명령 줄 옵션을, 그래서 현재와 같은 일을 허용하지 않습니다 --privileged.
Monty Wild

@xpt 님 안녕하세요, 이제 로커가 중단 된 이후로 다른 업데이트를받을 수 있습니까
Shardj

이제 로커가 중단되었으므로 답을 "불가"로 다시 되돌립니다. OP 및 선택한 답변을 참조하십시오.
xpt

14

빌드 중에 볼륨을 마운트하는 방법이 있지만 Dockerfile은 포함하지 않습니다.

이 기법은 사용하려는베이스 ( 컨테이너에 볼륨을 -v옵션으로 마운트)에서 컨테이너를 생성하고 셸 스크립트를 실행하여 이미지 작성 작업을 수행 한 다음 완료되면 컨테이너 를 이미지로 커밋하는 것입니다. .

이렇게하면 원하지 않는 초과 파일 (SSH 파일과 같은 보안 파일에도 적합 함)이 없어 질뿐만 아니라 단일 이미지도 생성됩니다. 단점은 다음과 같습니다. commit 명령은 모든 Dockerfile 명령어를 지원하지 않으며 빌드 스크립트를 편집해야 할 때 중단했을 때 선택할 수 없습니다.

최신 정보:

예를 들어

CONTAINER_ID=$(docker run -dit ubuntu:16.04)
docker cp build.sh $CONTAINER_ID:/build.sh
docker exec -t $CONTAINER_ID /bin/sh -c '/bin/sh /build.sh'
docker commit $CONTAINER_ID $REPO:$TAG
docker stop $CONTAINER_ID

6
+1 두 번째 단락의 지침에 대해 좀 더 자세히 설명해 주시겠습니까? 예를 들어, base가 debian:wheezy있고 shell 스크립트가 build.sh이면 어떤 특정 명령어를 사용합니까?
Drux

6

컨테이너를 실행하면 호스트의 디렉토리가 작성되어 컨테이너에 마운트됩니다. 이 디렉토리가있는 디렉토리를 찾을 수 있습니다

$ docker inspect --format "{{ .Volumes }}" <ID>
map[/export:/var/lib/docker/vfs/dir/<VOLUME ID...>]

컨테이너 내부의 호스트에서 디렉토리를 마운트하려면 -v매개 변수를 사용하고 디렉토리를 지정해야합니다. 귀하의 경우 이것은 다음과 같습니다.

docker run -v /export:/export data

따라서 컨테이너 내부의 hosts 폴더를 사용합니다.


1
감사. 질문이 수정되었습니다. 실제로 해결하려는 질문은 빌드 중에 Dockerfile의 docker 컨테이너에 호스트 볼륨을 마운트하는 방법입니다. 고마워.
xpt

과감한 방식으로 질문을 수정하지 마십시오 . 편집하기 전에 완벽하게 유효했지만 내 질문이 유효하지 않습니다. 대신 새로운 질문을하십시오.
Behe

11
원래 질문 : Dockerfile에서 VOLUME 명령을 사용하는 방법은 무엇입니까? 오늘날에도 여전히 질문의 시작 부분에 있습니다. 귀하의 답변은 런타임 에 대한 것이며, 제 질문은 항상 빌드 시간 에 관한 것입니다 .Dockerfile의 목적입니다.
xpt

4

도커 컨테이너 내부에서 실행되는 docker 명령을 통해 빌드를 실행하여 원하는 작업을 수행 할 수 있다고 생각합니다. Docker에서 Docker를 실행할 수 있음을 참조하십시오. 도커 블로그 . 컨테이너를 사용하여 외부 도커에 실제로 액세스하는 이와 같은 기술이 예를 들어 가능한 가장 작은 Docker 컨테이너만드는 방법을 탐색하는 동안 사용되었습니다. 제 비아 블로그 .

다른 관련 기사는 Docker 이미지 최적화 | CenturyLink Labs 는 빌드 중에 물건을 다운로드하면 결국 하나의 RUN 단계에서 다운로드를 다운로드, 빌드 및 삭제하여 최종 이미지에서 공간을 낭비하지 않도록 할 수 있다고 설명합니다.


3

그것은 추악하지만, 나는 다음과 같이 비슷합니다.

도커 파일 :

FROM foo
COPY ./m2/ /root/.m2
RUN stuff

imageBuild.sh :

docker build . -t barImage
container="$(docker run -d barImage)"
rm -rf ./m2
docker cp "$container:/root/.m2" ./m2
docker rm -f "$container"

유니버스를 /root/.m2로 다운로드하고 매번 그렇게하는 Java 빌드가 있습니다 . imageBuild.sh빌드 후 해당 폴더의 내용을 호스트에 Dockerfile복사하고 다음 빌드를 위해 이미지에 다시 복사합니다.

이것은 볼륨의 작동 방식과 같습니다 (즉, 빌드간에 유지됨).


이는 Docker 기반 연속 통합 일명 CI에 적합한 솔루션입니다. 라이브러리와 컴파일러를 설정하고 Dockerfile 명령을 통해 make를 실행하고 컨테이너를 만들기 위해 이미지를 간단하게 시작한 다음 .deb와 같은 원하는 아티팩트를 복사하십시오. 게시 해 주셔서 감사합니다.
chrisinmtown

이 솔루션을 사용하면 ./m2/에 모든 파일이 포함 된 이미지 (필요한 파일과 필요없는 파일)가 남게되므로 원치 않는 거대한 프로덕션 이미지가 생성 될 수 있습니다! 외부 종속성 디렉토리에 마운트하면 필요한 파일 만 이미지로 복사됩니다.
Marko Krajnc

이미지를 게시하려는 경우 기다릴 때마다 매번 새로운 의존성을 새로 다운로드하는 것이 가장 좋습니다. 이 해킹은 테스트 할 이미지 (최종 사용자가 절대 접촉하지 않는 이미지)를 준비하는 경우에만 의미가 있습니다.
MatrixManAtYrService

1

다음은 쉘 스크립트없이 빌드 및 커밋을 사용하는 단순화 된 2 단계 접근 방식입니다. 여기에는 다음이 포함됩니다.

  1. 볼륨없이 이미지를 부분적으로 빌드
  2. 볼륨이 있는 컨테이너 실행 하고 변경 한 다음 결과를 커밋하고 원래 이미지 이름을 바꿉니다.

비교적 약간의 변경으로 추가 단계는 빌드 시간에 몇 초만 추가됩니다.

원래:

docker build -t image-name . # your normal docker build

# Now run a command in a throwaway container that uses volumes and makes changes:
docker run -v /some:/volume --name temp-container image-name /some/post-configure/command

# Replace the original image with the result:
# (reverting CMD to whatever it was, otherwise it will be set to /some/post-configure/command)   
docker commit --change="CMD bash" temp-container image-name 

# Delete the temporary container:
docker rm temp-container

유스 케이스에서는 maven toolchains.xml 파일을 미리 생성하려고하지만 많은 JDK 설치가 런타임까지 사용할 수없는 볼륨에 있습니다. 일부 이미지는 모든 JDKS와 호환되지 않으므로 빌드시 호환성을 테스트하고 toolchains.xml을 조건부로 채워야합니다. 휴대용 이미지가 필요하지 않으며 Docker Hub에 게시하지 않습니다.


1

이미 많은 사람들이 대답했듯이 빌드 중에 호스트 볼륨을 마운트 할 수 없습니다. 방금 docker-compose방법 을 추가하고 싶습니다 . 주로 개발 / 테스트 용도로 사용하는 것이 좋을 것이라고 생각합니다.

도커 파일

FROM node:10
WORKDIR /app
COPY . .
RUN npm ci
CMD sleep 999999999

docker-compose.yml

version: '3'
services:
  test-service:
    image: test/image
    build:
      context: .
      dockerfile: Dockerfile
    container_name: test
    volumes:
      - ./export:/app/export
      - ./build:/app/build

그리고 컨테이너를 docker-compose up -d --build

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