如何在 Docker 图像中写入文件?

How to write files in Docker Images?

我已经将文件复制到 docker 图像中:

COPY dbconfig.xml /var/app/dbconfig.xml

之后,我尝试将文件中的一些值替换为:

RUN sed -i "s/PASSWD/$dbpasswd/" /var/app/dbconfig.xml

请注意 $dbpassword 是一个 ENV 变量。

当我检查 config.xml 的内容时,通过启动该图像的容器和其中的 运行 一个 bash,dbconfig.xml 中没有任何变化.

现在我想我误解了 docker 图像的一些基本原理..

我什至测试过创建一个简单的文件:

RUN echo "test" > newfile.txt

调用后好像删除了.. 我知道每个 运行 语句都会创建一个 新层 并且在语句之后它会被删除(?)。

我很困惑。为什么用

安装软件之类的东西
RUN apt-get install -y some-package

没有被删除并且创建一个简单的文件确实被删除了?

所以..我如何在图像构建时更改 docker 图像中的文件?

Dockerfile:

FROM dchevell/jira-software:8.0

COPY dbconfig.xml /var/atlassian/application-data/jira/dbconfig.xml
WORKDIR /var/atlassian/application-data/jira

# set default password to admin
ENV dbpasswd=admin

RUN sed -i "s/PASSWD/$dbpasswd/" dbconfig.xml \
 && cat dbconfig.xml 

RUN echo "test" > newfile.txt

dbconfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<jira-database-config>
  <name>defaultDS</name>
  <delegator-name>default</delegator-name>
  <database-type>postgres72</database-type>
  <schema-name>public</schema-name>
  <jdbc-datasource>
    <url>jdbc:postgresql://docker-postgres:5432/jiradb</url>
    <driver-class>org.postgresql.Driver</driver-class>
    <username>atlasdb</username>
    <password>PASSWD</password>
    <pool-test-while-idle>true</pool-test-while-idle>
  </jdbc-datasource>
</jira-database-config>

更新 1

令人困惑的是,当我在 WORKDIR 文件夹中复制某些内容时,它仍然存在,但是当我随后尝试使用 SED 对其进行修改时,这些更改不会持续存在!我认为在后台发生了一些真正的黑暗魔法...... 也许我尝试将我预配置的 dbconfig.xml 绑定到 docker-compose 中,看看是否有帮助..

更新 2

来自Docker Documentation

Changing the volume from within the Dockerfile: If any build steps change the data within the volume after it has been declared, those changes will be discarded.

我完全错过了!感谢 David 指点我:) 所以创建和编写文件确实按预期工作,但要小心 VOLUME 目录。 运行 语句在这里不起作用。 因此,要解决此问题,最佳做法是将文件绑定挂载到该卷中。

每个RUN语句不会创建一个中间容器,而是在联合文件系统上创建一个新层,它是只读的。当您 运行 图像时,将为该容器创建一个特殊的可写层,并且您对该容器所做的所有更改都将写入该层。 (卷除外。这是一个不同的概念)。这就是为什么 docker 能够在容器之间安全地共享相同的图像(甚至层),而不会相互影响。您可以查看 docker documentation 了解更多信息。

对于您的问题,您应该在构建时在此图像的 运行ning 实例中看到您所做的所有更改,除非您以某种方式删除或覆盖它们。

看到这个

您运行的命令是正确的,它们应该创建文件。我怀疑的是,当您 运行 您的容器时,jira 应用程序正在覆盖您指定的 WORKDIR

试试这个 Dockerfile:

WORKDIR /var/atlassian/application-data/jira

# set default password to admin
ENV dbpasswd=admin

RUN sed -i "s/PASSWD/$dbpasswd/" dbconfig.xml \
 && cat dbconfig.xml 


WORKDIR /testtest
RUN touch test.txt
RUN echo "test" > newfile.txt

WORKDIR  /var/atlassian/application-data/jira

现在,如果您启动容器,您可以看到文件正在 /testtest 文件夹中创建。

如果您希望对 dbconfig.xml 文件所做的更改持续存在,您应该尝试使用卷将本地 dbconfig.xml 与 jira 文件夹绑定。

感谢这个有趣的问题:)

如果你看the Dockerfile for that base image,它说部分

ENV JIRA_HOME /var/atlassian/application-data/jira
VOLUME ["${JIRA_HOME}"]

在 Dockerfile 中执行 VOLUME 语句后,later Dockerfile statements can't make any more changes in that specific directory

考虑到您尝试更改的是非常特定于安装的设置(管理员密码、数据库设置),我不会尝试使用这些来构建映像。相反,我会使用 docker run -v 选项在运行时注入配置文件。