Run your Laravel app with docker-compose

Feb 27, 2021 by Thibault | 284 views

Laravel Docker PHP

https://cylab.be/blog/131/run-your-laravel-app-with-docker-compose

Docker-compose is an elegant way to run a Laravel app. It allows to define and run the different services: the main web app, a MySQL database and a redis server. There are however a few tricks to solve: how to run the database migrations, how to run the queue worker and the scheduler?

In this blog post we show one possible approach, where we override the entrypoint directive.

docker-compose.yml

First, create docker-compose.yml like the one below:

version: "3"
services:
  myapp:
    image: myapp
    build:
      context: .
    depends_on:
      - redis
      - mysql
    ports:
      - 8080:80
    volumes:
      - myapp:/var/www/html/storage
    ## we wait for the MySQL container to be up and running
    ## then we run the migration
    ## and finally we start apache
    entrypoint: sh -c "sleep 30 && php /var/www/html/artisan migrate && apache2-foreground"

  queue:
    image: myapp
    depends_on:
      - myapp
    volumes:
      - myapp:/var/www/html/storage
    ## for the queue worker, we use the same image, but run 
    ## artisan queue:work
    entrypoint: php /var/www/html/artisan queue:work --verbose --tries=3 --timeout=60

  scheduler:
    image: myapp
    depends_on:
      - myapp
    ## for the scheduler we use an infinite while loop
    entrypoint: sh -c "while true; do php /var/www/html/artisan schedule:run --verbose & sleep 60; done"

  redis:
    image: redis:4-alpine
    volumes:
      - redis:/data

  mysql:
    image: mysql:5.7
    volumes:
      - mysql:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: myapp

volumes:
  myapp:
    driver: "local"
  redis:
    driver: "local"
  mysql:
    driver: "local"

Dockerfile

Now create the appropriate Dockerfile to build your image. In the example below we use a multi-stage build. You can also find some inspiration in the other blog post Dockerize your Laravel app - part 2

#### Step 1 : composer

FROM cylab/php74 AS composer

COPY . /var/www/html
WORKDIR /var/www/html
RUN composer install --no-dev --optimize-autoloader

#### Step 2 : actual docker image

FROM php:7.4-apache

## PHP extensions

RUN docker-php-ext-install pdo_mysql

RUN pecl install -o -f redis \
    &&  rm -rf /tmp/pear \
    &&  docker-php-ext-enable redis

## Apache

# change the document root to /var/www/html/public
RUN sed -i -e "s/html/html\/public/g" \
    /etc/apache2/sites-enabled/000-default.conf

RUN a2enmod rewrite

## Laravel application

COPY . /var/www/html
# I like to use a dedicated .env file to prive sound defaults
COPY env.docker /var/www/html/.env
COPY --from=composer /var/www/html/vendor /var/www/html/vendor

RUN mkdir -p storage/framework/cache storage/framework/sessions storage/framework/views \
    && chown -R www-data:www-data /var/www/html/storage /var/www/html/bootstrap/cache \
    && php artisan config:clear

env.docker

As you may have noticed above, I like to have a dedicated .env file to run the application. Here is an example env.docker:

APP_NAME=myqpp
APP_ENV=prod
APP_KEY=base64:ezEe4jH/6EUM2fMWLnco3kuMz1OMStq/XfV456ZwMhc=
APP_DEBUG=false
APP_URL=http://localhost

LOG_CHANNEL=stack

DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=myapp
DB_USERNAME=root
DB_PASSWORD=root

BROADCAST_DRIVER=log
CACHE_DRIVER=redis
QUEUE_CONNECTION=redis
SESSION_DRIVER=redis
SESSION_LIFETIME=120

REDIS_HOST=redis
REDIS_PASSWORD=null
REDIS_PORT=6379

MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null

Running

You are now ready to run your app:

docker-compose up --build