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

从Docker文档中:

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

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

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

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


当前回答

我花了很长时间试图找出一个好的模式,以及如何更好地解释这个特性支持的情况。我意识到最好的解释方法如下。。。

Dockerfile:将只看到其自身相对路径下的文件上下文:“空间”中的一个位置,您要共享的文件和Dockerfile将被复制到该位置

因此,尽管如此,这里有一个Dockerfile的示例,它需要重用一个名为start.sh的文件

Dockerfile文件

它将始终从其相对路径加载,将其当前目录作为指定路径的本地引用。

COPY start.sh /runtime/start.sh

文件夹

考虑到这个想法,我们可以考虑为Dockerfile创建多个副本来构建特定的东西,但它们都需要访问start.sh。

./all-services/
   /start.sh
   /service-X/Dockerfile
   /service-Y/Dockerfile
   /service-Z/Dockerfile
./docker-compose.yaml

考虑到这个结构和上面的文件,这里有一个docker-compose.yml

码头组合.yaml

在本例中,共享上下文目录是运行时目录。这里的思维模式是一样的,认为这个目录下的所有文件都被移到了所谓的上下文中。同样,只需指定要复制到同一目录的Dockerfile。可以使用dockerfile指定。主要内容所在的目录是要设置的实际上下文。

docker-compose.yml如下

version: "3.3"
services:
  
  service-A
    build:
      context: ./all-service
      dockerfile: ./service-A/Dockerfile

  service-B
    build:
      context: ./all-service
      dockerfile: ./service-B/Dockerfile

  service-C
    build:
      context: ./all-service
      dockerfile: ./service-C/Dockerfile

所有服务都被设置为上下文,共享文件start.sh以及每个Dockerfile指定的Dockerfile都被复制到那里。每个人都可以按照自己的方式构建,共享开始文件!

其他回答

一个简单的解决方法可能是在运行该卷并以这种方式访问文件时,简单地将其装载(使用-v或--mount标志)到容器中。

例子:

docker run -v /path/to/file/on/host:/desired/path/to/file/in/container/ image_name

有关详细信息,请参阅:https://docs.docker.com/storage/volumes/

您还可以创建图像首先需要的内容的tarball,并将其用作上下文。

https://docs.docker.com/engine/reference/commandline/build/#/tarball-上下文

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

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

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

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

我在一个项目和一些数据文件中遇到了同样的问题,由于HIPAA的原因,我无法在回购上下文中移动这些文件。我最终使用了2个Dockerfile。一个构建主应用程序,而不需要我在容器外部所需的东西,并将其发布到内部存储库。然后,第二个dockerfile提取该图像并添加数据,然后创建一个新图像,然后将其部署并永远不会存储在任何地方。不太理想,但它对我将敏感信息排除在回购之外的目的起到了作用。

使用docker compose,我通过创建一个服务来装载所需的卷并提交容器的映像来完成这一点。然后,在后续服务中,我依赖于先前提交的映像,该映像将所有数据存储在装载位置。然后,您必须将这些文件复制到其最终目的地,因为在运行docker commit命令时不会提交主机装载的目录

你不必使用docker compose来实现这一点,但它会让生活变得简单一些

# docker-compose.yml

version: '3'
  services:
    stage:
      image: alpine
      volumes:
        - /host/machine/path:/tmp/container/path
      command: bash -c "cp -r /tmp/container/path /final/container/path"
    setup:
      image: stage
# setup.sh

# Start "stage" service
docker-compose up stage

# Commit changes to an image named "stage"
docker commit $(docker-compose ps -q stage) stage

# Start setup service off of stage image
docker-compose up setup