Symfony is one of the best PHP framework for developers who want to build enterprise grade web application or any web services. Besides Symfony, Docker is one of the most necessary tooling every developers need. Docker containerized your App. So the question is, what can be the best way to run Symfony web application on Docker container?
Since Symfony 5.x got released I tested it for one of our applications that I have developed. You have to remember, any kinds of web application requires few services to make it available to the internet or to your audience.
Essential parts of any web application
As a web developer you should also know this very well. But let me write a list here that will help us to decide later in this article. To run a successful web application, we need –
- A web server (Nginx or Apache)
- A Database (MySQL, PostgreSQL, etc)
- Web application (in PHP, Python, etc)
These 3 are essential in most cases.
So, how to dockerized Symfony web app?
To containerized (a.k.a dockerized) any web application you have to make sure that other services (web server, database) all are inter-connected. In the context of containerization we should also containerized those services as well. So it would be considered as micro services.
Each services will be running on a Docker container and each are independent but connected with each other. So to make it easy we have to use docker-compose where we can define all the configuration sets for each services and with a single command for docker-compose we can run the entire micro service and make it available to whoever we want to.
It’s easy to manage all related components for a web app from a single Docker Compose configuration file instead of making separate containers. It’s efficient, recommended and correct way.
What’s the docker-compose setup look like for Symfony 5.x web app?
This is the main section of the article. Let’s talk straight to the point. Here I am going to share individual Dockerfile for each service first. Let’s have a look –
Nginx web server
This is the dockerfile to run Nginx web server.
# docker/nginx/Dockerfile
FROM nginx:alpine
# Custom nginx configuration for this app
COPY ./docker/nginx/default.conf /etc/nginx/conf.d/default.conf
COPY ./public /var/www/html/public
If you are familiar with Dockerfile writing you will understand. I just added one extra line to copy a custom configuration (default.conf) for nginx for our Symfony app.. Here is the default.conf too.
# docker/nginx/default.conf
server {
listen 80;
server_name _;
index index.html index.php;
root /var/www/html/public;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_index index.php;
fastcgi_pass symfony:9000;
}
location ~ /\. {
log_not_found off;
deny all;
}
}
It’s a custom virtual host configuration for our application as we decided to run our application on Nginx.
MySQL Database
We also need database. For this particular app, we are using MySQL 5.7 without any custom configuration. So we don’t need any custom Dockerfile for that. Very little configuration we need that we can achieve from docker-compose.yml file directly.
Dockerfile is essential for custom configuration. Otherwise you can directly add container name in docker-compose.yml
Symfony 5.x web application Dockerfile
Now here is the Dockerfile for your web application that was built on top of Symfony 5.x PHP framework.
# docker/symfony/Dockerfile
FROM php:7.4-fpm-alpine
# Install DB driver for PHP => pdo pdo_mysql
RUN set -xe \
&& apk add --no-cache --update --virtual .phpize-deps $PHPIZE_DEPS \
&& apk add git \
&& docker-php-ext-install pdo pdo_mysql \
&& rm -rf /usr/share/php \
&& rm -rf /tmp/* \
&& apk del .phpize-deps
# Override php.ini settings
COPY ./docker/symfony/app_custom.ini /usr/local/etc/php/conf.d/app_custom.ini
WORKDIR /var/www/html
COPY . /var/www/html
# To run some additional command during build time (db migrations, loading fixtures, etc)
COPY ./docker/symfony/prepare.sh .
RUN chmod a+x ./prepare.sh
# Install composer
RUN curl --show-error --silent https://getcomposer.org/installer | php \
&& php composer.phar install -v
I am not sharing prepare.sh file. It’s just a regular bash script. Also In the above Dockerfile you will see I am overriding some php.ini values with a custom app_custom.ini file. I think that’s also not necessary to share. You can override by yourself if you want.
docker-compose.yml to run Symfony 5.x web app
This is the original file to run all the service together. All the Dockerfile I shared above that will now get connected into this single file. I created those Dockerfile because I wanted to do some customization by myself to meet my platform requirements for the app.
So here is my docker-compose.yml file that is all you need to run a web app successfully whether your app was built with Symfony or not.
version: '2.2' # Let's build all the services required to run this app (dev version) # We need - # MySQL => Database # Nginx => Web Server # PHP-FPM services: mysql: container_name: mysql image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: symfony MYSQL_DATABASE: symfony # Database will be created on start MYSQL_USER: symfony # Password for MySQL User. MYSQL_PASSWORD: symfony # We need to run healthcheck because we need to make sure that the initial & default # database has been created healthcheck: test: "/usr/bin/mysql --user=root --password=symfony --execute \"SHOW DATABASES;\"" interval: 2s timeout: 20s retries: 10 symfony: container_name: symfony build: context: . dockerfile: ./docker/symfony/Dockerfile command: ./prepare.sh # Reset database, run migration + fixtures volumes: - ./var:/var/www/html/var environment: DATABASE_URL: mysql://symfony:symfony@mysql:3306/symfony?serverVersion=5.7 APP_ENV: dev # For debugging purpose we built it as a dev version links: - mysql # Database must be ready before running this searvice depends_on: mysql: condition: service_healthy # DB service must be in healthy state to start this App nginx: container_name: nginx build: context: . dockerfile: ./docker/nginx/Dockerfile ports: - "8011:80" # Webserver will run on http://localhost:8011 depends_on: - symfony # Web App service must be running - mysql # DB must be ready
This file will be located in the root directory of your Symfony app. There will be another directory called docker where you will place all the above Dockerfile. I the Dockerfile I wrote the path structure too.
Now see in the docker-compose.yml file. I have added 3 services for this entire system to run successfully. mysql, symfony, nginx. If you see the service configuration you will see that I pointed out custom Dockerfiles wherever needed.
Run docker-compose.yml
To run docker-compose.yml you just run the following commands in your command line –
# -d = run in detach mode
# --build = force build
# start the service
$ docker-compose up -d --build
# stop services
# [--volumes to remove all used volumes, --remove-orphans will remove other necessary docker components too]
$ docker-compose down --remove-orphans --volumes
If you have experience to work with Docker you will understand the above file. There are no complex stuff involved in it unless you design any complex architecture to run your micro service that will power up web application.
Note: I used Symfony 5.0.4 version. I didn’t test this with any other old release. But it should work with charm I hope. Write your comments in the below if it worked for your correctly or share any issue if you faced.