【问题标题】:How to automatically start a service when running a docker container?运行docker容器时如何自动启动服务?
【发布时间】:2014-09-27 22:38:03
【问题描述】:

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

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

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

service mysql start

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

【问题讨论】:

  • 不,对于一个简单的服务,不需要supervisor,这对于启动用户来说很复杂
  • 您可能想在此处复制 dockerfile,而不是链接到不再存在的文件
  • 关于 supervisord 的 docker 文章现在在这里:docs.docker.com/config/containers/multi-service_container 我使用 && tail 命令让我的服务工作 - 但需要在 docker run 命令中添加“--cap-add SYS_PTRACE” .

标签: docker


【解决方案1】:

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

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

Docker 镜像不保存正在运行的进程。因此,您的RUN 命令仅在docker build 阶段执行,并在构建完成后停止。相反,您需要在容器启动时使用CMDENTRYPOINT 命令指定命令,如下所示:

CMD mysql start

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

解决方案

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

  • 使用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 容器中启动后如何重启服务?
  • @KarlMorrison docker exec -it <CONTAINER NAME> mysql /etc/init.d/mysqld restart
  • 我不建议跟踪 MySQL 的错误日志来确定数据库是否正在运行。在大多数 mysqld 设置中,服务器将从 soe 错误中恢复,在此过程中,错误日志将关闭然后重新打开。我也不确定你的 tail -F 在所有甚至某些情况下都对你有用。
  • 我不知道为什么,但第一个解决方案选项适用于服务脚本。当你不使用tail时,它会失败,即使服务已经启动(至少对于tomcat7服务)。用尾巴它可以工作。对于这两种情况,您都需要使用 switch cap_add(--cap-add SYS_PTRACE for run) 至少 SYS_PTRACE
  • 不,在stackoverflow.com/questions/46800594/…中查看更多信息
【解决方案2】:

在您的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

【讨论】:

  • 这很好,但我认为你不能这样拥有一个分离的容器。
  • 这对我很有用。我无法让 Nginx 1.8 自动启动。您可能会发现添加以下内容很有帮助: RUN echo "daemon off;" >> /etc/nginx/nginx.conf 运行 ln -sf /dev/stdout /var/log/nginx/access.log 运行 ln -sf /dev/stderr /var/log/nginx/error.log
  • 这个解决方案有什么缺点吗?
  • 当您想优雅地停止服务时,最终启动 Bash 是一个坏主意,因为这样 docker 容器不能被 docker stopdocker restart 优雅地停止,只能被杀死。
  • 我正在使用打包程序来创建 docker 映像,这似乎解决了我在打包程序文件中使用 conaitner 的问题。 “变化”:[“入口点服务 nginx 启动 && /bin/bash”]
【解决方案3】:

简单!在dockerfile末尾添加:

ENTRYPOINT service mysql start && /bin/bash

【讨论】:

  • 这是解决我当前 Docker 容器问题的最佳答案:Docker version 18.09.7, build 2d0083d,如果没有 && /bin/bash,服务将立即停止
【解决方案4】:

还有另一种我一直认为更具可读性的方法。

假设您想在运行 rabbitmq 和 mongodb 时启动它,那么您的 CMD 将如下所示:

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

由于每个Dockerfile 只能有一个CMD,因此诀窍是将所有指令与&& 连接起来,然后为每个命令使用\ 来开始新的一行。

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

CMD /start.sh

【讨论】:

    【解决方案5】:

    在我的例子中,我有一个由 Apache2 在连接到 MYSQL 后端数据库的 docker 容器中提供服务的 PHP Web 应用程序。 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 容器中的根目录。
    • Dockerfile 在哪里?
    【解决方案6】:

    这不起作用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

    【讨论】:

      【解决方案7】:

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

      /etc/init.d/ssh start
      ~/.bashrc
      可以解决,但是只有用bash打开才行。

      【讨论】:

        【解决方案8】:

        这是我在 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 在容器内运行。

        【讨论】:

          【解决方案9】:

          我将以下代码添加到/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
          

          【讨论】:

            【解决方案10】:
            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 脚本而不是跟踪启动时启动的服务更容易。

            【讨论】:

              【解决方案11】:

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

              这里也有人问过这个问题的变体:

              【讨论】:

              【解决方案12】:

              如果您无法更改 docker 文件 /docker 映像。 这是解决方法:

              docker run imageid bash -c 'service mysql start ;虽然是真的;睡100;完毕; '

              【讨论】:

                【解决方案13】:

                我正在使用docker-compose.yml(版本:“3.9”)

                我所做的是在docker-compose.yml的服务中添加如下命令来启动服务并运行非结束进程。

                command: /bin/sh -c "service mysql start; while sleep 1000; do :; done"
                

                【讨论】:

                  猜你喜欢
                  • 2023-03-30
                  • 2014-11-04
                  • 2013-08-05
                  • 1970-01-01
                  • 2016-12-16
                  • 1970-01-01
                  • 2020-11-28
                  • 2019-11-24
                  • 2018-05-20
                  相关资源
                  最近更新 更多