运行Docker容器时如何自动启动服务?


157

我有一个Dockerfile将MySQL服务器安装在一个容器中,然后像这样开始:

sudo docker run -t -i 09d18b9a12be /bin/bash

但是MySQL服务不会自动启动,我必须手动运行(从容器内部):

service mysql start

运行docker容器时如何自动启动MySQL服务?


1
不,对于一项简单的服务,不需要主管,这对于
Larry Cai

8
您可能要在这里复制dockerfile而不是链接到不再存在的文件
neo112 '16

docker上有关supervisor的文章现在在这里:docs.docker.com/config/containers/multi-service_container 我使用&& tail命令使我的服务正常工作-但需要在docker上添加“ --cap-add SYS_PTRACE”运行命令。
Ted Cahall,

Answers:


205

首先,有一个问题,在您的Dockerfile

RUN service mysql restart && /tmp/setup.sh

Docker映像不会保存正在运行的进程。因此,您的RUN命令仅在docker build阶段执行,并在构建完成后停止。相反,当使用以下命令CMD或时,需要在启动容器时指定命令ENTRYPOINT

CMD mysql start

其次,docker容器需要一个进程(最后一个命令)来保持运行,否则该容器将退出/停止。因此,普通service mysql start命令不能直接在Dockerfile中使用。

保持进程运行的三种典型方法:

  • 使用service命令并在其后附加非结束命令tail -F

    CMD service mysql start && tail -F /var/log/mysql/error.log
    

当您运行单个服务时,这通常是首选的,因为这会使docker访问输出的日志。

  • 或使用前台命令执行此操作

    CMD /usr/bin/mysqld_safe
    

仅当存在类似的脚本时,此方法才有效mysqld_safe

  • 或将您的脚本打包start.sh并放在最后

    CMD /start.sh
    

如果命令必须执行一系列步骤(最好再次/start.sh保持运行状态),则最好。

注意

对于初学者supervisord,不建议使用。老实说,这太过分了。最好对容器使用单个服务/单个命令。

顺便说一句:请检查https://registry.hub.docker.com以获取现有的mysql docker镜像以供参考


在docker容器中启动后,如何重新启动服务?
K-SO的毒性在增加。

3
@KarlMorrisondocker exec -it <CONTAINER NAME> mysql /etc/init.d/mysqld restart
凯泽

1
我不建议拖延MySQL的错误日志来确定数据库是否正在运行。在大多数mysqld设置中,服务器将从SOE错误中恢复,并且在执行此操作的过程中,错误日志将被关闭,然后重新打开。我也不确定您的尾巴-F在所有甚至某些情况下都能为您解决。
Brian Aker

我不知道为什么,但是第一个解决方案选项对于服务脚本来说效果很好。当不使用tail时,即使服务已启动,它也会失败(至少对于tomcat7服务而言)。有尾巴的作品。对于这两种情况下,你需要使用开关cap_add( -用于运行帽加SYS_PTRACE)与至少SYS_PTRACE
zhrist


73

在您的中Dockerfile,在最后一行添加

ENTRYPOINT service ssh restart && bash

这个对我有用

结果如下:

root@ubuntu:/home/vagrant/docker/add# docker run -i -t ubuntu
 * Restarting OpenBSD Secure Shell server sshd   [ OK ]                                                                      
root@dccc354e422e:~# service ssh status
 * sshd is running

2
这很好,但是我认为您不能通过这种方式来分离容器。
mdob 2015年

1
这对我来说很棒。我无法让Nginx 1.8自动启动。您可能会发现添加以下帮助:RUN echo“ daemon off;”;>> /etc/nginx/nginx.conf RUN ln -sf / dev / stdout /var/log/nginx/access.log RUN ln -sf / dev / stderr /var/log/nginx/error.log
Lionel Morrison

1
该解决方案有什么缺点吗?
srph '16

2
当您要优雅地停止服务时,最终启动Bash是个坏主意,因为通过这种方式,docker contaienr不能被优雅地停止,docker stop或者docker restart可以被杀死。
Mohammed Noureldin

我正在使用打包器来创建docker映像,这似乎可以解决打包器文件中conaitner的问题。“更改”:[“ ENTRYPOINT服务nginx启动&& / bin / bash”]
karthik101 '17

8

简单!在dockerfile的末尾添加:

ENTRYPOINT service mysql start && /bin/bash

这是解决我目前的码头工人集装箱问题的最佳答案:Docker version 18.09.7, build 2d0083d&& /bin/bash该服务将立即停止

7

我一直发现还有另一种方法可以使可读性更高。

