Docker ADD vs VOLUME
我正在学习docker,我对何时何地使用ADD和VOLUME表示怀疑。以下是我认为这两种方法的作用:
添加
在生成时将文件复制到映像。映像包含所有文件,因此您可以非常轻松地部署。另一方面,在开发中,每次都需要构建看起来并不是一个好主意,因为构建需要开发人员运行一个命令来重建容器;此外,构建容器可能非常耗时。
体积
我了解到,使用docker run -v,您可以在容器中装入一个主机文件夹,这样您就可以轻松地修改文件并观察容器中的应用程序对更改的反应。它在开发中看起来很好,但我不确定如何以这种方式部署我的文件。
- 一般来说,最好是选择COPY而不是ADD。它们几乎是相同的,但是ADD有一些额外的能力来处理URL和归档文件,这可能会令人惊讶。
- 我不认为是这样的:我认为你必须使用ADD而不是COPY。请看这里。
- @jamesstone——链接(和官方Docker文档)建议相反——使用copy而不是add。
- 噢,你说得对-干杯!
添加
这两者之间的根本区别在于,ADD可以制作您添加的任何内容,无论是文件夹还是文件,实际上都是图像的一部分。任何使用您之后创建的图像的人都可以访问您的ADD。这是真的,即使您后来删除它,因为docker工作在层和ADD层仍将作为图像的一部分存在。很明显,您在构建时只使用ADD的东西,在运行时不能使用ADD。
您希望使用ADD的几个示例:
- 在requirements.txt文件中,您有一些需要要参考并安装在dockerfile中。你可以这样做: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
体积
另一方面,卷只允许从映像运行的容器访问运行容器的任何本地计算机上的某个路径。您不能使用dockerfile中的VOLUME目录中的文件。卷目录中的任何内容在生成时都无法访问,但在运行时可以访问。
您希望使用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运行容器。
- 您有一些本地设置文件希望容器中的应用程序可以访问。也许这些设置文件在本地计算机上与dev和production上是不同的。尤其是如果这些设置文件是秘密的,在这种情况下,您肯定不希望它们出现在您的图像中。在这种情况下,一个好的策略是将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存在于您希望运行应用程序的所有环境中。
- 到目前为止,我在"添加"和"音量"上找到的最有用的帖子
- 如果指定了卷,但在Docker运行期间未提供卷,会发生什么情况(例如-v xxx参数丢失)?是RESP。体积然后有效地变为瞬态?
- 在dockerfile中,卷可能只用于持久性和/或调试,但是您可以使用volume命令行开关将应用程序获取到现有映像中(不需要dockerfile),然后像这样运行docker run -v $HOST_PATH:$CONTAINER_PATH node:latest node $CONTAINER_PATH/app.js。
- 漂亮的"层次"细节
VOLUME指令在运行时在Docker容器中创建数据卷。作为VOLUME的参数提供的目录是一个绕过联合文件系统的目录,主要用于持久和共享数据。
如果运行docker inspect ,您将看到在Mounts部分下面有一个Source,表示主机上的目录位置,还有一个Destination,表示容器中装入的目录位置。例如,
1 2 3 4 5 6 7 8 9 10 11
| "Mounts": [
{
"Name":"fac362...80535",
"Source":"/var/lib/docker/volumes/fac362...80535/_data",
"Destination":"/webapp",
"Driver":"local",
"Mode":"",
"RW": true,
"Propagation":""
}
] |
这里有3个docker run -v的用例:
docker run -v /data:这类似于在dockerfile中指定VOLUME指令。
docker run -v $host_path:$container_path:这允许您在运行时将$host_path从主机安装到容器中的$container_path。在开发中,这对于在主机上与容器共享源代码很有用。在生产中,这可以用于将主机的DNS信息(在/etc/resolv.conf中找到)或机密等内容装入容器中。相反,您也可以使用此技术将容器的日志写入主机上的特定文件夹中。$host_path和$container_path都必须是绝对路径。
docker run -v my_volume:$container_path:这会在$container_path的容器中创建一个数据卷,并将其命名为my_volume。它本质上与使用docker volume create my_volume创建和命名卷相同。使用类似Flocker的多主机存储驱动程序命名这样的卷对于容器数据卷和共享存储卷很有用。
请注意,在DockerFile中,将主机文件夹装入数据卷的方法不可用。引用Docker文档,
Note: This is not available from a Dockerfile due to the portability and sharing purpose of it. As the host directory is, by its nature, host-dependent, a host directory specified in a Dockerfile probably wouldn't work on all hosts.
现在,如果要将文件复制到非开发环境中的容器中,可以在dockerfile中使用ADD或COPY指令。这些是我通常用于非开发部署的。
- 我应该创建2个Docker文件吗?一个用于开发,一个用于部署?
- 我不这么认为。在dockerfile中使用ADD指令没有任何错误,因为它只由docker build命令执行。当其他人第一次构建容器时,以及当您准备将其部署到其他非开发环境时,需要这样做。
- 但是,在没有文件的情况下构建一个映像,并使用-v命令进行开发,让另一个docker文件创建一个包含ADD文件进行部署的映像,这不是更有效吗?
- 这是一个你必须决定的权衡。选择适合你的。使用ADD构建需要多长时间?总共几秒钟?如果您有两个dockerfile文件,并且与其他人共享(或在docker注册表上发布),那么默认是哪一个?您将有一些额外的维护开销,以确保正确的默认dockerfile得到正确的用户。但是在一天结束的时候,你决定什么对你最有效。就我个人而言,我喜欢确保有一个而且只有一个dockerfile来构建我的容器。
- 如果您担心容器图像会很快建立起来并占用空间,则可以始终使用docker rmi删除它们。
- 顺便说一下,我认为可以先添加,然后用-v覆盖该添加进行开发。这样你就不需要单独的文件了。
- 我认为你是在颠倒:的顺序;相反。
- @阿卜杜固定。谢谢。