Cómo desplegar una aplicación Symfony 4 en tu servidor
5 (100%) 13 voto[s]

En otros artículos hemos hablado de los motivos por los que utilizar Symfony como nuestra herramienta de desarrollo, buenas prácticas o cómo crear nuestro primer proyecto con Symfony 4.

Una vez nos hemos decidido a desarrollar nuestra aplicación con Symfony y la tenemos lista para desplegar en producción debemos tener en cuenta una serie de cosas tanto cuando se trata de un primer despliegue como cuando se trata de una actualización.

¿Qué opciones tenemos para desplegar los cambios en una aplicación?

Actualmente hay 2 alternativas principales, por un lado podemos ver la aplicación como un conjunto de ficheros de código, configuración, base de datos, dependencias y demás artefactos. En ese caso necesitaremos tener una estrategia clara para que los nuevos cambios en el conjunto de nuestra aplicación que se suele describir mediante build scripts.

docker

Otra aproximación que se está extendiendo rápidamente son las aplicaciones empaquetadas en contenedores.

Actualmente es docker la herramienta que se ha posicionado como estándar de facto y que nos permite, en lugar de utilizar scripts que manejan los cambios en la aplicación, empaquetar la aplicación en una imagen que contiene todas las dependencias y aísla la ejecución de otras aplicaciones que se estén ejecutando en el servidor.

La ventaja es que para cada versión de nuestro software podemos construir la imagen necesaria en nuestro servidor de CI/CD y publicarla en el registro correspondiente para que la actualización sea tan sencilla como levantar otro contenedor que sirva la aplicación en base a la imagen nueva y detener la ejecución del contenedor con la versión antigua.

Normalmente durante el desarrollo se debe tener en cuenta si el objetivo será usar docker ya que puede condicionar algunas decisiones que tomemos para facilitar después el uso de contenedores. Por ejemplo cuando usamos contenedores las aplicaciones deben ser stateless (no deben mantener estado, es decir, debe poder destruirse el contenedor de un nodo del clúster y levantarse otro usando la misma imagen sin que el servicio se vea afectado).

¿Qué vamos tratar nosotros en este artículo?

Vamos a seguir la aproximación clásica, tenemos un servidor en el que reside la aplicación, con un estado actual y queremos poder desplegar nuestras nuevas versiones de la manera más sencilla y automatizada posible.

Para ello, como ya hemos anticipado, no vamos a entrar en las posibilidades del mundo de los contenedores porque se trata de un tema algo más avanzando, tampoco en los zero downtime deployments en los que el servicio no se interrumpe.

Lo que sí pretendemos es sentar las bases de qué cambios son los más comunes que sufre una aplicación cuando está en desarrollo o mantenimiento y necesita ser actualizada para que a partir de ahí cada equipo profundice en las técnicas avanzadas relacionadas con sus necesidades.

¿Qué piezas componen una aplicación cuando afrontamos su despliegue?

Código de la aplicación

Es el código que nosotros escribimos y por tanto del que nos responsabilizamos, en nuestro caso se trata fundamentalmente del contenido de las carpetas assets, config, src y templates.

Cuando queremos desplegar una nueva funcionalidad por lo general tendremos nuevo código o modificaciones en el código de nuestra aplicación y transmitir estos cambios desde nuestro entorno de trabajo al servidor de producción puede ser tan sencillo como subir mediante FTP los ficheros correspondientes. Esto es un proceso manual y como todo proceso manual es propenso a errores, es por ello que si ponemos en una balanza simplicidad, comodidad y calidad del proceso (que sea repetible, fiable, la posibilidad de rollback) una opción sólida que equilibra las cualidades que queremos maximizar es el uso de git.

Ya deberíamos estar utilizando git como pieza central en nuestro flujo de desarrollo y como sistema de control de versiones distribuido nos va a permitir tener otro repositorio en producción que utilizaremos únicamente para desplegar cambios.

Esto puede hacerse de manera más o menos automatizada según queramos complicar el proceso. Si usamos un servicio de CI/CD podemos automatizar el envío a nuestro servidor de producción de los cambios, pero si no queremos dar el paso podemos trabajar con 2 remotes en nuestro proyecto, uno para nuestro repositorio central (github, gitlab, etc) y otro para el servidor de producción..

Para cambiar la versión del código de producción lo único que tendremos que hacer es pushear los nuevos commits al remote que tengamos configurado.

Configuración

Los parámetros que configuramos en una aplicación Symfony deberían encontrarse en los ficheros .env*, es cierto que al desplegar los cambios en el código habremos actualizado nuestro fichero .env pero tendremos que realizar manualmente cualquier cambio en .env.local.

