How to containerize your Laravel Applications for local development using Docker

Andres Felipe Abello
May 27
docker

In this tutorial, I will show you how to set up your local environment with multiple Laravel applications using Docker. For this, we are going to use Laradock.io. Laradock is a full PHP development environment for Docker. It supports a variety of common services, all pre-configured to provide a ready PHP development environment.

I will show you how to set up an environment using NGINX, Redis, Mailhog, PHP worker, MySQL, and Laravel Echo. This will allow you to run a realistic environment on your local machine, one that matches a real-world server setup, plus you can actually deploy it just like this. I will write a blog post about it in the coming weeks. You can use Docker with Mac, Linux, or Windows. In my case, I use a Mac, but it should bet very similar to set up on the rest.

You can watch the video I posted a few weeks ago for visual guidance. But first, if you don’t have docker, go and install it now. You can do so following these instructions for Mac https://docs.docker.com/docker-for-mac/install/,   windows https://docs.docker.com/docker-for-windows/install/, and Linux https://docs.docker.com/engine/install/.

Once you have docker on your machine. The first thing you need to do is to go to https://laradock.io/getting-started/#installation. This will have a step by step guide to install Laradock on your machine. Set up a separate folder for all the applications you are going to containerized using docker

mdkir ~/documents/sites or whatever name you prefer.

Once you have a directory for all your Laravel development install Laradock using git like

git clone https://github.com/laradock/laradock.git
this will install Laradock in your site's directory, sites can be an existing directory where you have all your Laravel or any applications, by default Laradock is configured to read all the siblings directories of Laradock as the /var/www/ like a server. The result should be something like:
blob:https://andresabello.com/a1f54eb8-0743-4d2e-b70c-fd3896a82bcf
Now, copy the env-example file to .env like cp env-example .env, in it you can configure the version of PHP and MYSQL and any service, like FFMPEG that you want docker to install in your server.  You can configure the ports where each service will be mapped to, if you want to be able to use it like example.test on your computer then do not change the ports for HTTP, make sure they are mapped to port 80, you may have to turn off other services that are using this port, but this is important if you are trying to have a setup where you want to do something like example.test and example-2.test on your browser. I have it set up to PHP 7.3 and MYSQL 5.7. You can go through the configuration and see what will work for you.
blob:https://andresabello.com/3d515573-d3ae-477d-a84a-3b9d8772d6c7
Now, we are going to create the NGINX configurations for each service, go into the Laradock directory and then into nginx/sites, this is the same as you set it up in a server, in there you will find a few example configurations you can use laravel.conf.example. You can copy this file into the file you want for your application like cp laravel.conf.example example.conf. Go into example.conf and change the configuration to what you need. In the following example I am replacing Laravel for example, notice example.test, this is what we are going to map in our hosts file.
listen 80;
    listen [::]:80;

    # For https
    # listen 443 ssl;
    # listen [::]:443 ssl ipv6only=on;
    # ssl_certificate /etc/nginx/ssl/default.crt;
    # ssl_certificate_key /etc/nginx/ssl/default.key;

    server_name example.test;
    root /public;
    index index.php index.html index.htm;

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

    location ~ \.php$ {
        try_files $uri /index.php =404;
        fastcgi_pass php-upstream;
        fastcgi_index index.php;
        fastcgi_buffers 16 16k;
        fastcgi_buffer_size 32k;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        #fixes timeouts
        fastcgi_read_timeout 600;
        include fastcgi_params;
    }

    location ~ /\.ht {
        deny all;
    }

    location /.well-known/acme-challenge/ {
        root /var/www/letsencrypt/;
        log_not_found off;
    }

    error_log /var/log/nginx/laravel_error.log;
    access_log /var/log/nginx/laravel_access.log;
Once you create your conf file, go into /etc/hosts, and then add 127.0.0.1  example.test, make sure you save the file and then go back into Laradock. Now, you are ready to start your environment, you are going to use docker-compose to build your environment in the Laradock directory run:
docker-compose up -d mysql nginx php-worker redis laravel-echo-server workspace mailhog
You are starting the services you will need and -d is for detaching the command so that it starts and you can continue using the command line if this is the first time you run it, it will take a while setting everything up.  Now, if you have your Laravel application mapped in /var/www/example inside the container or as a sibling of Laradok outside the container, you can go into example.test in your browser and you are ready to start using Laravel with docker. Go into your .env file inside your example Laravel application and change DB_HOST=mysql and add reds as your driver where you can, here is an example
blob:https://andresabello.com/a83d2a63-d453-4381-8734-bd9611859358

 Now, you are running your cache, session, broadcast, queue with Redis, and you are trapping all of the email notifications that come out of the application in your local environment, just fo to localhost:8025 and you will have a mailbox where you catch all the emails. 

What you are doing is using the docker container names like MySQL, and Redis as the IP for each service, inside docker Redis, is changed to the right IP and MySQL as well, this is the power of docker at your disposal. That is why DB_HOST=mysql works because it knows that MySQL in this case maps to the MySQL container and it uses the id generated for it, same with Redis.

If you want to set up an automatic queue service like with supervisor, you can do it using the php-worker, go into the laradock/php-worker/supervisord.d directory, in there you will see an example worker, you can cp laravel-worker.conf.example example.conf then go into example.conf and make siure you configure it to your application and run the queue how you want. 

Then go back to Laradock and run docker-compose build php-worker, then docker-compose restart php-worker, this will recreate the container and add the new configuration to the supervisor instance of php-worker, you can do the same with the laravel echo server, go into laravel-echo-server/laravel-echo-server.json and change it to the configuration you want. 

Before access containers, let’s setup your database, go to laradok/mysql/docker-entrypoint-initdb.d and cp createdb.sql.example createdb.sql Follow the example and create the script to create your database. Something like:

CREATE DATABASE IF NOT EXISTS `example` COLLATE 'utf8mb4_general_ci';
GRANT ALL ON `example`.* TO 'default'@'%';
If you look at the comments it says you can access your MySQL container and then run the SQL script. Go back to Laradock and run docker-compose exec mysql bash ti access the MySQL container and then mysql -u root -p < /docker-entrypoint-initdb.d/createdb.sql to run the script, you should now have your database.
docker-compose exec mysql bash
mysql -u root -p < /docker-entrypoint-initdb.d/createdb.sql
Also, keep in mind you can access any container either via command line using docker-compose exec php-worker sh to change any configuration right into the container, to access your environment or in this case the workspace you can use docker-compose exec workspace bash, this will take you right the server or container and then you can cd /var/www/example to go to your Laravel application where you can run composer install and php artisan migrate. Go back to the browser type example.test and congratulations your application is fully setup.
Andres Felipe Abello
May 27