How to run Laravel using Docker
May 19, 2019

Docker and Laravel

Laravel has official documentation for running laravel locally here. The documentation doesn't touch on how to use docker. Laradock is a good solution, however it tries to provide everything under the sun. I don't need that. I need simplicity so I can code.

At my previous employer I came up with a pretty slick test rig so that I could do end to end tests with typescript. This post will describe my approach to this.

So first thing I needed to provide was a docker image for this to work. That can be found here. From there a docker-compose.yml file can be added to your laravel project with the following configuration.

version: '2'
services:
  app:
    image: kyleparisi/larasible
    ports:
      - 80:80
    environment:
      - APP_ENV=testing
    volumes:
      - ./:/var/www/default

  mysql:
    image: mysql:5.7
    ports:
      - 3306:3306
    environment:
      - MYSQL_DATABASE=homestead
      - MYSQL_USER=homestead
      - MYSQL_PASSWORD=secret
      - MYSQL_ROOT_PASSWORD=secret

One thing I have rarely seen answered is how to do a composer install without running into permission issues between the host and the container. I later found that you can attach the host user id as the owner and this will allow both the host and the container to work with the vendor files.

#!/usr/bin/env bash

docker run --rm \
    --user $(id -u):$(id -g) \
    --volume $PWD:/var/www/default \
    --volume $HOME/.composer:/.composer \
    --workdir /var/www/default \
    --entrypoint "composer" \
    kyleparisi/larasible "$@"

I usually add this bash script to ./scripts/composer.sh and you can run all the typical commands you want. ./scripts/composer.sh install for example. This is nice because you no longer need any dependencies on the host beyond docker. The same thing can be done for the front end dependencies.

#!/usr/bin/env bash

docker run --rm \
    --volume $PWD:/usr/src/app \
    --workdir /usr/src/app \
    node:8 npm "$@"

So add both scripts to a ./scripts/ directory in your laravel project and make them executable.

chmod +x ./scripts/composer.sh
chmod +x ./scripts/npm.sh

Add a .env.testing file to your laravel project which will be used in our test rig.

APP_ENV=testing
APP_KEY=base64:blahblah
APP_DEBUG=true
APP_LOG_LEVEL=debug
APP_URL=http://localhost

DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret

BROADCAST_DRIVER=log
CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=sync

REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379

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

PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=

Now for the meat and potatoes.

#!/usr/bin/env bash

set -e

 [ -f ".env.testing" ] || $(echo Please make an .env.testing file and run: php artisan key:generate --env=testing; exit 1)
export $(cat .env.testing | grep -v ^# | xargs);
echo Starting services
docker-compose up -d
echo Host: 127.0.0.1
until docker-compose exec mysql mysql -h 127.0.0.1 -u $DB_USERNAME -p$DB_PASSWORD -D $DB_DATABASE --silent -e "show databases;"
do
  echo "Waiting for database connection..."
  sleep 5
done
echo Installing dependencies
./scripts/npm.sh install
./scripts/composer.sh install
echo Seeding database
rm -f bootstrap/cache/*.php
docker-compose exec app php artisan migrate --env=testing && echo Database migrated
docker-compose exec app php artisan db:seed --env=testing && echo Database seeded

Add the above script to the root of your laravel project as testrig.sh and also make it executable. This script does everything you need to run your laravel project. It starts up the servers, ensures the database is booted, installs dependencies, runs database migrations, and runs database seeds. These services are exposed to your computer on the standard ports.

./testrig.sh

Visit http://localhost when the script is done to see the laravel welcome screen. Mysql can be found on port 3306. If you had snazzy end to end tests you could add your test command to the end of the testrig.sh file. For example npm test.

From here you can do your "test driven development" or regular development using this test rig. When your done for the day, clean up is super simple.

docker-compose stop && docker-compose rm

Hopefully you'll find this method faster than the official options and simpler than laradock.

Gist of files.

Get updates