star870126 发表于 2018-5-27 12:57:59

docker commit 定制镜像

概念

镜像是容器的基础,每次执行 docker run 的时候都会指定哪个镜像作为容器运行的基础。在之前的例子中,我们所使用的都是来自于 Docker Hub 的镜像。直接使用这些镜像是可以满足一定的需求,而当这些镜像无法直接满足需求时,我们就需要定制这些镜像。


镜像是多层存储,每一层是在前一层的基础上进行的修改;而容器同样也是多层存储,是在以镜像为基础层,在其基础上加一层作为容器运行时的存储层。


docker commit语法格式
docker commit [选项] <容器ID或容器名> [<仓库名>[:<标签>]]



操作
  

我虚拟机环境是系统centos7.1 ip 192.168.12.234

  

1.首先我们先导入一个nginx镜像


  

2.运行这个容器
# docker run -d -p 80:80 --name nginx nginx
4e4d4e3af79671359f8f388429af932940c8f22d2c0efc43b73aa8f492c8f537
# docker ps -a
CONTAINER ID      IMAGE               COMMAND                  CREATED             STATUS                     PORTS                NAMES
4e4d4e3af796      nginx               "nginx -g 'daemon ..."   3 seconds ago       Up 2 seconds               0.0.0.0:80->80/tcp   nginx  

看看页面展示效果(nginx默认欢迎界面)

  

  

3.现在我进入这个容器进行修改
# docker exec -it nginx /bin/bash
root@4e4d4e3af796:/# echo 'Hello Docker!!' > /usr/share/nginx/html/index.html
root@4e4d4e3af796:/# exit  

现在我们再刷新浏览器的话,会发现内容被改变了。

  

  

我们修改了容器的文件,也就是改动了容器的存储层。我们可以通过 docker diff 命令看到具体的改动。
# docker diff nginx
C /run
A /run/nginx.pid
C /usr
C /usr/share
C /usr/share/nginx
C /usr/share/nginx/html
C /usr/share/nginx/html/index.html
C /var
C /var/cache
C /var/cache/nginx
A /var/cache/nginx/uwsgi_temp
A /var/cache/nginx/client_temp
A /var/cache/nginx/fastcgi_temp
A /var/cache/nginx/proxy_temp
A /var/cache/nginx/scgi_temp
C /root
A /root/.bash_history  

现在我们定制好了变化,我们希望能将其保存下来形成镜像。要知道,当我们运行一个容器的时候(如果不使用卷的话),我们做的任何文件修改都会被记录于容器存储层里。而 Docker 提供了一个 docker commit 命令,可以将容器的存储层保存下来成为镜像。换句话说,就是在原有镜像的基础上,再叠利用 commit 理解镜像构成加上容器的存储层,并构成新的镜像。以后我们运行这个新镜像的时候,就会拥有原有容器最后的文件变化。(ps:这段话意思就是上面只是将容器里面的/usr/share/nginx/html/index.html文件改动了,镜像并没有改变,如果我把改动的容器删了,再重新docker run一个新的容器,访问nginx首页时又会是welcome to nginx欢迎界面。要想镜像也改变,需要docker commit。这段我一开始理解了好久才理解明白)
  

4.先找到刚刚docker exec的容器id,再docker commit
# docker ps -a
CONTAINER ID      IMAGE               COMMAND                  CREATED             STATUS                     PORTS                NAMES
fcc25c86fa6a      nginx               "nginx -g 'daemon ..."   6 minutes ago       Up 6 minutes               0.0.0.0:80->80/tcp   nginx
# docker commit fcc25c86fa6a nginx
sha256:346cb56295b271084a0d2998b930ddb74d4fec6e3a2052ecd0a8d852e06d3da0  

至此镜像已经构建完毕
  

docker commit弊端(一般慎用)
使用 docker commit 命令虽然可以比较直观的帮助理解镜像分层存储的概念,但是实际环境中并不会这样使用。
  

首先,如果仔细观察之前的 docker diff nginx的结果,你会发现除了真正想要修改的 /usr/share/nginx/html/index.html 文件外,由于命令的执行,还有很多文件被改动或添加了。这还仅仅是最简单的操作,如果是安装软件包、编译构建,那会有大量的无关内容被添加进来,如果不小心清理,将会导致镜像极为臃肿。
  

此外,使用 docker commit 意味着所有对镜像的操作都是黑箱操作,生成的镜像也被称为黑箱镜像,换句话说,就是除了制作镜像的人知道执行过什么命令、怎么生成的镜像,别人根本无从得知。而且,即使是这个制作镜像的人,过一段时间后也无法记清具体在操作的。虽然 docker diff 或许可以告诉得到一些线索,但是远远不到可以确保生成一致镜像的地步。这种黑箱镜像的维护工作是非常痛苦的。
  

而且,回顾之前提及的镜像所使用的分层存储的概念,除当前层外,之前的每一层都是不会发生改变的,换句话说,任何修改的结果仅仅是在当前层进行标记、添加、修改,而不会改动上一层。如果使用 docker commit 制作镜像,以及后期修改的话,每一次修改都会让镜像更加臃肿一次,所删除的上一层的东西并不会丢失,会一直如影随形的跟着这个镜像,即使根本无法访问到。这会让镜像更加臃肿。
  

docker commit 命令除了学习之外,还有一些特殊的应用场合,比如被入侵后保存现场等。但是,不要使用 docker commit 定制镜像,定制行为应该使用Dockerfile 来完成。之后的文章我们就来讲述一下如何使用 Dockerfile 定制镜像。
  
页: [1]
查看完整版本: docker commit 定制镜像