一、提交容器更改
由于 docker 镜像的本质是多个基于 UnionFS 的镜像层依次挂载的结果,而容器的文件系统则是在以只读方式挂载镜像后增加的一个可读可写的沙盒环境。
基于这样的结构,docker 中提供了将容器中的这个可读可写的沙盒环境持久化为一个镜像层的方法。更浅显的说,就是可以在 docker 里将容器内的修改记录下来,保存为一个新的镜像。
将容器修改的内容保存为镜像的命令是 docker commit
,由于镜像的结构很像代码仓库里的修改记录,而记录容器修改的过程又像是在提交代码,所以这里更形象的称之为提交容器的更改。
$ sudo docker commit nginx
sha256:718e7f550c049738751dbd2a0e997f2a1e8c7ab0ba778bf503782b07f14efab8
docker 执行将容器内沙盒文件系统记录成镜像层的时候,会先暂停容器的运行,以保证容器内的文件系统处于一个相对稳定的状态,确保数据的一致性。
在使用 docker commit
提交镜像更新后,可以得到 docker 创建的新镜像的 id,之后也能够从本地镜像列表中找到它。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> 718e7f550c04 53 seconds ago 126MB
redis 5.0.7 dcf9ec9265e0 12 days ago 98.2MB
nginx 1.17.6 231d40e811cd 13 days ago 126MB
elasticsearch 7.1.0 12ad640a1ec0 6 months ago 894MB
像通过 git 等代码仓库软件提交代码一样,还能在提交容器更改的时候给出一个提交信息,方便以后查询。
$ sudo docker commit -m "my test commit" nginx
二、镜像命名
前面提交的容器更新后产生的镜像并没 REPOSITORY 和 TAG 的内容,也就是说,这个新的镜像还没有名字。可以通过 docker tag
命令为其命名 :
$ sudo docker tag 718e7f550c04 mnginx:m1.17.6
查看镜像就可以看到刚刚的命名了 :
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mnginx m1.17.6 718e7f550c04 12 minutes ago 126MB
redis 5.0.7 dcf9ec9265e0 12 days ago 98.2MB
nginx 1.17.6 231d40e811cd 13 days ago 126MB
elasticsearch 7.1.0 12ad640a1ec0 6 months ago 894MB
docker tag
命令能够为未命名的镜像指定镜像名,也能够对已有的镜像创建一个新的命名。比如对刚刚命名的镜像再次命名:
$ sudo docker tag 718e7f550c04 m2nginx:m1.17.6
由于镜像是对镜像层的引用记录,所以对镜像进行命名后,虽然能够在镜像列表里同时看到新老两个镜像,实质是它们其实引用着相同的镜像层,这个能够从镜像 id 中就可以看出来(因为镜像 id 就是最上层镜像层的 id)。虽然创建了新的镜像,但对物理存储的占用空间却不是镜像大小直接翻倍,并且创建也在霎那之间。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
m2nginx m1.17.6 718e7f550c04 17 minutes ago 126MB
mnginx m1.17.6 718e7f550c04 17 minutes ago 126MB
redis 5.0.7 dcf9ec9265e0 12 days ago 98.2MB
nginx 1.17.6 231d40e811cd 13 days ago 126MB
elasticsearch 7.1.0 12ad640a1ec0 6 months ago 894MB
除了使用 docker tag
在容器提交为新的镜像后为镜像命名这种方式外,还可以直接在 docker commit
命令里指定新的镜像名,这种方式在使用容器提交时会更加方便。
语法是 : sudo docker commint -m "提交注释" 需要提交的容器名 <REPOSITORY>:<TAG>
$ sudo docker commit -m "new image." nginx m3nginx:m1.17.6
三、导出镜像
由于 docker 是以集中的方式管理镜像的,所以在迁移之前,要先从 Docker 中取出镜像。
使用流的方式导出镜像
使用 docker save
命令导出镜像:
sudo docker save mnginx:m1.17.6 > /tmp/mnginx-m1.17.6.tar
在默认定义下,docker save
命令会将镜像内容放入输出流中,这就需要我们使用管道(>)进行接收,默认会导出到当前文件夹。
使用指定文件的方式导出镜像
通过 -o
选项指定输出文件:
$ sudo docker save -o /tmp/mnginx-m1.17.6.tar mnginx:m1.17.6
四、导入镜像
可以使用 docker load
命令导入镜像:
使用流的方式导入镜像
docker load
命令是从输入流中读取镜像的数据,需要使用管道(<)来传输内容:
$ sudo docker load < /tmp/mnginx-m1.17.6.tar
使用指定文件的方式导入镜像
使用 -i
选项指定输入文件:
$ sudo docker load -i /tmp/mnginx-m1.17.6.tar
五、批量导入导出
docker save
和 docker load
命令还可以镜像批量操作,只要在 docker save
中传入多个镜像名作为参数,它就能够将这些镜像都打成一个包,便于一次性迁移多个镜像。
$ sudo docker save -o /tmp/my-images.tar redis:5.0.7 nginx:1.17.6 elasticsearch:7.1.0
装有多个镜像的包可以直接被 docker load
识别和读取,将这个包导入后,所有其中装载的镜像都会被导入到 docker 之中。
六、导出和导入容器
除了对镜像导入导出外,还可以直接导入导出容器。
导出容器
可以使用 docker export
命令直接导出容器,可以把这个命令的作用理解为 docker commit
与 docker save
的过程结合。
$ sudo docker export -o /tmp/nginx.tar nginx
导入容器
可以使用 docker import
导入容器,需要注意的是,使用 docker import
并非直接将容器导入,而是将容器运行时的内容以镜像的形式导入,所以导入的结果其实是一个镜像,而不是容器。
在 docker import
的参数里,可以给这个镜像命名:
# 删除已有的镜像
$ docker rmi mnginx:1.17.6
$ sudo docker import /tmp/mnginx-m1.17.6.tar mnginx:1.17.6