Dockerizar tu aplicación Symfony

Una vez que empiezas con Docker ya quieres dockerizarlo todo 🙂 Como llevo un tiempo trabajando con Symfony para diferentes escenarios, en este artículo quería compartirte la configuración que estoy utilizando para generar mis contenedores, para un entorno de desarrollo.

docker-compose.yml

 version:  '3.7'
 services:
    nginx:
      image: nginx:1.15.3-alpine
      restart: on-failure
      volumes:
        - './public/:/usr/src/app'
        - './docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro'
      ports:
        - "8000:80"
      depends_on:
        - php
    php:
      build:
        context: .
        dockerfile: Dockerfile
      restart: on-failure
      environment:
        XDEBUG_CONFIG: remote_host=host.docker.internal remote_port=9000 remote_enable=1
      volumes:
        - '.:/usr/src/app'      

Como puedes ver, uso Nginx como servidor web, con el que estoy compartiendo un archivo de configuración solo de lectura, con la ruta donde está el código de mi aplicación, /usr/src/app.

# ./docker/nginx/default.conf
server {
 server_name ~.*;

 location / {
     root /usr/src/app;

     try_files $uri /index.php$is_args$args;
 }

 location ~ ^/index\.php(/|$) {
     client_max_body_size 50m;

     fastcgi_pass php:9000;
     fastcgi_buffers 16 16k;
     fastcgi_buffer_size 32k;
     include fastcgi_params;
     fastcgi_param SCRIPT_FILENAME /usr/src/app/public/index.php;
 }

 error_log /dev/stderr debug;
 access_log /dev/stdout;
}

Acto seguido, mapeo el directorio public de mi código fuente con /usr/src/app. Además, estoy exponiendo hacia afuera el puerto 8000, que está mapeado con el puerto 80 de Nginx. Por último, a través de depends_on, digo que este contenedor depende del llamado php, que es el que está interpretando mi código a través de php-fmp. En este otro contenedor mapeo el directorio donde está mi código fuente en el host, para que pueda hacer cambios en mi código y que estos se vean reflejados. Por último, en lugar de utilizar una imagen de Docker Hub, o cualquier otro registro, tiene asociado un archivo Dockerfile que será la receta de la imagen que utilizará este contenedor.

El archivo Dockerfile de php

# ./docker/php/Dockerfile
FROM php:7.2-fpm-alpine

RUN apk update \
    && apk add  --no-cache \
    git \ 
    curl \ 
    icu-dev \
    libxml2-dev \ 
    g++ \ 
    make \
    autoconf \
    && docker-php-source extract \
    && pecl install xdebug \
    && docker-php-ext-enable xdebug \ 
    && docker-php-source delete \
    && docker-php-ext-install pdo_mysql soap intl zip \
    && echo "zend_extension=$(find /usr/local/lib/php/extensions/ -name xdebug.so)" > /usr/local/etc/php/conf.d/xdebug.ini \
    && curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
    && rm -rf /tmp/*


WORKDIR /usr/src/app

COPY . /usr/src/app

RUN composer install

La imagen que queremos crear para el contenedor php básicamente utiliza la imagen de php-fpm sobre la distribución Alpine, la cual es la distribución Linux más ligera, y es realmente buena para trabajar con Docker. Actualizamos el repositorio e instalamos todos los paquetes que nos hacen falta para ejecutar nuestro código PHP, además de poder depurarlo. También instalamos composer para poder ejecutarlo e instalar los paquetes PHP.

Archivo .dockerignore

Todavía no sé todos los trucos para optimizar el tamaño de las imágenes en Docker. Sin embargo, he utilizado .dockerignore para omitir algunas carpetas y aligerar la carga.

var/
vendor/
docker/
Dockerfile

Depurar tu contenedor con Symfony

Ya tienes todo listo para desarrollar y ejecutar tu aplicación con Symfony. Si además necesitas depurarla, puedes hacerlo de forma sencilla con Visual Studio Code. Hace un tiempo, escribí los pasos en este artículo para depur código PHPar. En el caso de los contenedores, necesitas que el archivo launch.json tenga esta configuración:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Listen for XDebug",
            "type": "php",
            "request": "launch",
            "port": 9000,
            "pathMappings": {
                "/usr/src/app": "${workspaceFolder}"
            },
            "xdebugSettings": {
                "max_data": 65535,
                "show_hidden": 1,
                "max_children": 100,
                "max_depth": 5
            }
        }
    ]
}

Imagen de portada por ayhan barış.

¡Saludos!