Cómo integrar Docker en un proyecto basado en Symfony
Descripción de los pasos a seguir para dockerizar un proyecto de Symfony que use Nginx, PHP-FPM y MySQL
Si habéis trabajo con proyectos con un cierto nivel de complejidad es probable que hayáis oído hablar de Docker. En pocas palabras, esta herramienta nos permite estandarizar el software usado en cada proyecto de modo que funcione igual independientemente de la máquina que lo albergue.
Es decir, lo que Docker nos proporciona es una capa de abstracción sobre el software empleado por medio del concepto de “contenedor” lo cual simplifica la creación, despliegue y ejecución de nuestras aplicaciones. Gracias a estos containers podremos olvidarnos de uno de los problemas más recurrentes de la programación:
“En mi local funciona”
Ya que en ellos quedan empaquetadas las dependencias de nuestra aplicación evitándonos tener que instalarlas manualmente cada vez que cambiemos de máquina.
Lo que haremos en este artículo será aprender a integrar Docker dentro de un proyecto de Symfony, de modo que podamos ejecutarlo en cualquier ordenador o servidor. Para ello bastará con tener Docker instalado en donde queramos ejecutar el proyecto, algo que podéis hacer desde el siguiente enlace:
Hecho esto, vamos a por la parte interesante!
Estructura de carpetas
Antes de comenzar, lo primero que haremos será plantear la estructura de carpetas con la que contará nuestro proyecto. Puesto que vamos a emplear Docker, nuestro proyecto contará con la estructura siguiente:
📦symfony-docker
┣ 📂build
┣ 📂mysql
┣ 📂symfony
┗ 📜docker-compose.yml
- En la carpeta build se encontrarán los archivos que emplearemos para configurar cada uno de los containers de Docker de nuestra aplicación.
- En la carpeta mysql se almacenará la base de datos de nuestro proyecto.
- Dentro de la carpeta symfony residirá la aplicación que escribiremos empleando nuestro framework de PHP favorito.
- Finalmente, el archivo
docker-compose.yml
será donde configuremos los 3 containers con los que contará nuestra aplicación: el de Nginx, el de PHP y el de MySQL.
Para aquellos a los que no os suene Docker Compose, esta utilidad nos permite definir en un archivo todos los containers de los que se compone nuestra aplicación y correrlos posteriormente. Esta configuración se realiza dentro de un archivo Yaml
situado en la raíz del proyecto (nuestro ya mencionado docker-compose.yml
). Si queréis leer más sobre esta herramienta os sugiero que acudáis a la documentación oficial ya que allí se explica perfectamente:
Configurando el container para Nginx
Lo primero que haremos será configurar el primer container dentro del cual se encontrará un servidor basado en Nginx.
Para ello, abriremos nuestro archivo docker-compose.yml
y añadiremos lo siguiente:

A partir de la línea 4 es donde definiremos el container de Nginx:
dockerfile
indica el archivo de configuración que se empleará para construir el contenedor y que crearemos a continuación.volumes
establecerá que nuestra carpeta local llamadasymfony
estará enlazada a la carpeta/var/www/symfony
del container.ports
realiza el mapeo entre el puerto 80 del container y el puerto 8001 que emplearemos para acceder a través del navegador.- Y finalmente
networks
establece una red para todo el proyecto de modo que todos lo containers puedan comunicarse entre ellos.
A continuación, crearemos el archivo Dockerfile-nginx
también en la raíz de nuestro proyecto con el siguiente contenido:

En la línea 1 definiremos mediante la directiva FROM
la imagen de Nginx que queremos emplear.
En la línea 2 emplearemos el método COPY
para copiar el contenido del archivo default.conf
de nuestro proyecto (donde se encuentra la configuración del servidor por defecto que empleará Nginx) dentro de la carpeta /etc/nginx/conf.d
del contenedor.
Este archivo default.conf
se situará en la carpeta /build/nginx
y tendrá el siguiente aspecto:

Como podéis ver, en la línea 3 tenemos la configuración del root
que apunta a la carpeta public
de nuestro proyecto
Nota. Recordad que en un proyecto de Symfony el servidor debe apuntar no a la raíz del proyecto sino a la carpeta public
del mismo.
Con todo esto, podemos probar ya nuestro primer container ejecutando el siguiente comando desde la raíz del proyecto:
docker-compose up -d --build
lo cual construirá o levantará el único contenedor que tenemos.
Configurando el container para PHP
El siguiente paso será crear el container donde se ejecutará el servicio PHP FPM para lo cual añadiremos lo siguiente a nuestro archivo docker-compose.yml
:

Como veis, la configuración es similar a la que empleamos para Nginx salvo por los siguientes detalles:
- Dentro de
environment
podremos declarar las variables de entorno que queremos que posteriormente nuestro proyecto de Symfony lea y cargue. - Las
networks
se componen también de un único elemento:symfony
lo que permite que este contenedor y el de Nginx puedan comunicarse. - Finalmente
volumes
tiene el mismo valor que el contenedor de Nginx, de modo que se enlace la carpetasymfony
de nuestro proyecto con la carpeta/var/www/symfony
del container.
En cuanto al archivo Dockerfile-php
tendrá el siguiente aspecto:

Por medio del comando docker-php-ext-install
podemos requerir todas las extensiones de PHP que necesitemos. En nuestro caso tan sólo estoy empleando zip
, intl
y las asociadas a MySQL. El listado completo podéis verlo aquí:
https://gist.github.com/giansalex/2776a4206666d940d014792ab4700d80
Nuevamente podéis comprobar que todo ha ido correctamente mediante el siguiente comando:
docker-compose up -d --build
Ahora ya veremos cómo se levantan dos contenedores, el de Nginx y el nuevo de PHP.
Configurando el container para MySQL
Finalmente, el container para MySQL podremos configurarlo añadiendo lo siguiente a nuestro archivo docker-compose.yml
:

