Developing Laravel applications with Docker

Patrick Foh Jr
7 min readDec 19, 2016

--

One challenge every developer or development team faces is environment consistency. At some point in your career you might have had to deal with situations where code deployed to your production environment doesn’t quite work as it did in your development environment.

Configuration and versions differences are usually the cause of this problem, imagine developing a PHP application with PHP 7 on your local machine with all the modules you need enabled, and deploying to a production environment only to discover modules your application requires to run are absent. To solve this problem, we started using VM(virtual machines) to maintain environment consistency, but soon we discovered VMs are not very efficient or portable. They are typically time consuming and require a lot of system resources to function properly.

Enter Docker.

Docker containers wrap a piece of software in a complete filesystem that contains everything needed to run: code, runtime, system tools, system libraries — anything that can be installed on a server. This guarantees that the software will always run the same, regardless of its environment.

With Docker, you can build and run lightweight containers for any service you would need. Need to upgrade to a newer version of PHP?, no problem Docker allows you destroy your entire environment, reconfigure it, and have it running again quickly.

Laravel(one of the best things to happen to PHP) integrates with alot of technologies (MySQL, Redis, MongoDB, Memcached, etc) to provide a wide array of functionalities. It can be quite a challenge to get a good configuration when starting out. The goal of this post is to provide some understanding of building Laravel apps with Docker.

tldr; You can checkout the code for this at https://github.com/mrfoh/docker-laravel

Contents

  • Laravel setup
  • Docker setup
  • Local environment setup
  • Adding a database

Laravel setup

We’ll be working with Laravel 5.3 for this post. We’ll be installing it using composer.

Next step is verify your installation

$ cd docker-laravel
$ php artisan serve
Installation success

Docker setup

Docker runs on Mac, Windows, and Linux. Select your platform to install Docker on your machine. This will install Docker, as well as Docker Compose which we will use in this post.

After installing you should be able to verify installation with these commands.

I already have some containers running

If you get an error running the docker ps command, you need open Docker and start it manually.

Local environment setup

Next step is getting local environment setup right. If you setup a PHP environment before you are probably already familiar with running PHP alongside a web server like Nginx or Apache. With Docker, we’ll create containers to house specific parts of the infrastructure of our local environment. We’ll have a container that runs nginx to handle web request, another container to handle application requests with PHP-FPM, and couple others to handle the application’s database and caching needs. Each container will have a single responsibility and will be linked together, so they can communicate.

Overview of the environment

Next up, we’ll use Docker Compose to put together all the pieces of our environment. In the root of the project, create a file named docker-compose.yml.

docker-composer.yml

In the docker-compose.yml file;

  • We have defined two services AKA containers; web and app
  • The web and app containers are set to use the project root as the context from which the docker-compose tool builds out environment. The files also specifies the names of Dockerfiles(app.docker, web.docker) which will instruct Docker on how to build our containers.
  • The next thing you’ll next is the volumes directive. This allows us to mount our project directory as volume on the container at the specified path, in this case /var/www .
  • The web container exposes port 8080 on our machine and maps it to port 80 on the container, allowing us access to the app.
  • The links directive allows us to link one container to another, allowing us to reference the app container as a host from within the web container.

The docker documentation has more information about more configuration directives available for Docker Compose, you can check it out here.

Lets create the Dockerfiles for our containers. Dockerfiles are essential files containing instructions on how to build a container image. These instructions are similar to the typical steps taken to provision a server for a task; web server, database server, PHP app server, etc. Dockerfiles allows us leverage already created base images which makes configuration very minimal.

app.docker

In line 1, we specify the base image for our app container to be PHP-FPM using FROM, with this convention you can easily switch to a different versions of this base image. Our base image is pulled from the Docker Hub, which houses a lot of other base images.

In line 2, we run some commands to make sure our container is up to date, and also fetch some dependencies for our application.

web.docker

Like in the app.docker file, we specify a base image and perform some configuration. In line 3, we are adding an Nginx configuration file to the web container.

vhost.conf

The vhost.conf file contains standard Nginx configuration that will handle http requests and proxy traffic to our app container on port 9000. Remember from earlier, we named our container app in the Docker Compose file and linked it on the web container, so here we can just reference that container by its name and Docker will route traffic to that app container.

Next up, run this command from the root of the project

$ docker-compose up -d

This command tells Docker to start the containers in the background. The first time you run the command, it might take sometime to download the two base images, after that it will be much faster. You can now visit the app at http://localhost:8080

Note: Docker may not be using localhost (like on Windows sometimes). Run docker-machine ip default to get the IP address to use instead

Now we’ve got our laravel app powered by docker containers running.

Adding a database

So we’ve got our Laravel app up and running, the next step is to add another container to handle the application’s database needs. First off let’s stop our containers.

$ docker-composer kill #stops all running containers

Next we’ll update the docker-compose.yml file and add a MySQL base image for our database container.

We made a few changes:

  • added link on the appcontainer to the dbcontainer.
  • add DB_PORT and DB_HOST environment variables to the app container. This will allow us to configure our local machine to connect using the config values set in the laravel .env file. This allows us run artisan locally, without messing with the connection details that are used inside the container.
  • created the db container using the mysql base image and set some environment values to configure some defaults for the image.
  • expose port 33061 on our machine and forward it to 3306 on the container. This is also so that we can run artisan locally.

Now in our .env file for Laravel we can configure the connection details.

Now you can startup your updated environment with

$ docker-compose up -d

You now have database container to store data. You can now run php artisan migrate to create the laravel migrations table on your db, and start create laravel database migrations as usual.

You can make sure the mysql container is running with

$ docker ps

We successfully dockerized our local laravel environment. Now we can easily update the Docker Compose fill and add new containers for more services like Redis, MongoDb, etc.

This post was heavily inspired by a blog post by Kyle Ferguson, which gave me a headstart on Docker.

--

--