In my previous post about Docker and Laravel, we needed a large amount of containers to get everything working and to conform to Docker best-practices. These best practices mean we should have one container per process, which helps keep the containers simple and isolated. All the "core" processes (e.g. Nginx, PHP-FPM, etc.) and "development" processes (e.g. composer, artisan etc.) each had their own container. In a production environment this would be perfectly fine, because we would configure the operating system's init daemon (e.g. Systemd) to automatically start the "core" containers on boot, and we wouldn't really need to be running the "development" containers that often so we could deal with the complexity then. A development environment is much more dynamic though, and we're going to need to be starting and stopping containers regularly, each time we run
bower, etc commands. Something a bit more graceful is needed for managing the containers we need to run in our development environment.
When you visit the Fig homepage, a slogan greets you stating "Fast, isolated development environments using Docker". This sounds like exactly what we need!
The premise behind Fig is you have a
fig.yml file in the root of your application directory which defines how all your containers fit together. You can simply run the
fig up command to bring all your containers up and working together. For example, running
fig up in a directory with the below
fig.yml file in it brings up a PHP-FPM and Nginx web server, linked together.
php: image: dylanlindgren/docker-laravel-phpfpm volumes: - /laravel:/data web: image: dylanlindgren/docker-laravel-nginx volumes_from: - php links: - php:fpm ports: - "80:80"
The beauty of Fig is that it works not just on Docker's native environment Linux, but also works with Boot2Docker, and will run the containers within the virtual machine that it creates.
Preparations & Assumptions
I use a late-2013 MacBook Pro, and these instructions are written for that environment. It shouldn't be hard however to translate the below to either Linux or a Windows if you understand the basics of Docker.
To follow these instructions on OS X, you must have Boot2Docker installed with an ISO that supports shared folders. I suggest reading my previous post if you need help with this.
The Boot2Docker virtual machine must have two ports mapped to it, one for web traffic (e.g.
8080), and another for SQL traffic (e.g.
3306). It also must have two shared folders mapped to it, one for your Laravel files and Nginx logs (mounted to
/laravel on your Boot2Docker VM), and another for MariaDB's data folder (mounted at
/mariadb on your Boot2Docker VM). Here's that structure visualised:
Lets take the 6 containers we used in my previous post, and an additional
dylanlindgren/docker-mariadb container, to create a local development environment using Fig:
db: image: dylanlindgren/docker-mariadb volumes: - /mariadb:/data/mariadb ports: - "3306:3306" privileged: true data: image: dylanlindgren/docker-laravel-data volumes: - /laravel:/data privileged: true php: image: dylanlindgren/docker-laravel-phpfpm volumes_from: - data links: - db:db privileged: true web: image: dylanlindgren/docker-laravel-nginx volumes_from: - data links: - php:fpm ports: - "8080:80" privileged: true composer: image: dylanlindgren/docker-laravel-composer volumes_from: - data artisan: image: dylanlindgren/docker-laravel-artisan volumes_from: - data links: - db:db bower: image: dylanlindgren/docker-laravel-bower volumes_from: - data
You should notice that each section of the file has a heading, which is the name of the container that will be created (e.g.
web). Underneath that heading is all the details about how to create the container, such as the image to be used, which ports to publish, volumes to map, and directive to run the container in privileged mode. Fig supports all commands available under the
docker run command. You can read more about
fig.yml files at the Fig website.
One thing I want to point out is that the
db container has the directory
/mariadb on the VM mapped as
/data inside it. In a similar fashion, the
data container has the
/laravel directory on the VM mapped as
/data inside of it.
Running our Development Environment
To run Fig, simply run the
fig up -d command from the directory where your
fig.yml file is. The
-d switch directs Fig to run the containers in the background.
When you run
docker ps -a you can see all the containers were created.
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 654355f20257 41369f0ff493 "php artisan dump-au 5 hours ago Exited (0) 5 hours ago www_artisan_1 57ff9703c7ca dylanlindgren/docker-laravel-nginx:latest "/opt/bin/nginx-star 5 hours ago Up 5 hours 443/tcp, 0.0.0.0:8080->80/tcp www_web_1... cc289ee65926 dylanlindgren/docker-laravel-phpfpm:latest "/usr/sbin/php5-fpm 5 hours ago Up 5 hours 9000/tcp www_php_1... 1c550a761dfb dylanlindgren/docker-mariadb:latest "/opt/bin/mariadb-st 5 hours ago Up 5 hours 0.0.0.0:3306->3306/tcp www_db_1... 246e1cb9cf1a dylanlindgren/docker-laravel-bower:latest "bower help" 5 hours ago Exited (0) 5 hours ago www_bower_1 f0a795b85b03 dylanlindgren/docker-laravel-composer:latest "composer --help" 5 hours ago Exited (0) 5 hours ago www_composer_1 b9f0feed3058 dylanlindgren/docker-laravel-data:latest "true" 5 hours ago Exited (0) 5 hours ago www_data_1
You'll notice in the
fig.yml file we've used the
links directive (which translates into the
link Docker command) to link the
db container when creating the
php container. When you use the
link Docker command, the details for the container you're linking to become available as environment variables in the container you're running. For example, in the case above, an environment variable in the
php container called
DB_PORT_3306_TCP_ADDR will exist, as the
dylanlindgren/docker-mariadb container publishes port
3306. This environment variable will contain the IP address of the
db container. Therefore, in our Laravel
database.php, we could use this environment variable as the host, and no matter what the IP address assigned to the
db container, Laravel will always point to the correct one!
... 'driver' => 'mysql', 'host' => getenv('DB_PORT_3306_TCP_ADDR'), 'database' => 'track', 'username' => 'docker', 'password' => 'docker', ...
Running Development Commands
To run one-off commands for development you can use the
fig run command. For example, lets setup Laravel with composer.
fig run --rm composer create-project laravel/laravel /data/www --prefer-dist
This instructs Fig to run the
composer container, with the command
create-project laravel/laravel /data/www --prefer-dist, and then remove the container after it's run (the
If we wanted to run all the migrations and seed the database with , we would do so in a similar way:
fig run --rm artisan migrate:refresh --seed
Hopefully this article not only helps you understand how to use Fig to create your Docker + Laravel development environment, but also gives you a greater understanding of Docker and its many advantages.
Feel free to contact me in the comments below, on twitter at @dylanlindgren, or email with email@example.com.