Codementor Events

Docker for PHP Developers

Published May 30, 2018Last updated Nov 26, 2018
Docker for PHP Developers

I don’t want to start like other articles giving a “brief introduction” about Docker or PHP, that is boring as hell, it’s supposed that if you are looking a tutorial like this one, is because you already passed by this “brief introduction” of 100 hours, so, if you don’t know what this article is about, please, look for some information before diving into it. I am not a DevOps engineer nor a rocket scientist, just a backend engineer with a couple of hours “invested” in joining a lot of information from different resources to deploy a PHP Application with docker, and of course, docker compose, please, I will not explain Dockerfile workflow here, so, if you are looking for such thing, sad day for you. Well, no more words, I’ll start, feel free to leave a comment if something doesn’t work, and I’ll try to help you, but you must know that everything posted here is already tested and is my personal minimum configuration file for running PHP and related frameworks, of course, I’ll stick with PHP only, for each frameworks you will need some extra configurations for improve their speed and performance.

Docker configuration.

Once you got installed and configured your environment, you can start by entering your project folder or creating a new one and placing the classic docker-compose.yml inside, below you will find the whole content of this file, and then I’ll start explaining step by step:

This is my project structure:

There you go, that’s it, simple and beautiful as that, and for the ones who likes the customisation of their work environment (like me), that is Sublime Text 3 with Material Theme and Material Icons, and the font family is Ayuthaya (I use Fira Code because of the fonts ligatures, but the guys of sublime haven’t decided to add this yet).

First of all, you have a code folder where you will place, well, your code, this organisation is flexible, you can put your files however you want, but I want to keep things dry and simples, so I put them in that way.

For getting up and running a php application, in a web server, you normally need to have in your server Apache or Nginx as web server, PHP for allow the web server to interpret the source code of your application, and, the database engine of your preference, I use MySQL, but you can also use PostgreSQL as well, of course, that is for a monolith environment, so past century!, now in every sentence of a developer/system engineer are the words “Microservices”, “Scalable” and all those stuffs you can check on Wikipedia for further information, well, after this article, you will be able to say that you are in XXI century, year 2017. Docker is the same thing as a monolith environment, you have all the programs you need to put your system to work, but that is the thing, you only have the programs you need, and with a deployment time of 5 seconds or less (depending on your internet connection, for me, a few months ago, deploy in docker used to take ages 😄, but that is another story), well, as I mentioned before, we are going to need Nginx, PHP and MySQL images.

Putting the puzzle together

If you are still reading, here is where the important thing happens, I’m going to explain every single line of the snippet pasted before and make reference of the nginx configuration file.

First of all, you are going to need PHP, for that you can use php:fpm image, and of course, you need to let the php container generated by docker-compose knows where your code is in order to get a nice response in the browser.

php:
    image: php:fpm
    volumes:
      - ./code:/code

And simple as that we have the php service already configured, note that with the volumes node we share folders between the container and the host computer.

For the MySQL image is almost the same thing:

db:
    image: mysql
    environment:
      - MYSQL_ROOT_PASSWORD=TheMegaPassword
      - MYSQL_DATABASE=the_db
    volumes:
      - ./db_data:/var/lib/mysql

Note that here service definitions goes bigger, we have to define environment variables for the container, we have even more, but these two MYSQL_ROOT_PASSWORD and MYSQL_DATABASE are the minimum configuration, the first one is going to contain the root password for access to MySQL, and the second one is the database that is going to be created by default once the container goes up, and the shared volume defined in this service is for avoiding lose your data if you need to get your container down, if you don’t care about the data, then you can remove that shared volume, but it is highly recommended for production environments.

And finally, the Nginx configuration, or as I like to call it, the web service, this one is slightly bigger, but nothing different:

web:
    image: nginx
    ports:
      - "8080:80"
    volumes:
      - ./code:/code
      - ./nginx/app.conf:/etc/nginx/conf.d/app.conf
      - ./server_logs:/var/log/nginx
    environment:
      - DB_HOST=db
      - DB_PORT=3306
      - DB_DATABASE=the_db
      - DB_USERNAME=root
      - DB_PASSWORD=TheMegaPassword

First of all, we see a node there called ports , that is the port where I’m going to expose which port, to explain a little bit better, on the left goes the local port, and on the right goes the container port, in my case I put 8080 as the local port, but you can also put 80, is fine, nothing nuclear is going to happen for change such thing, now, the volumes is the tricky thing here. The first volume of course is where your application’s source code is located, no doubt with that, the second volume is not a volume, but a shared file instead, we are locating the local app.conf file inside /etc/nginx/conf.d/ , this is the place where the configuration files for nginx virtual hosts are located, yes, I know, is different than our old monolith environment where we had to put a file into a sites_available and then make a symbolic link to sites_enabled , I think the Docker way is better, less commands, less human errors, and lastly but no less important, logs, yes, those ugly files that you need when you want to know access or errors, we are making a folder to sync it with the container folder that holds the logs, as we learned in Docker 101 for dummies, the shared volumes are bidirectionally synced, so, whenever the container writes something to a shared volume, this is going to be persisted in the local computer as well.

That’s it, almost done, you only need the Nginx configuration file and you are ready to put your PHP application to run, here goes another huge snippet:

I think this is pretty understandable for you that already knows how to configure a monolith environment, but anyways, let’s check the php-fpm integration section of the file:

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;
    }

Note the highlighted line in the section fastcgi_pass php:9000 interesting something here, for indicate the php-fpm server, you can write the name of the server instead of the ip address, great, isn’t it?, docker-compose container has the ability of resolve containers ip address by their name server, and where did you indicated the nameserver?, well, the nameserver is the name of the service itself, for php-fpm is php and for mysql is db , of course, this is also customisable.

Well guys, you are done, pretty straightforward, wasn’t it?, now, the final result we were waiting for:

I almost forgot, for running our scaffold, you have to enter the root folder of the docker-compose file and execute docker-compose up -d , if you reach to see something like this:

Then you are good to go, I didn’t present any example connecting PHP with the database, but the principle is the same, just indicate the host as db or however you named your service and that’s it.

Ok, thanks a lot for reading such tutorial, I think is going to help someone because of my own experience, I didn’t reach to find any tutorial as complete as this one how to deploy a PHP application using docker. If you need to deploy something else in docker, and don’t find anything suitable, let me know by the comments and I’ll publish something (I have work, so please understand if I take my time). Cheers.

Discover and read more posts from Cesar Bretana Gonzalez
get started