Dockerfile执行cp/mv/ln命令后镜像无变更的问题求助
我一眼就注意到你的基础镜像Dockerfile最后一行有VOLUME /root——这就是问题的核心!
Docker的VOLUME机制有个容易被忽略的特性:当基础镜像声明了某个目录为VOLUME后,后续构建阶段(比如子镜像的RUN、COPY命令)对该目录的任何修改都不会被保存到最终镜像中。构建过程中,这些修改只会存在于临时创建的容器里,当构建步骤完成后,临时容器被销毁,修改也随之消失。这就是为什么你构建时没报错,但运行容器后看不到/root/DEMO目录;而手动进入容器执行命令能生效,是因为此时VOLUME已经挂载(默认是匿名卷),修改的是卷内的内容,而非镜像本身。
方案一:修改基础镜像(推荐)
如果可以重新构建基础镜像,直接去掉基础镜像Dockerfile里的VOLUME /root行,然后重新构建基础镜像:
sudo docker build -t plu_build_1:latest . # 在基础镜像的Dockerfile目录执行
之后再重新构建你的子镜像,此时RUN cp -a $BASEDIR/TEMPLATE/ $BASEDIR/DEMO/和COPY命令的修改就会正常保存到镜像层,运行容器后就能看到/root/DEMO目录了。
方案二:无法修改基础镜像时的替代方案
如果不能修改基础镜像,我们可以在构建时把文件放到非VOLUME目录,然后在容器启动时复制到目标位置:
- 修改你的子镜像Dockerfile:
FROM plu_build_1:latest ENV BASEDIR=/root # 先把文件复制到非VOLUME目录,比如/tmp/template_files WORKDIR /tmp/template_files RUN cp -a $BASEDIR/TEMPLATE/ ./DEMO/ COPY DEMO/parameters.DEMO ./DEMO/ COPY DEMO/config.DEMO ./DEMO/ ENV PATH="${BASEDIR}/bin:${PATH}" VOLUME ["/root/DEMO/LOG/"] # 创建启动脚本,容器启动时复制文件到/root/DEMO COPY entrypoint.sh /usr/local/bin/ RUN chmod +x /usr/local/bin/entrypoint.sh ENTRYPOINT ["entrypoint.sh"] CMD ["bash"]
- 在子镜像的构建目录下创建
entrypoint.sh脚本:
#!/bin/bash # 复制预准备的DEMO目录到/root cp -a /tmp/template_files/DEMO/ $BASEDIR/DEMO/ # 执行原来的CMD命令 exec "$@"
- 重新构建子镜像并运行:
sudo docker build -t my-name . sudo docker run -it my-name /bin/bash
容器启动时,entrypoint脚本会把预存在/tmp的DEMO目录复制到/root,此时就能看到目标目录了。
补充说明:你之前尝试的mv、ln、--no-cache都没用,就是因为VOLUME的特性,这些操作都属于构建阶段对VOLUME目录的修改,不会被持久化到镜像里。而手动执行是在容器运行时操作卷内容,所以能生效。
内容的提问来源于stack exchange,提问作者Marius P

