自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 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博客。像这样的技术,但实际上是从容器访问外部docker,被使用,例如,当探索如何创建最小的docker容器| Xebia Blog。

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

Git克隆从一个私人回购在docker使用我的私人SSH密钥

在使用BuildKit创建Linux映像时,docker build还使用——SSH标志提供SSH代理转发。Docker在build中使用SSH访问私有数据,Dockerfile可以在RUN命令中使用——mount=type= SSH,将SSH身份验证委托给主机的SSH代理:

# syntax=docker/dockerfile:1
FROM alpine
RUN apk add --no-cache openssh-client git

# Download public key of remote server at github.com 
RUN mkdir -p -m 0700 ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts

# Enable verbose output (optional)
ENV GIT_SSH_COMMAND='ssh -Tvv'

# Clone using private keys known to SSH agent on the host
RUN --mount=type=ssh git clone git@github.com:myorg/myproject.git myproject

在构建时,上面的程序基本上可以通过简单地运行来使用主机的SSH密钥:

docker build --ssh default .

在主机上,这需要使用ssh-add进行一些配置,如上面链接的文档中所述;如果一切正常,那么echo $SSH_AGENT_SOCK或echo $SSH_AUTH_SOCK中的一个应该会给你一些输出,ssh-add -L应该会显示上面可用的标识。

使用详细日志记录时可能出现的一些错误:

主机密钥验证失败:您没有将远程主机添加到映像的~/.ssh/known_hosts pubkey_prepare: ssh_get_authentication_socket:没有这样的文件或目录:你忘记在docker build中包含——ssh默认参数 pubkey_prepare: ssh_get_authentication_socket: Permission denied: are you using some USER <username>?然后使用——mount=type=ssh,uid=<uid>指定它的用户id,或者使用——mount=type=ssh,mode=0666向所有用户打开套接字

这也适用于PIP/Conda/Mamba直接从版本控制安装Python依赖项,如git+ssh://git@github.com/myorg/myproject.git@mybranch#egg=myproject:

RUN --mount=type=ssh mamba env create -n myenv --file conda_environment.yml

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

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

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

docker run -v /export:/export data

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

不可能使用VOLUME指令告诉docker要挂载什么。这将严重破坏可移植性。这条指令告诉docker,这些目录中的内容不会放在图像中,并且可以使用——volumes-from命令行参数从其他容器中访问。必须使用-v /path/on/host:/path/in/container命令运行容器才能访问主机上的目录。

无法在构建期间挂载主机卷。没有特权构建,安装主机也会严重降低可移植性。您可能想尝试使用wget或curl下载构建所需的任何内容,并将其放置到合适的位置。

更新:有人就是不会把“不”作为答案,我很喜欢,尤其是这个特别的问题。

好消息,现在有办法了

解决方案是Rocker: https://github.com/grammarly/rocker

约翰·亚尼说, “在我看来,它解决了Dockerfile的所有弱点,使其适合开发。”

摇滚歌手

https://github.com/grammarly/rocker

By introducing new commands, Rocker aims to solve the following use cases, which are painful with plain Docker: Mount reusable volumes on build stage, so dependency management tools may use cache between builds. Share ssh keys with build (for pulling private repos, etc.), while not leaving them in the resulting image. Build and run application in different images, be able to easily pass an artifact from one image to another, ideally have this logic in a single Dockerfile. Tag/Push images right from Dockerfiles. Pass variables from shell build command so they can be substituted to a Dockerfile. And more. These are the most critical issues that were blocking our adoption of Docker at Grammarly.

更新:根据Github上的官方项目回购,Rocker已经停产

截至2018年初,容器生态系统比三年前这个项目启动时要成熟得多。现在,虽然有些特性仍然是rocker独有的,但docker构建或其他支持良好的工具可以很容易地覆盖rocker的一些关键和突出的特性。详情见https://github.com/grammarly/rocker/issues/199。