假设您要在运行它时启动rabbitmq和mongodb,那么您CMD将看起来像这样:

CMD /etc/init.d/rabbitmq-server start && \
    /etc/init.d/mongod start

由于CMD每个选项只能包含一个,Dockerfile因此把所有指令连接在一起&&,然后\对每个命令使用它来开始新的一行。

如果最后添加了许多命令,我建议您将所有命令都放在脚本文件中,然后像@ larry-cai建议的那样启动它:

CMD /start.sh

3

就我而言,我有一个由Apache2提供服务的PHP Web应用程序,该容器由Docker容器连接至MYSQL后端数据库。Larry Cai的解决方案进行了少量修改。我创建了一个entrypoint.sh用于管理服务的文件。我认为entrypoint.sh在容器启动时创建一个有多个命令要执行的命令时,这是引导docker的一种更干净的方法。

#!/bin/sh

set -e

echo "Starting the mysql daemon"
service mysql start

echo "navigating to volume /var/www"
cd /var/www
echo "Creating soft link"
ln -s /opt/mysite mysite

a2enmod headers
service apache2 restart

a2ensite mysite.conf
a2dissite 000-default.conf
service apache2 reload

if [ -z "$1" ]
then
    exec "/usr/sbin/apache2 -D -foreground"
else
    exec "$1"
fi

只需将其与Dockerfile一起放置即可。然后在您的Dockerfile中,应该有一条指令将此文件复制到所需位置。然后,您将ENTRYPOINT ['your location']指令指向脚本文件。但是请记住要在脚本上设置执行权限。COPY entrypoint.sh /entrypoint.sh RUN chmod 755 /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"]。在此示例中,我将入口点复制到Docker容器中的根目录。
Doomsbuster先生18年

Dockerfile在哪里?
维克多·乔拉斯

3

当我想自动启动ssh服务时遇到同样的问题。我发现那个追加

/etc/init.d/ssh开始
〜/ .bashrc
可以解决它,但是只有您使用bash打开它才能做。


1

我将以下代码添加到/root/.bashrc中,以仅运行一次代码,

在运行此脚本之前,请先将容器提交到映像,否则将在映像中创建“ docker_services”文件,并且将不运行任何服务。

if [ ! -e /var/run/docker_services ]; then
    echo "Starting services"
    service mysql start
    service ssh start
    service nginx start
    touch /var/run/docker_services
fi

1

这是我在docker容器运行时自动启动MySQL服务的方式。

就我而言,我不仅需要运行MySQL,还需要运行PHP,Nginx和Memcached

我在Dockerfile中有以下几行

RUN echo "daemon off;" >> /etc/nginx/nginx.conf
EXPOSE 80
EXPOSE 3306
CMD service mysql start && service php-fpm start && nginx -g 'daemon off;' && service memcached start && bash

添加&& bash将使Nginx,MySQL,PHP和Memcached在容器中运行。


1

这行不通 CMD service mysql start && /bin/bash

这行不通 CMD service mysql start ; /bin/bash ;

-我猜交互式模式不支持前台。

这有效! CMD service nginx start ; while true ; do sleep 100; done;

这有效! CMD service nginx start && tail -F /var/log/nginx/access.log

当心您应该使用docker run -p 80:80 nginx_bash不带命令参数的命令。


0

Docker网站上的以下文档显示了如何在Docker容器中实现SSH服务。它应该很容易适应您的服务:

这里也有人问过这个问题:


nsenter工具是无需安装SSH服务器即可输入容器的另一种方法:github.com/jpetazzo/nsenter。但是这种方法需要访问您的Docker主机(通常SSH访问就足够了)。
Fabien Balageas 2015年

链接docs.docker.com/sorry/#/examples/running_ssh_service不起作用。你能更新一下吗?
ANKUR

0
docker export -o <nameOfContainer>.tar <nameOfContainer>

可能需要使用docker prune修剪现有容器...

导入并进行必要的修改:

cat <nameOfContainer>.tar | docker import -c "ENTRYPOINT service mysql start && /bin/bash" - <nameOfContainer>

例如,使用始终重启选项运行容器,以确保其在主机/守护进程回收后将自动恢复:

docker run -d -t -i --restart always --name <nameOfContainer> <nameOfContainer> /bin/bash

旁注:在我看来,合理的做法是仅启动cron服务,使容器保持尽可能干净,然后仅使用相应的检查/监视脚本修改crontab或cron.hourly,.daily等。原因是您仅依赖一个守护程序,如果发生更改,则使用ansible或puppet更容易重新分配cron脚本,而不是跟踪启动时启动的服务。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.