From e59ec8b27fb1b060efd556b25caf41f0a2067413 Mon Sep 17 00:00:00 2001 From: Jonathon Reinhart Date: Thu, 7 Mar 2019 15:42:00 -0500 Subject: [PATCH] Run Laravel schedule in docker image using supervisord (#6606) * docker: Rename /entrypoint.sh to /startup.sh This script is not configured as the docker image ENTRYPOINT, thus it is misleading to name it so. * docker: Terminate supervisord if a process enters the FATAL state By terminating PID 1, this will also terminate the Docker container. * docker: Use supervisord to start up apache and cron Note that this uses `apache2ctl -DFOREGROUND` rather than manually sourcing /etc/apache2/envvars and running apache2, as recommended at https://advancedweb.hu/2018/07/03/supervisor_docker/. * docker: Add artisan schedule:run to crontab This also switches to executing /var/www/html/artisan directly. * docker: Run artisan schedule:run directly from supervisor This has the following benefits over using cron: - Cron doesn't need to be installed - Docker-provided environment variables are preserved - It's easy and explicit to run as the docker user --- Dockerfile | 20 ++++++++------------ docker/{entrypoint.sh => startup.sh} | 5 ++--- docker/supervisor-exit-event-listener | 19 +++++++++++++++++++ docker/supervisord.conf | 27 +++++++++++++++++++++++++++ 4 files changed, 56 insertions(+), 15 deletions(-) rename docker/{entrypoint.sh => startup.sh} (92%) create mode 100644 docker/supervisor-exit-event-listener create mode 100644 docker/supervisord.conf diff --git a/Dockerfile b/Dockerfile index f13fa9ea61..e973275268 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,9 +18,8 @@ patch \ curl \ vim \ git \ -cron \ mysql-client \ -cron \ +supervisor \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* @@ -69,7 +68,9 @@ RUN \ && rm -r "/var/www/html/storage/app/backups" && ln -fs "/var/lib/snipeit/dumps" "/var/www/html/storage/app/backups" \ && mkdir "/var/lib/snipeit/keys" && ln -fs "/var/lib/snipeit/keys/oauth-private.key" "/var/www/html/storage/oauth-private.key" \ && ln -fs "/var/lib/snipeit/keys/oauth-public.key" "/var/www/html/storage/oauth-public.key" \ - && chown docker "/var/lib/snipeit/keys/" + && chown docker "/var/lib/snipeit/keys/" \ + && chmod +x /var/www/html/artisan \ + && echo "Finished setting up application in /var/www/html" ############## DEPENDENCIES via COMPOSER ################### @@ -96,16 +97,11 @@ VOLUME ["/var/lib/snipeit"] ##### START SERVER -COPY docker/entrypoint.sh /entrypoint.sh -RUN chmod +x /entrypoint.sh +COPY docker/startup.sh docker/supervisord.conf / +COPY docker/supervisor-exit-event-listener /usr/bin/supervisor-exit-event-listener +RUN chmod +x /startup.sh /usr/bin/supervisor-exit-event-listener -# Add Tini -ENV TINI_VERSION v0.14.0 -ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini -RUN chmod +x /tini -ENTRYPOINT ["/tini", "--"] - -CMD ["/entrypoint.sh"] +CMD ["/startup.sh"] EXPOSE 80 EXPOSE 443 diff --git a/docker/entrypoint.sh b/docker/startup.sh similarity index 92% rename from docker/entrypoint.sh rename to docker/startup.sh index 171b4f70a3..14777cc10d 100644 --- a/docker/entrypoint.sh +++ b/docker/startup.sh @@ -5,7 +5,7 @@ if [ -z "$APP_KEY" ] then echo "Please re-run this container with an environment variable \$APP_KEY" echo "An example APP_KEY you could use is: " - php artisan key:generate --show + /var/www/html/artisan key:generate --show exit fi @@ -47,5 +47,4 @@ then cp -ax /var/www/html/vendor/laravel/passport/database/migrations/* /var/www/html/database/migrations/ fi -. /etc/apache2/envvars -exec apache2 -DNO_DETACH < /dev/null +exec supervisord -c /supervisord.conf diff --git a/docker/supervisor-exit-event-listener b/docker/supervisor-exit-event-listener new file mode 100644 index 0000000000..84201634e1 --- /dev/null +++ b/docker/supervisor-exit-event-listener @@ -0,0 +1,19 @@ +#!/usr/bin/env python +# A supervisor event listener which terminates supervisord if any of its child +# processes enter the FATAL state. +# https://stackoverflow.com/a/37527488/119527 +import os +import signal + +from supervisor import childutils + +def main(): + while True: + headers, payload = childutils.listener.wait() + childutils.listener.ok() + if headers['eventname'] != 'PROCESS_STATE_FATAL': + continue + os.kill(os.getppid(), signal.SIGTERM) + +if __name__ == "__main__": + main() diff --git a/docker/supervisord.conf b/docker/supervisord.conf new file mode 100644 index 0000000000..9820147310 --- /dev/null +++ b/docker/supervisord.conf @@ -0,0 +1,27 @@ +[supervisord] +nodaemon=true + +[program:apache] +; https://advancedweb.hu/2018/07/03/supervisor_docker/ +command=apache2ctl -DFOREGROUND +killasgroup=true +stopasgroup=true +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + +[program:run_schedule] +; Simply run the Laravel command scheduler every minute +command=/bin/bash -c "while true; do /var/www/html/artisan schedule:run; sleep 1m; done" +user=docker +stdout_logfile=/dev/stdout +stdout_logfile_maxbytes=0 +stderr_logfile=/dev/stderr +stderr_logfile_maxbytes=0 + + +; https://stackoverflow.com/a/37527488/119527 +[eventlistener:exit_on_any_fatal] +command=supervisor-exit-event-listener +events=PROCESS_STATE_FATAL