我有一个使用两个容器的docker compose:nginx和php7-fpm。我正在通过Dockerfile构建php,并且需要在其上安装cron:
FROM 'php:7-fpm'
# PDO
RUN docker-php-ext-install pdo_mysql
# Cron
RUN apt-get update -q -q && apt-get install -y cron
ADD crontab /etc/cron.d/crontab
RUN chmod 0644 /etc/cron.d/crontab
RUN touch /var/log/cron.log
CMD cron && tail -f /var/log/cron.log // this line is breaking things
这样,nginx 就会报告 502 Bad Gateway 错误。如果我删除最后一行 CMD,一切正常。我该如何修复这个问题?
答案1
在 docker 容器中,启动容器时只能执行一个入口点或命令。在 Dockerfile 末尾添加以下内容:
CMD cron && tail -f /var/log/cron.log
这意味着唯一要运行的命令是 cron。因此,php-fpm 服务的初始入口点变得无关紧要。为了在 docker 容器中启动多个进程,您必须使用包装器脚本或主管。对于包装器脚本,请编写它并通过构建过程复制。该脚本应包含所有服务的启动命令。
CMD 将会有类似如下的内容:
CMD ./wrapper_script.sh
对于 Supervisor,网上有很多很好的教程,解释如何将 Supervisor 与 docker 结合使用。
你的 Dockerfile 将如下所示:
FROM 'php:7-fpm'
# PDO
RUN docker-php-ext-install pdo_mysql
# Cron
RUN apt-get update -q -q && apt-get install -y cron supervisor
ADD crontab /etc/cron.d/crontab
RUN chmod 0644 /etc/cron.d/crontab
RUN touch /var/log/cron.log
ADD supervisord.conf /etc/supervisor.conf
ENTRYPOINT ["/usr/bin/supervisord -c /etc/supervisor.conf"]
然后创建supervisord.conf文件:
[supervisord]
nodaemon=true
[program:php-fpm]
command=php-fpm-commands
[program:cron]
command=cron-commands
将 php-fpm-commands 和 cron-commands 替换为每个服务所需的命令和选项。
答案2
php-fpm
我在使用docker with和时也遇到了同样的问题nginx
。 我解决问题的方式与之前给出的答案类似。
总结
FROM 'php:7-fpm'
# PDO
RUN docker-php-ext-install pdo_mysql
# Cron
RUN apt-get update -q -q && apt-get install -y cron
ADD crontab /etc/cron.d/crontab
RUN chmod 0644 /etc/cron.d/crontab
RUN touch /var/log/cron.log
CMD cron && docker-php-entrypoint php-fpm
php-fpm
添加最后一行以启动要运行的进程
如上所述,
在docker容器中,启动容器时只能有一个入口点或一个执行的命令。
问题
CMD ["custom_script.sh"]
但是当您通过执行或将我们自己的入口点添加到docker容器时ENTRYPOINT ["custom_script.sh"]
,默认入口点脚本将被您的自定义脚本替换(在我们的例子中custom_script.sh
)。
我找到的解决问题的方法是编写脚本,不替换原始脚本,而是进行扩展。
解决方案
- 要了解 docker 容器默认运行哪个脚本,请
docker-compose ps
在没有入口点脚本的情况下运行容器。我机器上的结果如下所示;
Name Command State Ports
----------------------------------------------------------------------------------------------------------------
appointmentlaravel_appointment_app_1 docker-php-entrypoint php-fpm Up 0.0.0.0:9007->6001/tcp, 9000/tcp
可以看到,默认情况下,脚本容器运行就是docker-php-entrypoint php-fpm
这样的。
- 我们可以创建自定义脚本,以便最后运行与最初运行的相同的脚本,如下所示;
# arbitary code to run when docker-container starts
docker-php-entrypoint php-fpm
在您的情况下,dockerfile
可能看起来像;
FROM 'php:7-fpm'
# PDO
RUN docker-php-ext-install pdo_mysql
# Cron
RUN apt-get update -q -q && apt-get install -y cron
ADD crontab /etc/cron.d/crontab
RUN chmod 0644 /etc/cron.d/crontab
RUN touch /var/log/cron.log
CMD cron && docker-php-entrypoint php-fpm
看看我如何将 dockerfile 的最后一行替换为运行docker-php-entrypoint php-fpm
。
答案3
user460778 的答案是正确的,容器只能有一个入口点,这里应该是 php-fpm 服务,所以你需要从主管运行 crons。我的主管文件如下所示
[supervisord]
nodaemon=true
[program:php-fpm]
command = /usr/local/sbin/php-fpm
autostart=true
autorestart=true
[program:cron]
autorestart=false
command=cron -f