自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

当前回答

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

其他回答

由于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"

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

好消息,现在有办法了

解决方案是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。

如果你正在寻找一种“挂载”文件的方法,比如-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步骤中下载、构建和删除下载来避免在最终映像中浪费空间。

正如许多人已经回答的那样,在构建期间挂载主机卷是不可能的。我只是想添加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运行容器