自2014年提出这个问题以来,发生了许多情况,许多事情发生了变化。今天我再次讨论这个话题,这是我第12次编辑这个问题,以反映最新的变化。这个问题可能看起来很长,但它是按倒序排列的,所以最新的变化在顶部,你可以随时停止阅读。

我想解决的问题是——如何在构建过程中将主机卷挂载到Dockerfile中的docker容器中,即在docker构建过程中让docker运行-v /export:/export功能。

对我来说,这背后的一个原因是,当在Docker中构建东西时,我不希望那些(apt-get install)缓存被锁定在单个Docker中,而是共享/重用它们。

这就是我问这个问题的主要原因。我今天面临的另一个原因是试图利用来自主机的巨大私有回购,否则我必须使用我的私有ssh密钥从docker中的私有回购中做git克隆,我不知道如何,也没有研究过。

最新更新:

@BMitch回答中的Buildkit

使用RUN——mount语法,你还可以从build-context…

它现在已经内置在docker(我认为是第三方工具)中,只要你的版本超过18.09。我的现在是20.10.7 https://docs.docker.com/develop/develop-images/build_enhancements/

要启用BuildKit构建 重新安装docker最简单的方法是在调用docker build命令时设置DOCKER_BUILDKIT=1环境变量,例如: $ DOCKER_BUILDKIT=1个docker build。

否则,你会得到:

——mount选项需要BuildKit。参考https://docs.docker.com/go/buildkit/了解如何在启用BuildKit的情况下构建图像

因此,它将是我上面解释的第二个用例的完美解决方案。

截至2019年5月7日更新:

在docker v18.09之前,正确的答案应该是以:

有一种方法可以在构建期间挂载卷,但它不涉及Dockerfiles。

然而,这是一个陈述不当、组织不当和支持不足的回答。当我重新安装我的docker contains时,我碰巧发现了以下文章:

Dockerize apt-cache -ng服务 https://docs.docker.com/engine/examples/apt-cacher-ng/

这是码头工人对这个/我的问题的解决方案,不是直接的,而是间接的。这是docker建议我们做的正统方法。我承认这比我在这里想问的要好。

另一种方法是,新接受的答案,例如,v18.09中的Buildkit。

挑一个适合你的。


Was:曾经有一个解决方案- rocker,这不是来自Docker,但现在rocker已经停止,我将答案再次回复为“不可能”。


Old Update: So the answer is "Not possible". I can accept it as an answer as I know the issue has been extensively discussed at https://github.com/docker/docker/issues/3156. I can understand that portability is a paramount issue for docker developer; but as a docker user, I have to say I'm very disappointed about this missing feature. Let me close my argument with a quote from aforementioned discussion: "I would like to use Gentoo as a base image but definitely don't want > 1GB of Portage tree data to be in any of the layers once the image has been built. You could have some nice a compact containers if it wasn't for the gigantic portage tree having to appear in the image during the install." Yes, I can use wget or curl to download whatever I need, but the fact that merely a portability consideration is now forcing me to download > 1GB of Portage tree each time I build a Gentoo base image is neither efficient nor user friendly. Further more, the package repository WILL ALWAYS be under /usr/portage, thus ALWAYS PORTABLE under Gentoo. Again, I respect the decision, but please allow me expressing my disappointment as well in the mean time. Thanks.


原问题详情:

From

通过卷共享目录 http://docker.readthedocs.org/en/v0.7.3/use/working_with_volumes/

它说数据卷功能“从Docker远程API的版本1开始就可以使用”。我的docker是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命令将主机挂载的卷装入docker容器的正确方法是什么?

$ 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-compose方式,我认为它会很好,主要用于开发/测试用途

Dockerfile

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运行容器

其他回答

有一种方法可以在构建期间挂载卷,但它不涉及Dockerfiles。

该技术将从您想使用的任何基础上创建一个容器(使用-v选项将您的卷安装到容器中),运行shell脚本来进行映像构建工作,然后在完成后将容器作为映像提交。

这不仅省去了您不想要的多余文件(这也适用于安全文件,如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

如果你正在寻找一种“挂载”文件的方法,比如-v用于docker run,你现在可以使用——secret标志用于docker build

echo 'WARMACHINEROX' > mysecret.txt
docker build --secret id=mysecret,src=mysecret.txt .

在Dockerfile中,你可以访问这个秘密

# syntax = docker/dockerfile:1.0-experimental
FROM alpine

# shows secret from default secret location:
RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret

# shows secret from custom secret location:
RUN --mount=type=secret,id=mysecret,dst=/foobar cat /foobar

更多关于——secret的深入信息可以在Docker Docs上找到

我认为你可以通过docker命令来运行构建,这个命令本身是在docker容器中运行的。看到Docker现在可以运行在Docker | Docker博客。像这样的技术,但实际上是从容器访问外部docker,被使用,例如,当探索如何创建最小的docker容器| Xebia Blog。

另一篇相关文章是优化Docker图像| CenturyLink Labs,它解释了如果你在构建过程中下载了一些东西,你可以通过在一个RUN步骤中下载、构建和删除下载来避免在最终映像中浪费空间。

由于Windows容器仍然不支持BuildKit,一种替代方法是使用网络共享。这将创建一个最小的Docker映像大小,因为安装程序是在单个RUN语句期间从容器中添加/删除的。

将EXE / MSI文件放在主机上的一个文件夹中 共享文件夹 开始构建Docker 从Docker容器内映射共享 复制+运行+删除每个安装程序 移除容器内的映射 Docker构建 取消主机上的共享文件夹

下面是一个创建Java 11 Windows容器的工作示例:

build.cmd:

host=%COMPUTERNAME%
set domainAndUser=whoami
set "pswd=<host-password>"
set "shareName=tmpSmbShare"
set netPath=\\%COMPUTERNAME%\%shareName%
set "localPath=C:/Users/tester/Desktop/docker/Java11/winsrvcore/installers"

powershell New-SmbShare -Name %shareName% -Path %localPath% -FullAccess "Everyone"
docker build ^
--build-arg domainAndUser=%domainAndUser% ^
--build-arg pswd=%pswd% ^
--build-arg netPath=%netPath% ^
-t <docker-username>/java-11.0.16-winsrvcore.ltsc2019:1.0 .
powershell Remove-SmbShare -Name %shareName% -Force

Dockerfile:

FROM mcr.microsoft.com/windows/servercore:ltsc2019-amd64

ARG domainAndUser
ARG pswd
ARG netPath

RUN powershell New-SMBMapping -LocalPath "R:" -RemotePath "$env:netPath" -UserName "$env:domainAndUser" -Password "$env:pswd" \
    && dir "R:/" \
    && copy "R:/jdk-11.0.16_windows-x64_bin.exe" "C:/" \
    && powershell Start-Process -filepath 'C:/jdk-11.0.16_windows-x64_bin.exe' -Wait -PassThru -ArgumentList "/s,/L,install64.log" \
    && powershell Remove-SMBMapping -LocalPath "R:" -Force \
    && del "C:/jdk-11.0.16_windows-x64_bin.exe" 

ENV JAVA_HOME "C:\Program Files\Java\jdk-11.0.16"

在运行容器时,将在主机上创建一个目录并将其挂载到容器中。你可以找到它所在的目录

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

如果要在容器中挂载来自主机的目录,则必须使用-v参数并指定目录。在你的情况下,这将是:

docker run -v /export:/export data

你可以在容器中使用hosts文件夹。