docker commit采坑记录

最近使用docker commit碰到了一个小坑,记录分享一下。

问题现象记录:

使用官方docker镜像 nginx 1.19.2,想要修改镜像中nginx.conf中配置值,方法如下:(注:可以直接通过文件修改,此处为了给docker commit举例用)

  1. 使用某个镜像运行了一个容器(docker run image:tag /bin/bash)
  2. 在容器内修改了程序的启动参数
  3. 使用这个容器生成它需要的image(docker commit containerID)

理论上这个操作是没有任何问题的,实际上新的image一运行立刻就退出了 ,容器的状态为Exit(0)

查看日志,发现没有打印任何日志,推测很大的可能性是执行命令不是阻塞程序,执行完就直接退出了。

验证一下:通过docker ps对比新旧image容器的CMD指令,老image的CMD='nginx -g daemon off;’,新image的CMD=‘/bin/bash’,确认问题了,修改后的CMD覆盖掉了修改前的。

 

问题根源分析

1.为什么CMD会被修改

回顾全程看看cmd命令是什么时候被修改的:
  修改前image的cmd=‘nginx -g daemon off;’,然后docker run -it image:tag /bin/bash启动了容器并且进入到容器内部进行修改,最后执行docker commit 。
很明显docker commit将容器当前使用的cmd(/bin/bash)设置为新创建的image的CMD。也就是原来image的cmd被刚才commit时指定的容器cmd覆盖了。
为什么会覆盖呐?docker官方描述如下:
If you list more than one CMD then only the last CMD will take effect。如果有多条CMD命令,仅最后一条CMD命令生效。
老image的dockerfile中CMD是这样的:
 CMD ["nginx" "-g" "daemon off;"]

执行docker run命令时,最后一条cmd由原来的 nginx -g daemon off; 变为/bin/bash

docker run -it image:tag /bin/bash     #容器主进程变为/bin/bash

执行docker commit时,当前容器的cmd保存最后一条/bin/bash

2.为什么新CMD‘/bin/bash’导致容器退出
因为Docker 不是虚拟机,容器就是进程。既然是进程,那么在启动容器的时候,需要指定所运行的程序及参数。CMD 指令就是用于指定默认的容器主进程的启动命令的
对于容器而言,其启动程序就是容器应用进程,容器就是为了主进程而存在的,主进程退出,容器就失去了存在的意义,从而退出,其它辅助进程不是它需要关心的东西。
为了保证容器不退出,容器的主进程(即image的dockfile中CMD执行的命令)必须是常驻运行的(一直挂起的例如tail top等前台命令,后台命令一般执行后就会退出)。
docker官方描述如下:
The main purpose of a CMD is to provide defaults for an executing container。CMD主要目的是为可执行容器提供默认命令。

问题解决方案

1. docker run启动容器时,不指定CMD (docker run -dit image:tag,无 /bin/bash)。

  启动容器时,不指定CMD,则使用默认cmd运行容器。commit时自动保留原镜像的默认CMD。

  若需要进入容器bash环境编辑容器,再使用docker exec -it containerID /bin/bash即可。

2. docker commit时使用--change参数替换image中的cmd.

  比如:--change=‘CMD ["nginx", "-g", "daemon off;"]' 

 
 
 
 
posted @ 2021-04-12 14:34  钟灵.毓秀  阅读(2869)  评论(1编辑  收藏  举报