基于已有容器构建自己的 Docker 镜像

通过前面的介绍,我们知道了Docker 镜像是多个基于 UnionFS 的镜像层依次挂载的结果,而容器的文件系统则是在以只读方式挂载镜像后增加的一个可读可写的文件系统复合而成。

Docker 中为我们提供了将容器中的这个可读可写的环境持久化为一个镜像层的方法,即docker commitdocker commit将容器修改的内容保存为镜像,我们可以把它理解为提交容器的更改。

1.生成变更后的镜像

我们以上一节的 busybox 为例:

# 重新创建一个busybox容器
docker run --name busybox -d -i busybox
# 进入容器
docker exec -it busybox sh
# 做些更改,新建个文件
echo 'something' > something
# 查看变更后的目录和文件
ls

图片描述
exit退出容器后,使用docker commit进行提交变更

[root@centos8 ~]# docker commit -m 'something' busybox
sha256:19da0182bca9305944f6a66b1331ff7394a915bc8982cf520660a883484699fc

-m 参数进行提交的注释,用法类似 git。

执行 docker commit 将容器记录成镜像层的时候,会先暂停容器的运行,以保证容器内的文件系统处于一个相对稳定的状态,确保数据的一致性。提交镜像更新后,docker images 从本地镜像列表中找到它。

图片描述

2. 为镜像命名

在上面的例子里,我们发现提交容器更新后产生的镜像并没有 REPOSITORY 和 TAG 的内容,也就是说,这个新的镜像还没有名字。 Docker 为我们提供了一个为镜像取名的命令,也就是 docker tag 命令。

docker tag 19da0182bca9 mybusybox:1.0

使用 docker tag也能够对已有的镜像创建一个新的别名副本(旧的镜像与名称也会保留)。

docker tag mybusybox:1.0 mybusybox:latest

当然,我们可以在提交变更的时候同时命名镜像

docker commit -m 'something' busybox mybusybox2:latest

3. 迁移镜像

在我们将更新导出为镜像后,我们还可以开始迁移镜像。

由于 Docker 是以集中的方式管理镜像的,所以在迁移之前,我们要先从 Docker 中取出镜像。docker save 命令可以将镜像输出,提供了一种让我们保存镜像到 Docker 外部的方式。

#  将 something:latest镜像,导出到something-latest.tar
docker save -o ./something-latest.tar something:latest

-o 选项,用来指定输出文件
在镜像导出之后,我们就可以找到已经存储镜像内容的 something-latest.tar 这个文件了。如果使用解压软件查看其中的内容,会看到里面其实就是镜像所基于的几个镜像层的记录文件。
图片描述

我们可以通过很多种方式将导出的镜像文件复制到另一台机器上,在这么操作之后,我们就要将镜像导入到这台新机器中运行的 Docker 中。

导入镜像用 docker load 命令即可。

Tips: 我们并不真的需要一台新的机器,把当前环境中 Docker something 镜像删掉即可
docker image rm something:latest

docker load -i something-latest.tar

镜像导入后,我们就可以通过 docker images 看到它了,导入的镜像会延用原有的镜像名称。

4. 从容器直接导出到镜像压缩包

使用 docker export 命令我们可以直接导出容器,我们可以把它理解为 docker commitdocker save 的结合体。
下面我们从容器 busybox 中直接导出镜像包:

docker export -o ./something-export.tar busybox

需要注意的是,这种方式导出的镜像压缩包不能使用docker load的方式导入,而应该使用 docker import 。使用 docker import并非直接将容器导入,而是将容器运行时的内容以镜像的形式导入。所以导入的结果其实是一个镜像,而不是容器。在 docker import 的参数里,我们需要给这个镜像命名。

docker import ./something-export.tar something:export

5. 小结

这一节我们介绍了如何通过 docker commit 工具,从容器快速生成 Docker 镜像,在开发的过程中,使用 docker savedocker load,或者是使用 docker exportdocker import 都可以达到迁移容器或者镜像的目的。但这种方式可维护性较差,后面的章节我们会学习如何使用 Dockerfile,从基础镜像来构建新的镜像,这也是 Docker 官方推荐的方式。