A pesar de ser un paso manual en entornos en los que queremos tener un flujo sencillo no debería ser un problema ya que es una de las zonas de la aplicación que menos cambia. Además por la propia naturaleza de la información almacenada muchas veces no podemos incluirla en nuestros repositorios por lo que las opciones disponibles no son muchas, prácticamente nos quedan los gestores de secretos como vault o la configuración manual.

Si a esto le sumamos un esfuerzo por nuestra parte en tener valores por defecto sensatos nos encontraremos muchas veces sin la necesidad de sobrescribir el valor por defecto de .env y por tanto no tendremos que realizar ninguna acción manual. En otras ocasiones tendremos que configurar los valores de manera obligatoria, por ejemplo cuando tenemos que añadir un token de autenticación de un sistema de terceros.

Bases de datos

En una aplicación basada en Symfony es muy común que cuando estemos trabajando en nuevas funcionalidades nos encontremos trabajando con nuevas entidades o cambios en las ya existentes. Para ese caso de uso hay una opción muy potente, se trata del paquete doctrine/doctrine-migrations-bundle.

Una vez empecemos a utilizar migraciones nuestro flujo de trabajo durante el desarrollo contará con un paso más, cada vez que modificamos la persistencia de las entidades generaremos una migración. Esto se traducirá en un nuevo fichero php con la habilidad de ejecutar el SQL necesario para hacer el cambio en la entidad y el SQL necesario para deshacer el cambio.

Por tanto tendremos en nuestro sistema de control de versiones un sistema de control de versiones de la estructura de la base de datos. Podemos dejar que sea el paquete quien se encargue de generar el SQL necesario pero también podemos modificarlo para reflejar otro tipo de cambios o generar migraciones vacías en las que seremos nosotros quien defina el cuerpo de los métodos up y down.

Cuando esas nuevas migraciones se encuentren en el servidor de producción tendremos que ejecutarlas para que realice los cambios necesarios a en la base de datos.

piezas-aplicacion

Dependencias

Si estamos usando Symfony y Webpack Encore contaremos con 2 gestores de paquetes, por un lado Composer para las dependencias php y por otro Yarn para las correspondientes al front.

Cada vez que realicemos cambios en los ficheros que describen las dependencias que maneja Composer tendremos que ejecutar en nuestro servidor composer install –no-dev –optimize-autoloader para que la herramienta descargue las versiones correctas de nuestras dependencias y las instale teniendo en cuenta las optimizaciones que se pueden llevar a cabo en producción.

De igual manera, cada vez que realicemos cambios en los ficheros correspondientes a Yarn tendremos que ejecutar yarn install en nuestro servidor.

Artefactos

En el caso que planteamos, y siguiendo la misma filosofía que con las dependencias, si hay cualquier cambio en nuestros assets éste debería reflejarse en los artefactos construidos con Webpack.

Para ello tenemos 2 opciones, construir esos artefactos en otra máquina y enviarlos al servidor de producción o construirlos en el propio servidor de producción. La decisión aquí implica cambios en cómo instalamos nuestras dependencias con Yarn en el servidor de producción, si queremos utilizar Webpack en el servidor de manera que lancemos yarn encore production en producción para generar nuestros artefactos no podremos utilizar el flag –production con valor true, de lo contrario no tendremos instalados los paquetes necesarios

Caché

Por último cuando tenemos una aplicación Symfony configurada para ejecutarse en modo producción tanto el framework como algunos paquetes almacenan información en caché, cuando hacemos cambios es posible que tengamos que purgar la caché de Symfony para que realmente se ejecute nuestro nuevo código.

Desde cambios en las entidades a los cambios en las plantillas que se almacenan en caché precompiladas pasando por las traducciones forman parte de la lista de elementos que hacen uso intensivo de la caché del proyecto. Para esto solo tendremos que ejecutar php bin/console cache:clear en el entorno de producción, la caché quedará purgada y a partir de ese momento empezará a cachearse información en base a nuestro nuevo código.

Conclusión

Como hemos visto el proceso de manera global puede ser todo lo sencillo o todo lo complejo que queramos optando por diferentes técnicas y herramientas. Además cada paso del proceso de manera individual puede a su vez automatizarse en mayor o menor medida dependiendo del tipo de herramientas que usemos.

Con el planteamiento que realizamos debería ser suficiente escribir un script para que todas las partes automatizables se realicen de manera autónoma, a partir de ahí podemos saltar hacia el uso de herramientas especializadas como deployer, a servidores de CI/CD que orquesten el proceso y a flujos de trabajo basados en contenedores que es la dirección que está tomando la industria.

Dependiendo del tamaño de nuestros proyectos y de la cantidad de recursos que tengan asignados tendremos que tomar las decisiones que consideremos, nuestro consejo es que analicéis siempre en qué estado se encuentra vuestro proyecto en cuanto a proceso y defináis cuales son los puntos críticos para automatizarlos e ir avanzando.

He leído y estoy conforme con la Política de Privacidad.