09 Dec 2018
某天有其他项目组来问我,docker run启动没问题,但是换成docker-compose启动后,一直是显示restarting状态咋办。
因为我一直有以下的docker运行个人习惯:
所以一直没遇到过这个怪问题。后来经过一段时间的面向google运维找到了问题的答案。
参考文档:
通常用docker run命令启动容器时,为了同时启动多个服务或者执行多个操作,会设定entrypoint为一个脚本。
而使用脚本启动会遇到一个问题,那就是脚本执行完毕后,容器会进入exit状态。此时有人可能会采用下面的方法来解决
#!/bin/bash set -e # 其他逻辑信息,此处忽略 /usr/local/apache-tomcat-8.5.35/bin/catalina.sh start /bin/bash
这样使用最后一句/bin/bash,相当于把这个脚本hold住,让它不停止,则这个容器就会一直处于一个运行状态。然而这样真的完美吗?答案是否定的。
无语,竟然有人想到用sleep 30000d来解决,只能说世界之大,无奇不有啊
实际测试了一下,结果竟然真的复现了上面说到的情况,使用docker run启动没问题,但是换成docker-compose启动后,一直是显示restarting状态。
而查看docker-compose启动后的容器日志,是一直循环在输出程序启动的日志,于是问题肯定出现在,这个脚本最后的/bin/bash并没有起到把这个脚本hold住的效果。
原来,docker官方已经给这个问题提出过解决方案,详细内容可以参考docker docs - 关于docker entrypoint脚本的详细说明。以下是个人总结的entrypoint使用脚本时的几个要点:
exec <cmd>取代直接执行<cmd>的方式,让<cmd>来取代被执行的脚本,而不是另外生成一个新的进程。<cmd>不能是后台执行的语句,只能是前台执行的语句,才能保证容器持续运行下面这个要点看情况使用,并不是必须的
exec "$@"语句来重定向脚本执行的参数到脚本内部,其实就是把<entrypoint> <cmd>中的<cmd>传递到<entrypoint>脚本中。根据entrypoint使用脚本时的要点,上面的脚本存在几个问题:
catalina.sh start,这样启动是后台启动。需要变更成catalina.sh run这样前台启动的方式/bin/bash去掉,通过给catalina.sh run前面增加exec的方式来让catalina.sh run成为真正控制docker容器生命周期的命令。
> 为了增强entrypoint的灵活性(entrypoint就是因为能接收参数的灵活性,才在已经有cmd的情况下还有生存空间),可以将run赋值给entrypoint的默认参数cmd同上修正上面的问题,得到正确的entrypoint脚本:
#!/bin/bash set -e # 其他逻辑信息,此处忽略 exec /usr/local/apache-tomcat-8.5.35/bin/catalina.sh "$@" exec "$@"
而Dockerfile内容为:
...其他内容省略... ENTRYPOINT ["/bin/entrypoint.sh"] CMD ["run"]
通过将
run传递到/bin/entrypoint.sh中,得到真正决定docker生命周期的命令为/usr/local/apache-tomcat-8.5.35/bin/catalina.sh run