Docker ADD与VOLUME


116

我正在学习Docker,并且对何时何地使用ADDand 有疑问VOLUME。我认为这两个都是这样做的:

在构建时将文件复制到映像。该映像包含所有文件,因此您可以非常轻松地进行部署。另一方面,在每次开发中都需要构建似乎不是一个好主意,因为构建需要开发人员运行命令来重建容器。另外,建造容器可能很耗时。

我了解docker run -v您可以使用容器文件夹安装主机文件夹,这样您可以轻松地修改文件并观察容器中的应用程序对更改的反应。在开发中看起来很棒,但是我不确定如何以这种方式部署文件。


3
在一般情况下,最好还是喜欢COPYADD。它们几乎相同,但ADD具有URL和存档文件的一些额外功能,这可能令人惊讶。
Adrian Mouat 2015年

2
@jamesmstone-该链接(和官方docker文档)建议相反-使用COPY而不是ADD。
软件工程师

糟糕,您是对的-干杯!
jamesmstone

Answers:


183

两者之间的根本区别在于,ADD无论您要添加的内容是文件夹还是文件,它实际上都是图像的一部分。任何使用您之后构建的图像的人都可以访问您所拥有的任何内容ADD。即使后来删除它,也是如此,因为Docker在层中工作并且该ADD层仍将作为映像的一部分存在。需要明确的是,您只能ADD在构建时进行操作,而不能ADD在运行时进行操作。

您想使用的一些例子ADD

  • 您有要引用并安装在Dockerfile中的requirements.txt文件中的一些要求。然后,您可以做:ADD ./requirements.txt /requirements.txt后面RUN pip install -r /requirements.txt
  • 您想将应用程序代码用作Dockerfile中的上下文,例如,如果要将应用程序目录设置为映像中的工作目录,并希望从映像中运行容器中的默认命令实际运行您的应用程序,可以做:

    ADD ./ /usr/local/git/my_app

    WORKDIR /usr/local/git/my_app

    CMD python ./main.py

另一方面,Volume只允许从映像运行的容器可以访问容器运行所在的任何本地计算机上的某些路径。您不能VOLUME在Dockerfile中使用目录中的文件。卷目录中的任何内容都会不会在编译时访问的,但会在运行时可以访问

您想使用的一些例子 VOLUME

  • 在容器中运行的应用程序使登录 /var/log/my_app。您希望这些日志在主机上可以访问,而在删除容器时不要删除。您可以通过以下方法创建挂载点:/var/log/my_app添加VOLUME /var/log/my_app到Dockerfile,然后使用docker run -v /host/log/dir/my_app:/var/log/my_app some_repo/some_image:some_tag
  • 您有一些本地设置文件,希望容器中的应用可以访问。也许这些设置文件在本地计算机,开发环境和生产环境上是不同的。特别是如果这些设置文件是秘密文件,则在这种情况下,您绝对不希望它们出现在图像中。在这种情况下,一个好的策略是添加VOLUME /etc/settings/my_app_settings到Dockerfile中,使用来运行您的容器docker run -v /host/settings/dir:/etc/settings/my_app_settings some_repo/some_image:some_tag,并确保/ host / settings / dir存在于您希望运行应用程序的所有环境中。

13
到目前为止,我发现的最有用的帖子是ADD和VOLUME
Jasmeet18年

5
如果指定了VOLUME但在docker运行期间未提供VOLUME(例如-v xxx参数缺失),会发生什么?是resp。音量然后有效地变为瞬态?
col.panic 18-3-21

在Dockerfile中,卷可能仅用于持久性和/或调试,但是您可以使用volume命令行开关将应用程序放入现有映像(无需Dockerfile)并像这样运行它docker run -v $HOST_PATH:$CONTAINER_PATH node:latest node $CONTAINER_PATH/app.js
Chinoto Vokro

漂亮的“图层”细节
stratovarius

27

VOLUME指令在运行时在Docker容器中创建一个数据卷。作为参数提供VOLUME的目录是绕过Union File System的目录,主要用于持久性数据和共享数据。

如果运行docker inspect <your-container>,您将在该Mounts部分下看到,Source它代表主机上的目录位置,而Destination代表容器中已装载的目录位置。例如,

"Mounts": [
  {
    "Name": "fac362...80535",
    "Source": "/var/lib/docker/volumes/fac362...80535/_data",
    "Destination": "/webapp",
    "Driver": "local",
    "Mode": "",
    "RW": true,
    "Propagation": ""
  }
]

以下是3个用例docker run -v

  1. docker run -v /data:类似于VOLUME在Dockerfile中指定指令。
  2. docker run -v $host_path:$container_path:这允许您在运行时$host_path从主机挂载到$container_path容器中。在开发中,这对于与容器共享主机上的源代码很有用。在生产中,这可以用于将主机的DNS信息(位于中/etc/resolv.conf)或机密信息装入容器。相反,您也可以使用此技术将容器的日志写入主机上的特定文件夹。双方$host_path$container_path必须是绝对路径。
  3. docker run -v my_volume:$container_path:这将在您的容器中创建一个数据卷$container_path并为其命名my_volume。它本质上与使用创建和命名卷相同docker volume create my_volume。使用诸如Flocker之类的多主机存储驱动程序,这样命名卷对于容器数据卷和共享存储卷很有用

注意,将主机文件夹作为数据卷挂载的方法在Dockerfile中不可用。要引用Docker文档

注意:由于Dockerfile的可移植性和共享目的,因此该文件不可用。由于主机目录从本质上说是与主机相关的,因此Dockerfile中指定的主机目录可能无法在所有主机上正常工作。

现在,如果要将文件复制到非开发环境中的容器中,则可以使用Dockerfile中的ADDCOPY说明。这些是我通常用于非开发部署的内容。


3
我应该创建2个docker文件吗?一种用于开发,一种用于部署?
Cristian Garcia 2015年

我不这么认为。将ADD指令包含在Dockerfile中没有任何问题,因为该指令仅由docker build命令执行。当其他人第一次构建您的容器,并且准备将其部署到其他非开发环境时,则需要这样做。
ivan.sim 2015年

3
但是在没有文件的情况下构建映像并使用该-v命令进行开发,并让另一个docker文件创建包含ADD用于部署的文件的映像,会不会更高效?
Cristian Garcia

1
您必须权衡取舍。选择适合您的东西。ADD反正构建需要多长时间?总共几秒钟?如果你有两个Dockerfile文件,你与他人共享(或发布在泊坞窗注册表),其中一个是默认?您将有一些额外的维护开销,以确保将正确的默认Dockerfile传递给正确的用户。但是到了最后,您可以决定最适合自己的方法。我个人希望确保只有一个Dockerfile可以构建我的容器。
ivan.sim 2015年

11
顺便说一句,我认为先添加即可,然后使用-v覆盖添加以进行开发就可以了。这样,您将不需要单独的Dockerfile。
Attila Szeremi
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.