在Docker容器中,Docker Commit 和Docker Build的实战使用以及区别

艺帆风顺 发布于 2025-04-03 20 次阅读


还是需要从docker 三要素说起,docker的镜像和容器是指的一种实例状态,镜像运行后成为容器,也就是docker run 镜像后的状态叫容器。

1.容器保持运行状态至少需要一个工作在前台的进程。Docker容器中必须有一个前台进程,否则认为容器已经挂掉

2.镜像 docker run——>容器 这是镜像向容器转化。

    3.正在运行的容器 docker commit 或者dockerfile build--->镜像,这是容器-->镜像转化和镜像-->镜像。

那么,今天要讨论的是镜像向容器转化的两种方式的实现方法,以及它们之间的异同。

首先,来观察一下几个启动的容器的状态,以更好理解上面所说的第一条。

    [root@centos7 ~]# docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEhub.c.163.com/library/centos 7.3.1611 67591570dd29 4 years ago 192MB[root@centos7 ~]# docker run -itd --name centos1 hub.c.163.com/library/centos:7.3.1611[root@centos7 ~]# docker run -itd --name centos2 hub.c.163.com/library/centos:7.3.1611 [root@centos7 ~]# docker ps -aCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESc7d8d950f20b hub.c.163.com/library/centos:7.3.1611 "/bin/bash" 6 minutes ago Up 5 minutes centos2e20d77bee6af hub.c.163.com/library/centos:7.3.1611 "/bin/bash" 28 minutes ago Up 28 minutes centos1

    我现在有一个容器,这个容器名称为hub.c.163.com/library/centos:7.3.1611,执行docker run命令后,生成了两个容器实例,分别名称为centos1和centos2,status栏表明是up状态,也就是运行状态,此时执行docker exec 命令进入任意一个容器,观察ps  -ef 可以发现,有一个pid 为1的进程。

      [root@centos7 ~]# docker exec -it centos2 /bin/bash[root@c7d8d950f20b /]# ps -efUID PID PPID C STIME TTY TIME CMDroot 1 0 0 08:41 pts/0 00:00:00 /bin/bashroot 14 0 2 08:54 pts/1 00:00:00 /bin/bashroot 27 14 0 08:54 pts/1 00:00:00 ps -ef

      那么,如果在容器内没有这个pid 为1的进程,docker会认为这个容器不是在运行的,容器就会停止运行,为什么会有这个/bin/bash pid 为1的进程呢?请看下面的代码:

        [root@centos7 ~]# docker history hub.c.163.com/library/centos:7.3.1611IMAGE CREATED CREATED BY SIZE COMMENT67591570dd29 4 years ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B missing> 4 years ago /bin/sh -c #(nop) LABEL name=CentOS Base Im… 0B missing> 4 years ago /bin/sh -c #(nop) ADD file:940c77b6724c00d42… 192MB missing> 4 years ago /bin/sh -c #(nop) MAINTAINER https://github… 0B

        可以看到这个基础镜像是在另一个基础镜像的基础上 docker build 制作而成的,CMD命令会在镜像启动为容器时执行,执行的命令就是 /bin/bash、而这个命令是工作在容器的前台的哦。(前台运行就是没有&,没有nohup)。

        docker commit:

          [root@centos7 ~]# docker exec -it centos2 /bin/bash[root@c7d8d950f20b /]# vimbash: vim: command not found

          在前面启动的容器centos2 这个容器,我们进入后,可以发现这个容器是没有vim命令的,那么在实际使用过程中,会十分的不方便,这个时候我们可以使用 docker commit 先给这个容器安装vim,然后将这个容器转化为镜像,以后再使用这个新的镜像就可以直接使用vim命令 了。

          1,容器必须是up状态,也就是运行状态,docker ps -a 查询即可

          2,docker exec 进入这个容器,yum安装vim

            [root@c7d8d950f20b /]# yum install vim -yLoaded plugins: fastestmirror, ovlbase | 3.6 kB 00:00:00 extras | 2.9 kB 00:00:00 updates | 2.9 kB 00:00:00 (1/4): base/7/x86_64/group_gz | 153 kB 00:00:00 (2/4): extras/7/x86_64/primary_db | 222 kB 00:00:00 (3/4): base/7/x86_64/primary_db | 6.1 MB 00:00:07 (4/4): updates/7/x86_64/primary_db | 4.0 MB 00:00:10 Determining fastest mirrors * base: mirrors.163.com * extras: mirrors.163.com * updates: mirrors.bfsu.edu.cnResolving Dependencies--> Running transaction check

            3,退出容器,执行docker commit命令,具体如下:

            docker commit  容器名称 新镜像名称

              [root@c7d8d950f20b /]# exit[root@centos7 ~]# docker commit centos2 centos-vim:v1.0sha256:8df43092cfd1eb53b895fcda19c9ec0d18c358194045a5fd4d5cf47d177e8b30

              4, 查看是否生成新镜像

                [root@centos7 ~]# docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEcentos-vim v1.0 8df43092cfd1 58 seconds ago 332MB

                可以看到,新镜像已经生成,大小变为了332M

                5,docker run 新镜像,并进入新容器,查看是否vim保留在了新镜像 centos-vim:v1.0

                  [root@centos7 ~]# docker run -itd --name centos4 centos-vim:v1.085e5a130e4dc1f967534f1e81fba1072f97f81bb1263057e1db0b938b9053323[root@centos7 ~]# docker exec -it centos4 /bin/bash[root@85e5a130e4dc /]# vim[root@85e5a130e4dc /]# whereis vimvim: /usr/bin/vim /usr/share/vim

                  可以看到,新的镜像 centos-vim 确实有了vim命令,可以使用新镜像愉快的玩耍了。

                  6.查看新镜像的生成历史

                    [root@centos7 ~]# docker history centos-vim:v1.0IMAGE CREATED CREATED BY SIZE COMMENT8df43092cfd1 6 minutes ago /bin/bash 140MB 67591570dd29 4 years ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B missing> 4 years ago /bin/sh -c #(nop) LABEL name=CentOS Base Im… 0B missing> 4 years ago /bin/sh -c #(nop) ADD file:940c77b6724c00d42… 192MB missing> 4 years ago /bin/sh -c #(nop) MAINTAINER https://github… 0B

                    可以看到,新镜像在原有基础镜像上增加了一层140M大小,但并不清楚具体的增加的内容。这就造成了 黑箱操作。(除非我告诉你,否则你根本不会知道这个新镜像有了什么改变)。

                    docker commit 的弊端:

                    如果是安装软件包、编译构建,那会有大量的无关内容被添加进来,如果不小心清理,将会导致镜像极为臃肿

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

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

                    docker commit的优点:

                    操作简单,易上手,

                    docker build 方式镜像生成新的镜像:

                    docker build的方式生成新镜像的前提条件是有一个旧的基础镜像,在此基础上通过docker build 命令执行dockerfile 文件从而生成一个新的镜像,不同于docker commit,是镜像--> 镜像的转化。当然,是否转化正确是需要将镜像 docker run起来的哦。

                    现在,假设需求是将之前的镜像hub.c.163.com/library/centos:7.3.1611 作为基础镜像,通过dockerfile 文件的编写,执行,生成一个新的镜像,镜像名称为centos-vim:v2.0,。

                    1,新建一个空文件夹,名称任意,只需要为空就好。假设名称为 make_vim 这个文件夹,进入这个文件夹,编写文件,文件名称为 centos-vimv2.0

                      [root@centos7 make_vim]# pwd/root/make_vim[root@centos7 make_vim]# lscentos-vimv2.0

                      2.centos-vim2.0 的内容如下:

                        FROM hub.c.163.com/library/centos:7.3.1611RUN yum install -y vim httpd && yum clean all

                         3,运行build 命令,生成新镜像centos-vim:v2.0

                        docker build -f ./centos-vimv2.0 -t centos-vim:v2.0 .

                        注意,是在 make_vim 这个文件夹下执行此命令,命令最后是有一个点的哦,千万别忘了。

                        4 , 验证新镜像centos-vim:v2.0 是否带有vim命令

                        docker run -itd --name centos5 centos-vim:v2.0

                        [root@centos7 make_vim]# docker exec -it centos5 /bin/bash
                        [root@1eb659612a86 /]# whereis vim
                        vim: /usr/bin/vim /usr/share/vim

                        5,当然了,在dockerfile里,我加入了清理yum安装痕迹命令,因此,镜像要比commit 方式小一些。仅仅做一个小示例,因此dockerfile的很多功能没有演示,比如:复制宿主机的文件和文件夹到镜像内部,cmd ,entrypoint ,add,copy,export,workdir等等并没有使用。docker build -t 后面接的是新镜像的tag,-f 后面接的是dockerfile文件的名称,如果dockerfile的名称是Dockerfile,那么,可以省略-f以及其以后的内容,也就是不指定,docker会自动优先使用名称叫Dockerfile的文件构建新镜像。

                        Dockerfile的优点:

                        能够自由灵活的与宿主机联系,比如,某些配置文件在宿主机验证并使用过后很好用,那么,可以将文件copy到镜像中,(这个动作是写在dockerfile里),add 远程主机的配置文件到镜像中,定义onbuild动作等等各种灵活的功能。docker commit不能做到这些事情,因为是在一个封闭的在运行中的容器中,无法做复制拷贝宿主机文件的事情。

                        dockerfile本身就是一个比较详细的构建文档,有这个文档就可以清楚的知道新构建的镜像经历了怎样的变化。没有黑箱操作的困扰了,后期的维护更为方便了。

                        后期可扩展性强,一个文件就可以在哪都可以运行镜像了。(前提有网,有安装docker环境)

                        Dockerfile的缺点:

                        编写不容易,因为需要对脚本这些比较了解,有Linux基础的人才可以编写出好用的dockerfile,上手难度大。

                          版权声明:本文内容来自CSDN:晚风_END,遵循CC 4.0 BY-SA版权协议上原文接及本声明。本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行可。原文链接:https://blog.csdn.net/alwaysbefine/article/details/111375658如有涉及到侵权,请联系,将立即予以删除处理。在此特别鸣谢原作者的创作。此篇文章的所有版权归原作者所有,与本公众号无关,商业转载建议请联系原作者,非商业转载请注明出处。