从docker stop/start出发,实现自动启动容器内应用
接上篇,sqli-labs镜像能够实现docker run的时候自动启动mysql和apache进程,但是一旦docker异常退出或者执行docker stop之后,再次执行docker start启动容器时,mysql和apache不会自动启动,而只有mysql会启动起来,于是乎有了如下的折腾过程。
执行docker stop会发生什么?
先来看看官方文档怎么说:
1
2
3 用法:docker stop [OPTIONS] CONTAINER [CONTAINER...]
参数:--time , -t 10 Seconds to wait for stop before killing it
描述:The main process inside the container will receive SIGTERM, and after a grace period, SIGKILL.
讲得明白一点就是执行docker stop命令之后,会给容器内pid=1的进程发送SIGTERM信号,然后等待-t时间,如果在-t指定的时间内,进程没有正常结束,会发送SIGKILL信号强制结束pid=1这个进程,然后退出容器。这里的-t指定的时间可以预留给容器内的程序做一些善后工作,比如继续处理接收的请求,保存数据,做一些清理工作等。
于是我进入容器,查看一下pid=1的进程是什么,没错,就是在Dockerfile中CMD指令指定的那个脚本。
1 | [root@bd79479d225d /]# ps -aux |
为什么docker stop后,再docker start之后,apache没有启动呢?
首先docker stop sqlilab,再docker start sqlilab,查看容器内进程
1 | [root@bd79479d225d /]# ps -aux |
这里可以发现sqli_lab.sh被执行了两次,其中一个pid=1另外一个pid=6。并且mysql进程是存在的,那为什么apache进程没有启动起来呢?
继续来查看一下/etc/init.d/sqli_lab.sh
1 | !/bin/bash |
也许发现一些端倪了,应该是进程前后台设置混乱导致的。这里具体的细节原因限于我目前的知识水平无法解释。
解决办法
要保持docker在后台运行不要退出,一定要保留一个前台进程,这里我是使用的/bin/bash,其实上边的apache以前台模式运行就可以替代/bin/bash了。然后我尝试了一下/usr/bin/mysqld_safe –basedir=/usr,发现这条命令也会保持在前台不退出,那么久先把mysql给放到后台去,然后令apache在前台保持就好了。更改后的脚本如下:
1 | !/bin/bash |
保存后,重新stop/start,mysql和apache均能正常启动。问题暂时解决。
2018.6.8 更新
由于晚上我将服务器关机了,今天再次启动容器的时候发现问题依然存在,真是捉急。于是乎只有换个方法了,还是需要使用supervisor来管理mysql和httpd进程。
于是更改Dockerfile,增加安装supervisor
1 | RUN yum -y install epel-release && yum install supervisor -y |
编写分别用于控制httpd和mysqld的配置文件:
1 | [program:mysql] |
1 | [program:httpd] |
将配置文件加入到镜像中:
1 | ADD ./mysql.ini /etc/supervisord.d/mysql.ini |
这次问题终于得到解决了。