创建新镜像
首先,确认要基于哪个容器创建镜像,通过 docker ps -a 命令查看所有容器(包括已停止的):
1 | docker ps -a |
记录目标容器的 CONTAINER ID(如 abc123456789)或 NAMES(如 my-ubuntu-container).
使用 docker commit 创建新镜像
基本语法:
1 | docker commit [选项] <容器ID或名称> <新镜像名称[:标签]> |
基于容器 my-ubuntu-container 创建一个名为 my-custom-ubuntu、标签为 v1.0 的新镜像:
1 | docker commit my-ubuntu-container my-custom-ubuntu:v1.0 |
验证新镜像是否创建成功
使用 docker images
命令查看本地镜像列表
docker commit 不会提交外挂到外部主机的数据(即通过 -v 挂载的主机目录或数据卷中的内容),仅会提交容器自身可写层(容器内部未挂载区域)的文件变更。
核心原理:挂载数据与容器可写层的隔离性
Docker 中,通过 -v 挂载的外部数据(主机目录、数据卷)与容器的文件系统是隔离的:
容器可写层:容器运行时产生的新文件、修改的文件(未在挂载目录下)会保存在容器自身的可写层,这部分内容会被 docker commit 捕获并打包到新镜像中。
挂载的外部数据:通过 -v 主机路径:容器路径 挂载的外部数据,本质是 “主机文件系统的映射”,并不属于容器可写层的一部分,因此 docker commit 会完全忽略这部分内容。
是否需要关闭容器
容器是否处于运行状态,对通过 docker commit 创建镜像的最终结果(镜像内容)无本质影响,但会影响提交过程的稳定性和数据一致性.
关键原理:Docker Commit 捕获的是 “文件系统层”,而非 “运行状态”
Docker 容器的文件系统基于分层存储,docker commit 的本质是:将容器在基础镜像之上的 “增量文件变更层”(即 /var/lib/docker/overlay2 中的容器层)打包为新镜像。
无论容器是否运行,只要变更已被持久化到容器的文件系统(如 apt install 安装软件、echo “config” > file 写入文件),就会被包含在新镜像中;而仅存在于内存中的数据(如 echo “temp” 未写入文件、数据库未提交的事务、进程内存缓存),不会被捕获,与容器是否运行无关。
实操建议:优先选择 “停止容器后提交”
为避免因运行时数据写入导致的镜像损坏,建议遵循以下最佳实践:
停止容器前完成数据持久化
若容器运行中做了关键变更(如修改配置文件、生成数据文件),先确保变更已保存(如执行 sync 命令强制刷盘、关闭正在写入的进程),再停止容器。
停止容器后提交
通过 docker stop <容器名/ID> 停止容器,待容器状态变为 Exited 后,再执行 docker commit,此时文件系统无写入操作,镜像内容更稳定。
跳过容器中的大文件或文件夹
可以跳过容器中的大文件或文件夹,避免其被打包进新镜像(减少镜像体积、加快构建速度)。核心通过 docker commit 的 –exclude 参数 实现,也可结合容器内的临时目录特性辅助过滤,以下是具体方法、原理和实操示例:
使用 docker commit –exclude 显式排除
docker commit 支持通过 –exclude <路径> 参数,指定不需要包含在新镜像中的文件或文件夹路径(路径需基于容器内的绝对路径),可多次使用该参数排除多个目标。
1 | docker commit \ |
关键注意事项
路径必须是 “容器内的绝对路径”:不能使用主机路径(如 /var/lib/docker/...),需先通过 docker exec <容器ID> ls <路径> 确认容器内的目标路径存在。
支持文件夹和文件:既可以排除单个大文件(如 /data/logs/big.log),也可以排除整个大文件夹(如 /data/backup)。
排除是 “最终层过滤”:--exclude 会在打包容器增量层时,直接跳过指定路径的文件,这些文件不会进入新镜像(而非打包后删除,因此能真正减少镜像体积)。
实操示例:排除大文件 / 文件夹
假设我们有一个 centos 容器,容器内有两个需要排除的大目标:
大日志文件:/var/log/app/big-log-10G.log(10GB)
大备份文件夹:/data/backup(20GB)
步骤 1:确认容器内目标路径
先通过 docker exec 验证路径存在(避免因路径错误导致排除失败):
1 | docker exec <容器ID> ls -lh /var/log/app/big-log-10G.log # 确认大文件 |
步骤 2:停止容器(可选但推荐,确保数据稳定)
1 | docker stop <容器ID> |
步骤 3:带排除参数提交镜像
1 | docker commit \ |
常见问题与解决方案
排除后镜像体积未减少?
原因 1:路径错误(如使用相对路径、主机路径)。
解决:通过 docker exec <容器ID> pwd 确认容器内路径,确保 –exclude 后是绝对路径。
原因 2:目标文件在 “基础镜像层” 而非 “容器增量层”。
docker commit 仅能排除容器运行中新增 / 修改的文件(增量层),若大文件来自基础镜像(如基础镜像自带的大软件),–exclude 无法排除(需通过 Dockerfile 的 RUN rm 清理基础镜像层)。排除文件夹时,子目录未被排除?
原因:–exclude 是 “精确匹配路径”,但排除文件夹时会自动包含其所有子目录(无需单独排除子目录)。
例:–exclude /data/backup 会排除 /data/backup 及其下所有文件 / 子文件夹,无需再加 –exclude /data/backup/subdir。运行中的容器排除时,大文件仍在写入?
风险:若大文件正在被容器进程写入(如日志滚动),即使 –exclude,也可能因文件句柄未释放导致排除不完全。
解决:先停止容器(docker stop),再提交(停止后无写入操作,排除更彻底)。