如何在Docker文件中使用“ADD”命令包含Docker构建上下文之外的文件?

从Docker文档中:

路径必须位于生成的上下文中;您不能添加../something/something,因为docker构建的第一步是将上下文目录(和子目录)发送到docker守护进程。

我不想重组我的整个项目,只是为了在这件事上适应Docker。我想将所有Docker文件保存在同一个子目录中。

此外,Docker似乎还不支持符号链接:Dockerfile ADD命令不支持主机#1676上的符号链接。

我唯一能想到的另一件事是包含一个预构建步骤,将文件复制到Docker构建上下文中(并配置我的版本控制以忽略这些文件)。还有比这更好的解决方法吗?


当前回答

我认为更简单的解决方法是改变“上下文”本身。

因此,例如,不要给出:

docker build -t hello-demo-app .

它将当前目录设置为上下文,假设您希望父目录作为上下文,只需使用:

docker build -t hello-demo-app ..

其他回答

如何在两个Dockerfile之间共享typescript代码

我也遇到过同样的问题,只是在两个typescript项目之间共享文件。其他一些答案对我不起作用,因为我需要保留共享代码之间的相对导入路径。我通过这样组织代码来解决这个问题:

api/
  Dockerfile
  src/
    models/
      index.ts

frontend/
  Dockerfile
  src/
    models/
      index.ts

shared/
  model1.ts
  model2.ts
  index.ts

.dockerignore

注意:在将共享代码提取到顶部文件夹后,我避免了更新导入路径,因为我更新了api/models/index.ts和frontend/models//index.ts以从共享导出:(例如export*from'../../shared)

由于构建上下文现在高了一个目录,我不得不做一些额外的更改:

更新build命令以使用新上下文:docker build-f Dockerfile。。(两个点而不是一个)在顶层使用一个.dockerignore来排除所有node_module。(例如**/node_modules/**)在Dockerfile COPY命令前面加上api/或frontend/复制共享(除了api/src或frontend/src)工作目录/usr/src/appCOPY api/package*.json./<----前缀为api/运行npm ciCOPY api/src api/ts*.json./<----前缀为api/复制共享usr/src/shared<----添加RUN npm运行构建

这是我可以将所有内容发送到docker的最简单方法,同时保留两个项目中的相对导入路径。棘手的(令人讨厌的)部分是构建上下文在一个目录中引起的所有更改/后果。

在Linux上,您可以装载其他目录,而不是符号链接它们

mount --bind olddir newdir

看见https://superuser.com/questions/842642了解更多详情。

我不知道其他操作系统是否也有类似的功能。我还尝试使用Samba共享一个文件夹并将其重新安装到Docker上下文中,这同样有效。

创建一个包装docker构建shell脚本,该脚本获取文件,然后调用docker构建,然后删除文件。

在我的快速浏览中,这里没有提到一个简单的解决方案:

有一个名为docker_build.sh的包装脚本让它创建tarball,将大文件复制到当前工作目录调用docker构建清理油布球、大文件等

这个解决方案很好,因为(1.)它没有复制SSH私钥的安全漏洞(2.)另一个解决方案使用sudo绑定,所以它有另一个安全漏洞,因为它需要root权限才能进行绑定。

如果您阅读第2745期中的讨论,不仅docker可能永远不支持符号链接,他们也可能永远不会支持在您的上下文之外添加文件。这似乎是一种设计理念,即进入docker构建的文件应该明确地成为其上下文的一部分,或者来自一个URL,在该URL中,它可能也会以固定版本部署,这样构建就可以用docker容器附带的公知URL或文件重复。

我更喜欢从版本控制的源代码构建,即docker构建-t东西http://my.git.org/repo-否则我会在随机的地方用随机文件进行构建。从根本上说,不是……——斯文·多维迪特,多克公司

只是我的看法,但我认为您应该进行重组,以分离代码和docker存储库。这样,容器可以是通用的,并在运行时而不是构建时引入任何版本的代码。

或者,使用docker作为基本的代码部署工件,然后将dockerfile放在代码存储库的根目录中。如果您这样做,那么使用父docker容器获取更一般的系统级详细信息和子容器获取特定于您的代码的设置可能是有意义的。

在我的例子中,Dockerfile就像一个包含占位符的模板一样编写,我使用配置文件将其替换为实际值。

所以我不能直接指定这个文件,而是像这样将其导入docker构建:

sed "s/%email_address%/$EMAIL_ADDRESS/;" ./Dockerfile | docker build -t katzda/bookings:latest . -f -;

但由于管道的原因,COPY命令无法工作。但上述方法通过-f(明确表示未提供文件)来解决问题。只执行-如果不使用-f标志,则不会提供上下文和Dockerfile,这是一个警告。