Apr 20, 2024

Deploying Laravel in Docker

No-nonsense deployments

A fair warning

This Dockerfile is intended for use with API Laravel projects where your frontend is separate, therefore it does NOT handle building assets and would need to be modified for that use-case.

The Dockerfile

// DockerfileFROM webdevops/php-nginx:8.3-alpine

ENV WEB_DOCUMENT_ROOT=/app/public
ENV PHP_MEMORY_LIMIT=128M
ENV PHP_MAX_EXECUTION_TIME=30

# Configure Supervisor
COPY ./.docker/supervisor.d/10-init.conf /opt/docker/etc/supervisor.d/10-init.conf
COPY ./.docker/supervisor.d/20-queue-worker.conf /opt/docker/etc/supervisor.d/20-queue-worker.conf

# Configure Cron
RUN echo "* * * * * cd /app && php artisan schedule:run >> /dev/null 2>&1" >> /var/spool/cron/crontabs/root

# Move to the app folder
WORKDIR /app

# Copy application files over
COPY --chown=application:application . ./

# Install dependencies
RUN COMPOSER_MEMORY_LIMIT=-1 composer install --optimize-autoloader --no-interaction --no-progress --no-dev

EXPOSE 80

CMD ["supervisord"]

Now for the supervisor.d files that are referenced above

// .docker/supervisor-d.conf/10-init.conf[program:migration]
command=/usr/local/bin/php /app/artisan migrate --force
autostart=true
autorestart=false
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
environment=LOG_CHANNEL="stderr"
user=application

[program:optimize]
command=/usr/local/bin/php /app/artisan optimize
autostart=true
autorestart=false
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
environment=LOG_CHANNEL="stderr"
user=application
// .docker/supervisor-d.conf/20-queue-worker.conf[program:queue-worker]
process_name=%(program_name)s_%(process_num)02d
command=/usr/local/bin/php /app/artisan queue:work
autostart=true
autorestart=true
stopasgroup=true
killasgroup=true
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
environment=LOG_CHANNEL="stderr"
user=application
stopwaitsecs=3600

The init supervisor file is responsible for handling migrating the database and optimising the application, if you're using this dockerfile for development then you'll want to disable the optimisation; otherwise you'll be asking why your routes and views aren't updating.

Your directory structure should look like this:

my-awesome-laravel-app
│   Dockerfile
│
└───.docker
│   │
│   └───supervisor.d
│       │   10-init.conf
│       │   20-queue-worker.conf
│
└─── ...

Happy Dockering!

Why not Sail?

Sail is NOT intended for production environments, you'll be using the in-built Laravel dev server which can only handle one request at a time, hope you have some good autoscaling strategies!