PHP7-FPM Docker CMD results in 502 Nginx Error

I've a docker compose that use two containers: nginx and php7-fpm. I'm building php via Dockerfile and I need cron installed on it:

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

This way, nginx report a 502 Bad Gateway error. If i remove the last line, CMD, everything works fine. How can I fix this?


Solution 1:

In docker container, you can only have one entrypoint or a command executed when you start the container. When you have at the end of your Dockerfile:

CMD cron && tail -f /var/log/cron.log

It means the only command that will run is cron. So your initial entrypoint for php-fpm service becomes irrelevant. In order to launch several processes in a docker container, you have to use a wrapper script or supervisor. For wrapper script, write it and copy through the build process. The script should have the start commands for all your services.

The CMD will have something like:

CMD ./wrapper_script.sh

For supervisor, there are good tutorials available online that explains how to use supervisor with docker.

Your Dockerfile will look like this:

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"]

Then create supervisord.conf file:

[supervisord]
nodaemon=true

[program:php-fpm]
command=php-fpm-commands

[program:cron]
command=cron-commands

Replace php-fpm-commands and cron-commands with the commands and options you need to be there for each service.

Solution 2:

I also came across the same question when using docker with php-fpm and nginx. The way I solved the problem was similar to the answer given previously.

TL;DR

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

Adding last line to start the process that php-fpm intended to run


As stated above,

In docker container, you can only have one entrypoint or a command executed when you start the container.

Problem

But when you add our own entrypoint to the docker container by doing CMD ["custom_script.sh"] or ENTRYPOINT ["custom_script.sh"], the default entrypoint script gets replaced by your custom one (in our case custom_script.sh).

The way I came across solution to the problem was by writing script in such a way that doesn't replace original instead extend.

Solution

  • To learn which script the docker container runs by default was found using docker-compose ps after running the container without the entrypoint script. The result in my machine looks like below;
                Name                              Command               State                Ports              
----------------------------------------------------------------------------------------------------------------
appointmentlaravel_appointment_app_1   docker-php-entrypoint php-fpm    Up      0.0.0.0:9007->6001/tcp, 9000/tcp

As you can see, by default, the script container runs is docker-php-entrypoint php-fpm so.

  • We can create custom script in such a way that at the end runs the same script that it ran originally as shown below;
# arbitary code to run when docker-container starts

docker-php-entrypoint php-fpm

In your case, the dockerfile may look like;

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

Look how I replaced the last line of your dockerfile to run docker-php-entrypoint php-fpm.