En este caso no necesitamos un dockerfile puesto que toda la configuración que necesita nuestro contenedor para MySQL podemos especificarla dentro del archivo YAML. Sin embargo sí que hay unos cuantos detalles interesantes que comentar.
Plugin de autenticación
En la línea 29 he añadido la configuración que permite establecer qué plugin de autenticación se empleará al conectarnos con MySQL. Esto se debe a que hasta PHP 7.4 no hay compatibilidad con el plugin que usa MySQL para autenticar usuarios, lo cual provoca el siguiente fallo:
PDO::__construct(): The server requested authentication method unknown to the client [caching_sha2_password]
Referencia: https://github.com/laradock/laradock/issues/1390
Usuarios de la base de datos
Por otra parte, en la línea 31 establezco la contraseña del usuario root
de modo que luego podamos emplearla para autenticarnos desde Doctrine. En el caso de que quisiéramos generar una base de datos en el momento de crear el contenedor junto con un usuario con todos los privilegios sobre ella podemos optar por la siguiente configuración:

Dependencias entre contenedores
Finalmente en la línea 25 he añadido al contenedor de PHP la dependencia con el contenedor de MySQL de modo que se levanten en orden.
Lanzar los 3 contenedores
Una vez que hemos terminado de configurar el contenedor de MySQL, ya tendremos todo listo, por lo que ejecutaremos el comando para construir y levantar los 3 contenedores
docker-compose up -d --build
Y, si todo ha ido bien, deberíais obtener una salida similar a la siguiente:
symfony-docker_nginx_1 is up-to-datesymfony-docker_php_1 is up-to-dateCreating symfony-docker_mysql_1 ... done
Instalando Symfony
Puesto que a partir de ahora trabajaremos con nuestros contenedores, la instalación de Symfony la realizaremos dentro de ellos y no desde nuestro sistema operativo.
Por tanto, lo primero que tendremos que hacer es acceder a nuestro contenedor donde se encuentra PHP (acordaos de haberlo levantado) mediante el comando:
docker exec -it symfony-docker_php_1 bash
Donde symfony-docker_php_1
es el nombre que os haya devuelto el comando docker-compose up
tras haber terminado de lanzar los contenedores.
Ahora ya dentro del container podremos instalar Symfony tal y como sugiere la documentación:
curl -sS https://get.symfony.com/cli/installer | bashmv /root/.symfony/bin/symfony /usr/local/bin/symfonysymfony new symfony --dir=/var/www/symfony
Nota. Puede que la creación del proyecto os de el siguiente fallo:
*** Please tell me who you are.Rungit config --global user.email "you@example.com"git config --global user.name "Your Name"to set your account's default identity.
Con realizar la configuración de Git que solicita se resolverá sin mayor complicación.
Tras instalar Symfony podremos comprobar que todo ha funcionado correctamente accediendo a localhost:8001 (el puerto es el que mapeamos en Nginx dentro del archivo docker-compose.yml
) lo cual nos mostrará la página de bienvenida de Symfony:

Si ahora quisiéramos emplear Doctrine para trabajar con una base de datos, bastaría con instalar su bundle correspondiente mediante composer/flex del modo habitual (siempre desde dentro de nuestro contenedor):
composer require symfony/orm-pack
composer require --dev symfony/maker-bundle
Y añadir la variable de entorno DATABASE_URL
dentro de la configuración del contenedor de PHP:
DATABASE_URL: mysql://symfony_user:symfony_password@mysql:3306/symfony_db?serverVersion=5.7
Si os dais cuenta, el host de la base de datos es el nombre de nuestro contenedor ( mysql:3306
) y no la IP 127.0.0.1
. Es decir, si por ejemplo nuestro contenedor lo nombramos como database
dentro de nuestro archivo docker-compose.yml
, la variable de entorno para conectar a esa base de datos tendría el valor:
DATABASE_URL: mysql://symfony_user:symfony_password@database:3306/symfony_db?serverVersion=5.7
Hecho esto, reiniciaremos el contenedor para recoger este cambio en las variables de entorno de PHP:
docker-compose up -d php
Y ya podremos trabajar con nuestra base de datos normalmente. Por ejemplo, dentro de nuestro contenedor de PHP podremos lanzar el comando:
bin/console doctrine:database:create
si queremos comprobar que el proyecto se conecta de forma correcta a la base de datos que hayamos definido
Repositorio
Si queréis acceder al código completo de este artículo podéis hacerlo desde aquí:
Conclusiones
Tras haber dockerizado el proyecto ya podremos trabajar con él en cualquier máquina sin preocuparnos por las dependencias de librerías o el sistema operativo empleado.
Esto para proyectos de tamaño medio / grande donde además se involucran varios desarrolladores resulta muy útil ya que todos ellos trabajarán sobre las mismas versiones lo cual evitará que tengamos fallos por emplear distintas versiones en las librerías que requiramos.
Además, bastará con instalar Docker en la máquina donde queramos trabajar para poder seguir desarrollando el proyecto sin obligarnos a ir instalando una por una las librerías necesarias.
¿Quieres recibir más artículos como este?
Si te ha gustado este artículo te animo a que te suscribas a la newsletter que envío cada domingo con publicaciones similares a esta y más contenido recomendado: 👇👇👇