Using Docker for Laravel Development

Docker can be a good replacement for Homestead and Valet when developing a project that needs to be shared with developers working on different operating systems (Linux, Windows, MacOS) and having special requirements not covered by installing homestead. With smaller projects, Valet works fine, and Homestead can support larger projects due to preinstalled packages both of them have limitations. For Valet it's the issue of installing all the project's dependencies on a local machine which must be reinstalled to accommodate specific requirements. And Homestead is bulky, slow, includes a lot of unnecessary packages.

Docker in a way follows the "Composition over inheritance" principle by providing necessary smaller images to compose an environment instead of using a prebuilt monolith with bloat.

docker-compose cheatsheet #

Note: you need to cd first to where your docker-compose.yml is located.

Basic Setup #

To get started Laravel requires three basics: a web-server, a database and php. I will be using Nginx, PHP-FPM and PostgreSQL.

Minimal docker-compose.yml for docker:

I will be using alpine images to speed-up download times. And pre-built jguyomard/laravel-php:7.2 image, which includes all the necessary Laravel dependencies. It is possible to add extra packages and build your own php image. Just copy this Dockerfile and modify as needed. Here is a good example on ElisDN Laravel Demo. But I prefer images stored in the hub.docker.com as it removes the build step.

Notice that ${} syntax is used to extract environment variables from .env file. And that I've created a docker folder with additional configuration files.

version: "3"
services:
nginx:
image: nginx:1.15-alpine
volumes:
- .:/var/www/
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
ports:
- 8080:80
depends_on:
- php
- postgres
php:
image: jguyomard/laravel-php:7.2
volumes:
- ./:/var/www/
- $HOME/.composer/:$HOME/.composer/
environment:
- DB_HOST=${DB_HOST}
- DB_DATABASE=${DB_DATABASE}
- DB_USERNAME=${DB_USERNAME}
- DB_PASSWORD=${DB_PASSWORD}
postgres:
image: postgres:11-alpine
environment:
- POSTGRES_DB=${DB_DATABASE}
- POSTGRES_USER=${DB_USERNAME}
- POSTGRES_PASSWORD=${DB_PASSWORD}
ports:
- 5432:5432
volumes:
- postgres-data:/var/lib/postgresql/data
volumes: postgres-data:

And default.conf for nginx:

Here root /var/www/public; must correspond to previously configured volume in docker-compose.yml. And php name in fastcgi_pass php:9000; line will be the one used to indicate the php service. For example if there are multiple php services php-cli and php-fpm this line will be fastcgi_pass php-fpm:9000;.

server {
listen 80;
index index.php index.html;
root /var/www/public;
client_max_body_size 32M;

location / {
try_files $uri /index.php?$args;
}

location ~ \.php$ {
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;
}
}

Adding Extras #

Once the basic development environment is setup it is possible to add additional images: node to build front-end assets, redis for caching, mailhog to catch outbound email, elasticsearch for speeding up search and doing analytics.

version: '3'
services:
nginx:
image: nginx:1.15-alpine
volumes:
- .:/var/www/
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
ports:
- 8080:80
depends_on:
- php
- postgres
php:
image: jguyomard/laravel-php:7.2
volumes:
- ./:/var/www/
- $HOME/.composer/:$HOME/.composer/
environment:
- DB_HOST=${DB_HOST}
- DB_DATABASE=${DB_DATABASE}
- DB_USERNAME=${DB_USERNAME}
- DB_PASSWORD=${DB_PASSWORD}
postgres:
image: postgres:11-alpine
environment:
- POSTGRES_DB=${DB_DATABASE}
- POSTGRES_USER=${DB_USERNAME}
- POSTGRES_PASSWORD=${DB_PASSWORD}
ports:
- 5432:5432
volumes:
- postgres-data:/var/lib/postgresql/data
- ./docker/conf/postgres/:/docker-entrypoint-initdb.d/
node:
image: node:10.13-alpine
volumes:
- ./:/var/www
working_dir: /var/www
tty: true
redis:
image: redis:5.0
ports:
- 6379:6379
mailhog:
image: mailhog/mailhog:latest
ports:
- 1025:1025
- 8025:8025
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:6.4.3
environment:
- bootstrap.memory_lock=true
- 'ES_JAVA_OPTS=-Xms128m -Xmx128m'
ulimits:
memlock:
soft: -1
hard: -1
volumes:
- elastic-data:/usr/share/elasticsearch/data
ports:
- 9200:9200
volumes:
postgres-data:
elastic-data:

Services exposed outside your environment #

You can access your application via localhost.

ServiceAddress outside containers
Webserver (Nginx)localhost:8080
Mailhog (WebUI)localhost:8025
PostgreSQL (DB)localhost:5432
ElasticSearch (REST)localhost:9200
Redis (CLI)localhost:6379

Hosts within your environment #

You'll need to configure your application to use any services you enabled:

ServiceHostnamePort numberDescription
PHP-fpmphp9000Used for nginx, composer and artisan
SMTP (Mailhog)mailhog1025Catch outbound mail
HTTP (Mailhog)mailhog8025Access a WebUI to view caught email
Nodenode8081Build assets for frontend
PostgreSQLpostgres5432Application database
Redisredis6379Cache service
ElasticSearchelasticsearch9200Search service

Recommendations #

Here are some tips on using docker:



You've made it to the end! Sharing this article on your favorite social media network would be highly appreciated 🧑‍💻! For more information you can find me on Twitter.

Published