以cmswing为例,如何调试修改docker现有镜像?
发布于 作者:苏南大叔 来源:程序如此灵动~
得到一份新的docker镜像后,如果这个镜像不能使用,无法启动容器。该如何调试修改呢?正常情况下来说,要调试修改docker,就必须进入相关容器,而相关容器报错,无法启动,那么就无法调试。这就成了先有鸡,还是先有蛋的著名悖论了。
苏南大叔在本篇文章描述的内容是:如何修改调试已有的docker镜像。友情出境的是@特总 的cmswing的docker镜像。在这里,对特总提供实验镜像,表示感谢。当然本篇文章,并不是讲述如何使用cmswing的docker镜像的,仅仅是为了说明修改调试docker镜像的步骤而已。

调试修改docker镜像的整体思路
书接前文,苏南大叔实例化了cmswing的官方0.4版本镜像,但是失败了。docker ps -a的结果,显示Exited (1) 24 seconds ago。那么,如何查找docker的具体失败报错信息呢?又如何修改docker内的逻辑呢?
这个部分比较复杂了,是一系列docker命令的反复组合。基本的思路是这样的:
docker run或者docker start一个容器,容器报错。- 使用
docker logs -f查看报错信息。 - 使用
docker ps -a查看入口文件地址。 - 删除当前报错的容器,
docker rm。 - 使用新的命令参数
docker run -it进入新的测试容器,查看入口文件的逻辑,然后修改保存容器内的入口文件逻辑,尽量调试完整,没有错误之后,退出当前容器。 - 可能需要使用
docker start或者docker restart或者docker stop来操作容器,调整运行状态查看效果。 - 使用
docker commit把当前容器,提交为一个新的镜像版本。 - 删除实验用的的容器,
docker rm。 - 重复第一步。
docker run一个新的容器,看看效果。
整体的思路有了之后,苏南大叔来分步骤说明一下。docker run或者docker start在上一篇文章里面,已经描述过了。
查看docker日志 ,docker logs -f
因为对应镜像的实例对象,start失败了。在docker ps -a里面显示为:Exited (1)。也就是异常退出的意思。所以,需要仔细查看一下报错信息。
请使用docker ps -a找到对应实例的container id或者names,传递到下一句命令里面。命令行如下:
docker logs -f <containerid>在本次的实验demo中,这个命令就是:
docker logs -f cms_server或者
docker logs -f a6a513140715就可以看到一些报错信息的线索了。对于本文来说,报错信息,并不重要,只要是能看到由报错消息即可。
Error: Cannot find module '/web/cmswing/www/production.js'
at Function.Module._resolveFilename (module.js:469:15)
at Function.Module._load (module.js:417:25)
at Module.runMain (module.js:604:10)
at run (bootstrap_node.js:394:7)
at startup (bootstrap_node.js:149:9)
at bootstrap_node.js:509:3查看docker镜像入口文件,docker ps -a
每个镜像或者说容器,都是有个入口文件(命令)的。调试镜像或者容器错误的时候,这个入口文件地址是很重要的。所以,首要的问题,就是要弄清,异常退出的容器的入口文件命令是什么。
当然,这个信息,还是由docker ps -a来查看,这次我们查看的列信息是:COMMAND。对于本文的特约演员cmswing的0.4版本镜像来说,这个入口命令是:sh /run.sh。
记住这个入口命令,以后会用得到。
删除无用容器,docker rm
既然是容器,理论上来说,这容器里面就是没有重要数据的。如果您的容器里面有重要数据,请不要执行本步骤。通过containerid或者names可以删除掉这个容器。基本命令是这样的:
docker rm <name>docker run -it,实例化一个新的容器
此步骤就是属于调试的步骤了,对比一下普通的docker run命令。
docker run --name cms_server -v /home/www:/web -p 6080:80 -d registry.cn-hangzhou.aliyuncs.com/docker_open/cmswing:0.4调试版的docker run -it之最基础版本,命令仅仅多了一个-it,而且没有-v目录映射部分,没有-p端口映射部分,没有-d参数。如下:
docker run -it --name cms_server registry.cn-hangzhou.aliyuncs.com/docker_open/cmswing:0.4 /bin/bash-it,其实是-i加-t,大家理解为进入容器的意思,就可以了。-d,容器运行于前台还是后台,加了这个参数后,-it参数基本上就废了,因为进入后台运行了。我们也进不了容器,看不到容器内的情况了。所以,绝对不能加-d参数。-v <宿主路径>:<容器路径>,可以多次调用。因为会影响容器内容逻辑,视情况添加。-p <宿主端口>:<容器端口>,可以多次调用。因为会影响容器内容逻辑,视情况添加。- 最后的参数是:
<镜像地址/名称>:<版本号>,镜像地址pull回来后,就变成了镜像的名字了。不明白的话,可以使用docker images查看所有镜像信息。 <初始命令>。其中<初始命令>这个比较重要,不填的话,就是执行镜像里面默认的。如果定义的话,建议设置为:/bin/bash。就是说进入命令行的意思。
这个多次docker run --name <name>的过程中,因为会创建不同容器并启动,所以很有可能需要配合的命令是docker stop <name>和docker rm <name>。
通过这种新的docker run -it命令就可以进入到容器内部,进行调试了。可能需要:辅助添加一个或者多个-v或-p参数。
docker run -it --name <name> <镜像名称>:<镜像版本> /bin/bash进入容器后,苏南大叔推荐您:先从入口文件入手,开始调试就行了。docker ps -a可以查看command命令,就是入口文件。

退出当前容器exit,进入宿主机
退出当前容器的命令是:
exit退出容器后,如果想再次进入这个运行中的容器的话,使用这样的命令即可:
docker exec -it <containerid> /bin/bash提交为一个新的镜像版本,docker commit
如果反复实验调试,确认无误完毕后,就需要把当前的容器,commit为一个新的镜像版本。基本套路是这样的:
docker commit <container_id> <image_name>:<tag>比如:使用docker ps得到当前令人满意的容器的id是4ce44545cfd71。苏南大叔把他定义为cmswing镜像的0.5版本。
docker commit 4ce44545cfd7 registry.cn-hangzhou.aliyuncs.com/docker_open/cmswing:0.5这里值得说明的是:<image_name>:<tag>这个组合是可以随意覆盖的。并没有重名提示。而且,这个提交的话,也仅仅保存在宿主机上面,并不影响其他人。
在commit的时候,要注意一个重要事项,就是当前的入口文件是什么。因为默认的调试情况下,入口文件是/bin/bash。而commit之后,再run出来的镜像,默认的入口地址,也会是/bin/bash。
所以,很有可能发生的操作是:
docker run -it .... /bin/bash
exit
docker commit .....
docker stop ...
docker start ...
docker rm ... (-f)
docker run ..... sh run.sh
docker commit .....
docker stop ...
docker rm ... 这个时候得到的镜像,才是最符合要求的.... 有点复杂对吧....加油!
镜像调试步骤补充docker images和docker rmi
用户查看镜像列表的辅助命令,如下所示,注意是images,复数s:
docker images
删除不满意的镜像的方式是:
docker rmi <镜像id><镜像id>来自于docker images里面的IMAGE ID这一列。比如:
docker rmi 515ec1cf6d92总结
通过本文的一系列操作,就可以修改调试一个新的镜像了。是不是有些复杂了... 苏南大叔表示:如果您有更好的思路,欢迎提供给苏南大叔。谢谢。
更多苏南大叔编写的docker相关的经验文章,请猛击下面的链接查看。