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

원래 질문 : 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



답변

먼저 “왜 작동하지 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 이상이 필요한 경우에만 작동합니다.


답변

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

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


답변

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

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

해결책은 로커입니다 : 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 를 참조하십시오.


답변

빌드 중에 볼륨을 마운트하는 방법이 있지만 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


답변

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

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

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

docker run -v /export:/export data

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


답변

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

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


답변

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

도커 파일 :

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복사하고 다음 빌드를 위해 이미지에 다시 복사합니다.

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