docker commit在Ubuntu镜像生效但自制镜像无效,差异原因何在?
问题分析与解决方法
你猜的没错,容器挂载Volume正是导致修改无法被commit到新镜像的核心原因,咱们一步步拆解:
为什么会出现这个差异?
官方的Ubuntu:latest镜像默认没有定义任何Volume,所以你在容器内的所有修改都会存在于容器的可写层中,执行docker commit时,Docker会把这些可写层的变更打包成新镜像的层,自然能同步修改。
而你的自制镜像大概率在Dockerfile里用了VOLUME指令,或者你在创建容器时手动通过-v/--volume参数挂载了外部Volume。这时候,容器里对应Volume的目录会被映射到宿主机的存储位置(或者Docker管理的Volume存储区),所有对这个目录的修改都不会写入容器的可写层,而是直接存在Volume里——docker commit只会打包容器的可写层,自然不会包含Volume里的修改。
如何验证这个问题?
- 先检查自制镜像的元数据:
在输出里找docker inspect your_custom_image_nameVolumes字段,如果有类似"/some/path": {}的内容,说明这个镜像默认会挂载Volume到该路径。 - 进入运行中的容器,执行
mount命令,查看输出里带有tmpfs或者/var/lib/docker/volumes/...的挂载项,这些就是Volume目录,你的修改大概率是在这些目录里。
解决办法
根据你的场景选对应的方案:
- 移除Dockerfile里的VOLUME指令
如果你的自制镜像Dockerfile里写了VOLUME /target/path,直接删掉这一行,重新构建镜像:
之后再运行容器修改、commit,修改就会被包含到新镜像里了。docker build -t your_custom_image_name . - 创建容器时不挂载外部Volume
如果你是运行容器时手动加了-v参数挂载外部目录,下次运行时去掉这个参数,让目标目录属于容器自身的可写层。 - 把Volume内容同步到镜像层
如果你需要保留Volume功能,但又要把当前修改加入镜像,可以先把Volume里的内容复制到容器的非Volume目录,比如:
然后commit容器,之后在新的Dockerfile里把# 在容器内执行 cp -r /volume/path/* /temp/path//temp/path的内容复制回目标目录,再按需添加VOLUME指令。
内容的提问来源于stack exchange,提问作者Madix
相关产品推荐
相关产品推荐

