假设有以下Dockerfile描述的图像CMD <webserver-start-script>
:
A
我想指定一个从FROM bash
RUN mkdir "/data" && echo "FOO" > "/data/test"
VOLUME "/data"
继承并修改B
的图片A
。我不想挂载卷,我希望它有一些我在/data/test
中指定的默认数据:
B
问题是测试文件将保留FROM A
RUN echo "BAR" > "/data/test"
Dockerfile中VOLUME
指令时的内容。 A
图像测试文件将包含B
而不是FOO
,如我所料。
以下Dockerfile演示了这种行为:
BAR
构建Dockerfile将打印FROM bash
# overwriting volume file
RUN mkdir "/volume-data" && echo "FOO" > "/volume-data/test"
VOLUME "/volume-data"
RUN echo "BAR" > "/volume-data/test"
RUN cat "/volume-data/test" # prints "FOO"
# overwriting non-volume file
RUN mkdir "/regular-data" && echo "FOO" > "/regular-data/test"
RUN echo "BAR" > "/regular-data/test"
RUN cat "/regular-data/test" # prints "BAR"
和FOO
。
是否可以修改BAR
Dockerfile中的文件/data/test
?
答案 0 :(得分:2)
似乎这是intended behavior。
更改Dockerfile中的卷:如果任何构建步骤在声明后更改了卷中的数据,那么这些更改将被丢弃。
答案 1 :(得分:0)
有一些非显而易见的方法可以做到这一点,而且所有这些方法都有明显的缺陷。
也许最简单但最不可重用的方法是简单地使用父Dockerfile并对其进行修改。一个快速的docker <image-name:version> source
谷歌应该找到托管父图像Dockerfile的github。这有利于优化最终图像,但会破坏使用图层的重点。
虽然Dockerfile无法对卷进行进一步修改,但正在运行的容器可以。向图像添加脚本,并更改Entrypoint以调用该脚本(并使该脚本调用原始入口点)。如果您使用的是单件式容器,则需要执行此操作,并且需要部分重置&#39;启动时的音量。当然,由于卷在容器外部持久存在,请记住1)您的更改可能已经完成,2)同时启动的另一个容器可能已经在进行这些更改。
由于卷(实际上)是永远的,所以我在第一次启动容器后只使用一次设置脚本。这样我可以轻松控制何时设置/重置默认数据。 (如果需要,可以使用docker inspect <volume-name>
获取卷的主机位置)
这个的共同中间点似乎是有一个一次性图像,其唯一目的是运行一次来进行音量配置,然后将其清理干净。
将旧卷的内容复制到新卷,并配置所有内容以使用新卷。
你可能已经浪费了更多的时间而不是它的价值。 (根据我的经验,Docker的维护难度总是远远超过它的好处。但是,Docker是一个工具,使用任何工具,你需要花一点时间来反映你是否正确使用它,如果有更好的这项工作的工具。)
答案 2 :(得分:0)
音量不属于您的IMAGE。那么将数据植入其中的用例是什么?将图像推入另一个位置时,它在开始时使用空卷。 dockerfile行为确实会提醒您。
基本上,如果您想将数据与应用程序代码一起保存,则不应使用VOLUME。如果父图像中确实存在卷声明,则需要在开始自己的图像构建之前删除该卷。 (docker-copyedit)。