Dockerize a Symfony project (Nginx, PHP-FPM, and MariaDB)

This article is part of series that we created to have a common knowledge/rule base among our IT teams

As you might already know containers are a huge help if not a necessity when developing software. They help isolate applications from their underlying infrastructure and help reproduce the same environments regardless of the underlying operating system (also called portability). Docker is a set of platforms as service products that use OS-level virtualization to deliver software in containers.

In this tutorial we are going to show you how to dockerize a Symfony project using Docker, this docker was configured for Symfony version 4.4 but we believe but the steps are the same for other versions, you will just need to alter the dependencies for compatibility.

We put the code on a GitHub repository so feel free to skip the tutorial.

Create a new Symfony project

We will create a new Symfony project to get started but you can apply the same steps to an existing project. So if you have composer installed simply run:

> composer create-project symfony/skeleton:"^4.4" dockerized_sf_project

The project repository should look like this:

Add docker configuration files

Since we will be using multiple Docker containers for our Symfony project we are going to use Docker Compose to define and run them. We first create adocker-compose.yml file in our project directory and we will also create a new docker directory in which we are going to put the Docker files.

Nginx container

Since Symfony is a web application framework we need a web server to run it. We will be using nginx because it is a fast and reliable static web server. Add a Dockerfile-ngnix dockerfile inside thedocker directory with the following content:

FROM nginx:latestCOPY build/nginx/default.conf /etc/nginx/conf.d/RUN echo "upstream php-upstream { server fpm:9000; }" > /etc/nginx/conf.d/upstream.confRUN usermod -u 1000 www-data

What this configuration is doing pulling the latest version from Docker hub, we used the NGINX official image. and then we copy the nginx.conf file from our local container into the image. Then we configure the upstream to php-upsteamand fpm as a reference to the proxy and fastcgi_pass.

The ngx_http_upstream_module module is used to define groups of servers that can be referenced by the proxy_pass, fastcgi_pass, uwsgi_pass, scgi_pass, memcached_pass, and grpc_pass directives.

We also configure the usermod in order to get the permissions straight. This has the benefit that the container won’t run as root.

Now under the docker directory, create two sub-directories called build/nginx. Inside create a file called default.conf and put the following code to set the default configuration for Nginx:

server {listen 80;server_name  localhost;root /var/www/project/public;location / {try_files $uri @rewriteapp;}location @rewriteapp {rewrite ^(.*)$ /index.php/$1 last;}client_max_body_size 200M;location ~ ^/index.php(/|$) {fastcgi_pass php-upstream;fastcgi_split_path_info ^(.+\.php)(/.*)$;include fastcgi_params;fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;fastcgi_param HTTPS off;client_max_body_size 200M;fastcgi_read_timeout 600;}error_log /var/log/nginx/symfony_error.log;access_log /var/log/nginx/symfony_access.log;}

Now we need this container to our docker-compose file under services as follow:

version: "3.7"services:  nginx:    build:      context: ./docker      dockerfile: Dockerfile-nginx    volumes:      - ./:/var/www/project/:cached    ports:     - 10302:80 # Ports that are exposed, you can connect to port 8001 to port 80 of the container.   networks:   - symfony

The 3.7 represented composer version, we also define the Nginx service and link it to its dockerfile we created earlier, we also define volumes and ports.

PHP-FPM container

FPM (FastCGI Process Manager) is an alternative PHP FastCGI implementation with some additional features (mostly) useful for heavy-loaded sites. We will use it to install PHP and add configurations. It works perfectly with Nginx. Inside our docker repository we add the Dockerfile-php dockerfile for PHP and add the following:

FROM php:7.4-fpmRUN apt-get update && apt-get install -y --no-install-recommends \git \zlib1g-dev \libxml2-dev \libpng-dev \libzip-dev \vim curl debconf subversion git apt-transport-https apt-utils \build-essential locales acl mailutils wget nodejs zip unzip \gnupg gnupg1 gnupg2 \sudo \ssh \&& docker-php-ext-install \pdo_mysql \soap \zip \opcache \gd \intlCOPY build/php/opcache.ini /usr/local/etc/php/conf.d/COPY build/php/custom.ini /usr/local/etc/php/conf.d/RUN curl -sS https://getcomposer.org/installer | php && mv composer.phar /usr/local/bin/composerRUN composer self-update 1.9.0RUN wget --no-check-certificate https://phar.phpunit.de/phpunit-6.5.3.phar && \mv phpunit*.phar phpunit.phar && \chmod +x phpunit.phar && \mv phpunit.phar /usr/local/bin/phpunitRUN usermod -u 1000 www-dataRUN usermod -a -G www-data rootRUN mkdir -p /var/wwwRUN chown -R www-data:www-data /var/wwwRUN mkdir -p /var/www/.composerRUN chown -R www-data:www-data /var/www/.composerWORKDIR /var/www/project/

What we do is basically grab the PHP-FPM version 7.4 compatible with PHP 7.1 or higher. And we install other dependencies like pdo_mysql, SSH, zip … here you need to add other dependencies that your project might need.

Note that we also mentioned other two configuration files build/php/opcache.ini for cache configuration and build/php/custom.ini for more custom PHP configuration that you can alter depending on your project specifications. These two files and configuration are optional so feel free to skip this part.

So add these two files under docker/build/php directory and inside your build/php/opcache.ini add:

opcache.enable=1opcache.enable_cli=0opcache.memory_consumption=256opcache.max_accelerated_files=100000

While in your build/php/custom.ini file add:

date.timezone = "Europe/Paris"memory_limit = 4096Mupload_max_filesize = 200Mpost_max_size = 200M

Just like we did with Nginx we also need to add this container to our docker-compose file under services as follow:

fpm:    build: # Info to build the Docker image      context: ./docker # Specify where the Dockerfile is located (e.g. in the root directory of the project)      dockerfile: Dockerfile-php # Specify the name of the Dockerfile    environment: # You can use this section to set environment variables. But you can also use the .env file.      - DATABASE_URL=mysql://root:root@db/docker_sf    volumes:      - ./:/var/www/project/:cached # Location of the project for php-fpm. Note this should be the same for NGINX.*    networks:      - symfony # Docker containers (services) that need to connect to each other should be on the same network.

We linked the fpm service to its dockerfile and we set database, volumes …

MariaDB configuration

The database configuration is straight forward, in your docker-compose file under services add the following:

db: #address    image: mariadb:10.2.29    ports:      - "3317:3306" #outside:inside docker container from-within    environment:      - MYSQL_DATABASE=docker_sf      - MYSQL_ROOT_PASSWORD=root    volumes:      - persistent:/var/lib/mysql      - ./docker/build/db/:/docker-entrypoint-initdb.d/    networks:     - symfony

Here we set the database configuration, if you have an existing database just compress it and put it under your docker/build/db directory and this service will automatically compile the SQL script and create the database for you inside your container. In this example, we added a database script docker_sf.sql.gz. Otherwise, the image can be run with no need for an initial database.

By now your project directory should look like this:

Run project

To build the containers, simply run:

docker-compose build

Once done you can run your service with:

docker-compose up -d

And finally to enter your container run:

docker-compose exec -u 1000 fpm bash

Your project will start at http://localhost:10302/

And you can access your local database from port 3317 with username root and password root. If you initiated a database SQL file you should be able to see it, like in our case with the docker_sf.sql.gz file that we added we have our database created with tables in the script.

Find the full code here:

Enjoy 🖖.

References:

Software Engineer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store