Docker 容器的修改如何保存为可复现镜像
为什么会想到保存容器修改
上一篇文章把 VS Code 连接进了 TensorFlow 容器,但容器里还有两个现实问题:
- 为了调试,需要额外安装
pylint; - 更新或安装工具后,重新创建容器又要重复操作;
- VS Code Server 或容器扩展第一次连接时还需要重新准备。
于是当时想把“已经调好的容器”保存下来。这个思路可以快速验证,但要先分清三个对象:
镜像 image → 创建容器 container
容器文件系统 → 运行期间产生的修改
挂载卷 / bind mount → 不属于容器镜像文件系统
docker commit 保存的是容器文件系统当前状态,挂载到容器里的主机目录或 volume 不会因为 commit 自动打进镜像。
当时做的两项修改
在运行中的 tf 容器中手动完成了:
- 安装
pylint; - 更新
pip。

可以先记录修改前后的状态,避免“看起来装过”但无法确认:
docker exec tf python -m pip show pylint
docker exec tf python -m pip --version
如果命令在容器中执行,包就安装到了容器的文件系统;如果工作目录是通过 -v 挂载进来的,工作目录里的文件仍然属于主机。
用 docker commit 保存一次验证结果
当时执行:
docker commit \\
--message="install pylint" \\
--author="chauncey" \\
tf \\
chauncey/tf
这里的含义是:从名为 tf 的容器创建一个名为 chauncey/tf 的新镜像。可以检查镜像是否生成:
docker image inspect chauncey/tf
docker image ls chauncey/tf
如果还需要修改启动命令、环境变量或工作目录,docker commit 支持通过 --change 添加少量 Dockerfile 指令,但这仍然不能代替一个可读的 Dockerfile。
用新镜像创建容器测试
先停止原容器:
docker stop tf
再从新镜像创建容器:
docker run --gpus all -itd \\
--name tf \\
--rm \\
-v ~/Project:/root/Project \\
chauncey/tf
重新用 VS Code 连接后,检查 pip 和 pylint:
docker exec tf python -m pip --version
docker exec tf python -m pylint --version

如果这些命令能够在新容器中执行,说明这次容器文件系统的修改被保存下来了。挂载的 ~/Project 仍然来自主机,不要把它误认为是镜像中的代码。
docker commit 为什么不适合长期使用
它的优点是快:正在运行的容器里改了什么,可以先保存一份,适合:
- 临时排错;
- 抢救手工修改;
- 快速验证依赖是否能工作;
- 在正式写 Dockerfile 前保存一个实验快照。
但它也有明显代价:
- 修改历史不在 Dockerfile 中;
- 新接手的人不知道容器里执行过哪些命令;
- 依赖版本可能随当时的软件源变化;
- 容器里的日志、临时文件和缓存可能一起进入镜像;
- 重新构建、审计和漏洞扫描都不够清楚;
- bind mount 或 volume 中的内容不会被 commit 保存。
因此,docker commit 得到的镜像更像“实验快照”,不是长期的构建来源。
验证成功后写回 Dockerfile
例如,把已经确认需要的工具写入 Dockerfile:
# syntax=docker/dockerfile:1
FROM tensorflow/tensorflow:latest-gpu-py3
RUN python -m pip install --no-cache-dir pylint
WORKDIR /root/Project
然后构建:
docker build --pull -t chauncey/tf:dev .
这里的 Dockerfile 只是结构示意,基础镜像和依赖版本仍应根据项目实际环境固定。长期使用时,最好把 Python 依赖写进 requirements.txt,把 VS Code 扩展或 Dev Container 配置写进项目文件,而不是依赖某个已经运行过的容器。
这次实践的结论
这次真正解决的是“容器重建后手工配置丢失”的问题。docker commit 让实验结果暂时留下来,但它没有让环境变得可复现。验证想法可以先 commit;准备交给别人、放进 CI 或长期维护时,就应该回到 Dockerfile、依赖文件和版本控制。
镜像是构建结果,不应该成为唯一的配置来源。能从源码重新构建出来,才算真正保存下来。
参考资料
可用性说明:本文发布于 2020 年 1 月,距今已超过五年。文中涉及的软件版本、接口、下载地址、命令参数和操作界面可能已经发生变化,部分方案在当前环境下可能失效。请结合官方最新文档核对后再操作,生产环境使用前务必先行验证。
版权声明: 本文首发于 指尖魔法屋-Docker 容器的修改如何保存为可复现镜像(https://blog.thinkmoon.cn/post/703-notes-docker/) 转载或引用必须申明原指尖魔法屋来源及源地址!
评论
使用 GitHub 账号登录后即可留言,支持 Markdown。