docker-compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Then, with a single command, you create and start all the services from your configuration.
It's recently become more popular as many Laravel projects start to use it, and it's a system we've used for a long time when developing for Laravel. LoadForge is a Laravel project and uses docker-compose for it's development environment, and Laravel Vapor for production. We also have other projects that are deployed in a more traditional fashion that we use docker-compose in the exact same way for.
You need to install docker and docker-compose of course. On Ubuntu you can run the following (ps yes this works in WSL2 on Windows with the Ubuntu subsystem).
apt-get install docker-compose
The best WSL2 Windows Laravel dev environment in my mind is this exact one, run inside WSL but with Docker Desktop running in Windows.
Below is our Laravel specific docker-compose. It's a lot more complex than you may need because it includes many functions, specifically:
version: '3'
networks:
laravel:
services:
site:
image: nginx:stable-alpine
container_name: laravel_site
hostname: 'laravel.dev.test'
ports:
- 80:80
- 443:443
volumes:
- ./:/var/www/html
- ./docker/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- php
- postgres
- redis
networks:
- laravel
postgres:
image: postgres:12.3-alpine
container_name: laravel_postgres
ports:
- 5432
environment:
POSTGRES_DB: laravel
POSTGRES_USER: laravel
POSTGRES_PASSWORD: secret
networks:
- laravel
redis:
image: redis:6-alpine
container_name: laravel_redis
ports:
- 6379
networks:
- laravel
php:
build:
context: .
dockerfile: docker/php.dockerfile
container_name: laravel_php
volumes:
- ./:/var/www/html
ports:
- 9000
networks:
- laravel
composer:
image: composer:2
container_name: laravel_composer
volumes:
- ./:/var/www/html
working_dir: /var/www/html
depends_on:
- php
networks:
- laravel
npm:
image: node:13.7
container_name: laravel_npm
volumes:
- ./:/var/www/html
working_dir: /var/www/html
entrypoint: ['npm']
networks:
- laravel
artisan:
build:
context: .
dockerfile: docker/php.dockerfile
container_name: laravel_artisan
volumes:
- ./:/var/www/html
depends_on:
- postgres
- php
- redis
working_dir: /var/www/html
entrypoint: ['php', '/var/www/html/artisan']
networks:
- laravel
scheduler:
container_name: laravel_scheduler
build:
context: .
dockerfile: docker/php.dockerfile
volumes:
- ./docker/scheduler.sh:/run.sh
- ./:/var/www/html
working_dir: /var/www/html
depends_on:
- site
networks:
- laravel
command: /bin/sh /run.sh
worker:
container_name: laravel_worker
build:
context: .
dockerfile: docker/php.dockerfile
volumes:
- ./:/var/www/html
working_dir: /var/www/html
restart: always
depends_on:
- site
- redis
networks:
- laravel
command: php /var/www/html/artisan queue:work
You will want to create the above as docker-compose.yml in your main project directory (laravel/). Then create a docker directory inside of that for storing our custom configurations.
mkdir docker
In there we want to create three files. One is a custom nginx config file, and the second is our custom container for PHP allowing for customization of your PHP install. Finally we add a helper script for the scheduler.
docker/default.conf
server {
listen 80;
index index.php index.html;
server_name localhost;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /var/www/html/public;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
docker/php.dockerfile
FROM php:7.4-fpm-alpine
WORKDIR /var/www/html
RUN apk add --update sqlite-dev zlib-dev zlib libpng-dev libzip-dev freetype-dev libjpeg-turbo-dev libpq postgresql-dev pkgconfig imagemagick6 autoconf
RUN docker-php-ext-configure gd
RUN docker-php-ext-install zip pcntl pdo pdo_mysql gd exif sockets pgsql bcmath pdo_pgsql exif
RUN docker-php-ext-enable pdo_pgsql exif
RUN apk add --update autoconf build-base
RUN pecl install -o -f redis
RUN docker-php-ext-enable redis
RUN link /usr/local/bin/php /usr/bin/php
RUN echo "php_admin_value[memory_limit] = 2G" >> /usr/local/etc/php-fpm.d/www.conf
RUN echo "memory_limit=2G" >> /usr/local/etc/php/php.ini
docker/scheduler.sh
sleep 60
while [ true ]
do
php /var/www/html/artisan schedule:run --verbose --no-interaction &
sleep 60
done%
You can now run the following to launch the environment:
docker-compose up -d --build
Personally, I always add these aliases to my ~/.zshrc:
alias dev="docker-compose run --rm"
alias dcu="docker-compose up"
alias dqw="docker-compose run --rm artisan queue:work --timeout=900"
That allows you specifically to use "dcu" to launch your environment, and "dev" to run commands in it. For example:
dev npm update
dev composer require xyz
dev artisan test
Aside from the great opportunity to learn what's going on under the hood, and how it helps you to deploy into production, this guide really serves to help those who may have more complicated stacks that something like Laravel Sail provides. You can really customize and tweak your system to suit you.
Feel free to comment for any assistance :)
Recent blog posts from our load testing experts: