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-upsteam
and 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: ./dockerdockerfile: Dockerfile-nginxvolumes:- ./:/var/www/project/:cachedports:- 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 imagecontext: ./docker # Specify where the Dockerfile is located (e.g. in the root directory of the project)dockerfile: Dockerfile-php # Specify the name of the Dockerfileenvironment: # You can use this section to set environment variables. But you can also use the .env file.- DATABASE_URL=mysql://root:root@db/docker_sfvolumes:- ./:/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: #addressimage: mariadb:10.2.29ports:- "3317:3306" #outside:inside docker container from-withinenvironment:- MYSQL_DATABASE=docker_sf- MYSQL_ROOT_PASSWORD=rootvolumes:- 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 🖖.