Docker COPY命令未挂载目录

时间:2019-03-16 14:41:48

标签: docker docker-compose

Host OS: Linux
Container OS: Linux

我正在尝试学习如何使用docker。我使用docker-compose,成功构建了映像并运行了容器。

现在,如果我想在容器内挂载某个目录,文档说明我应该在Dockerfile中使用COPY命令。

COPY /path/to/my/addons/ /path/to/directory/inside/container

可悲的是,当我编写此容器时,COPY命令将被忽略,并且/ path / to / my / addons中的内容无法放入该容器中。

我也尝试过使用ADD命令,但是同样的问题。

3 个答案:

答案 0 :(得分:4)

绝对路径

首先,您不能为COPY使用绝对路径。所有路径都必须为inside the context of the build,这意味着相对于Dockerfile。如果主机上的文件夹结构是这样

my-docker-directory
-- Dockerfile
-- docker-compose.yml
-- addons

然后您就可以使用COPY addons /path/to/directory/inside/container。对于所有后续解释,我假设您相对于addons有一个Dockerfile文件夹。

安装目录

COPY并不只是在运行时将文件夹安装到容器。它实际上根本没有 mount 目录。而是将addons复制到图像中的/path/to/directory/inside/container。重要的是要了解,此过程是单向发生的(主机>映像),并且仅在生成映像时发生。

COPY旨在向构建时所需的映像添加依赖项,例如已编译为二进制文件的源代码。这就是为什么您不能使用绝对路径的原因。通常将Dockerfile与源代码/配置文件放在顶层区域。

图像的构建过程仅在第一次运行时发生,除非您使用docker-compose up --build对其进行强制。但这似乎并不是您想要的。要在运行时从主机挂载目录,请在volume文件中使用docker-compose

version: '3'
services:
  test:
    build: .
    volumes:
      - ./addons/:/path/to/directory/inside/container

何时使用COPY以及何时使用卷?

重要的是要意识到COPYADD会在构建时将内容复制到映像中,其中volumes在运行时将它们从主机上挂载(而不将其包含在图片中)。因此,通常会将用户需要的常规内容复制到映像中,例如默认配置文件。

卷必须包含来自主机的文件,例如自定义配置文件。或将持久性事物作为数据库的数据目录。没有卷,这些容器就可以工作,但不是持久的。因此,当容器重新启动时,所有内容都会丢失。

请注意,一个并不排除另一个。最好为映像中的某些应用程序设置COPY的默认配置,在该配置中,用户可以使用卷覆盖该配置以对其进行修改。特别是在开发过程中,这可以使事情变得更容易,因为您不必为单个更改的配置文件重建整个映像*

*尽管为集成缓存机制优化Dockerfile是一个很好的实践。如果Dockerfile写得很好,重建小型配置更改通常不会花费太长时间。但这是这个范围之外的另一个话题。

示例更详细的解释

COPY中用Dockerfile进行的基本设置

作为一个简单的示例,我们从nginx Web服务器图像创建一个Dockerfile并在其中复制html

FROM nginx:alpine
COPY my-html /usr/share/nginx/html

让我们用演示内容创建文件夹

mkdir my-html
echo "Dockerfile content" > my-html/index.html

并添加一个简约的docker-compose.yml

version: '3'
services:
  test:
    build: .

如果我们是第一次使用docker-compose up -d运行它,则图像已构建并提供了我们的测试页:

root@server2:~/docker-so-example# docker-compose up -d
Creating network "docker-so-example_default" with the default driver
Creating docker-so-example_test_1 ... done

root@server2:~/docker-so-example# curl $(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' docker-so-example_test_1)
Dockerfile content

让我们操作我们的测试文件:

echo "NEW Modified content" > my-html/index.html

如果再次使用curl请求服务器,则会得到旧的响应:

root@server2:~/docker-so-example# curl $(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' docker-so-example_test_1)
Dockerfile content

要应用我们的内容,需要重新构建:

docker-compose down && docker-compose up -d --build

现在我们可以看到我们的更改:

root@server2:~/docker-so-example# curl $(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' docker-so-example_test_1)
NEW Modified content

使用docker-compose中的卷

为显示差异,我们通过修改docker-compose.yml文件来使用卷,如下所示:

version: '3'
services:
  test:
    build: .
    volumes:
      - ./my-html:/usr/share/nginx/html

现在使用docker-compose down && docker-compose up -d重新启动容器,然后重试:

root@server2:~/docker-so-example# echo "Again changed content" > my-html/index.html
root@server2:~/docker-so-example# curl $(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' docker-so-example_test_1)
NEW Modified content
root@server2:~/docker-so-example# echo "Some content" > my-html/index.html
root@server2:~/docker-so-example# curl $(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' docker-so-example_test_1)
Some content

请注意,我们没有重新构建图像,我们的修改立即生效。使用卷,文件不包含在图像中。

答案 1 :(得分:0)

将您的插件文件夹移至Dockerfile所在的位置,然后运行

mkdir -p /path/to/directory/inside/container
COPY ./addons/* /path/to/directory/inside/container

答案 2 :(得分:0)

泊坞窗文件中的

COPY命令在构建时将内容复制到映像。安装卷是另一回事。要进行安装,您需要使用

docker run -v <volume_name>:<volume_name> ...

您到底要实现什么?您是否要查看主机中容器内的文件夹?