Buenas prácticas

Buenas prácticas (I): Despliegue con artefactos

La única forma de garantizar que lo que probamos en una máquina es lo mismo que subimos luego a Producción, es desplegando Artefactos. En este artículo explicamos qué son y cómo funcionan.

Photo by Kai Pilger / Unsplash

Antes de entrar en harina, este artículo es parte de una serie sobre buenas prácticas. Queremos explicar algunas de estas buenas prácticas de forma que las pueda entender todo el mundo, porque la literatura que hay al respecto suele ser muy técnica y farragosa.

De qué va el artículo, intro rápida

Despliegue y artefactos son dos palabras un poco rebuscadas, así que voy a explicar exactamente de qué vamos a hablar. Cada vez que, en nuestro proyecto, programa, etc, tenemos código nuevo que queremos entregar, ya sea a un cliente o a nosotros mismos, vamos a hablar de desplegar ese código, de hacer un despliegue (sirve tanto si estás entregando el código que controla el cohete que nos va a llevar a Marte, como si has cambiado un estilo en una plantilla de Wordpress).

Vale, y artefactos, ¿no había una palabra peor? El artefacto es lo que vamos a entregar, a desplegar. Vamos a empaquetar todo lo que compone nuestro código/programa/web en un solo objeto o artefacto y es lo que vamos a entregar. Por qué vamos a hacer esto y cómo vamos a hacerlo, es lo que voy a explicar a continuación...

En mi local funciona...

Es una frase muy escuchada, en el mundo del desarrollo, cuando algo falla y, probando en local, en la máquina del programador/a, funciona. Esto pasa por dos razones, fundamentalmente, o el código no es exactamente el mismo, o la máquina no es exactamente la misma. El despliegue de artefactos resuelve siempre el primer caso y, en ocasiones, el segundo también.

Por ponerlo en otro contexto, es como si has visto por ahí una receta maravillosa para hacer pan, por ejemplo, y lo pruebas y lo que sale es un esperpento. O no has seguido la receta al pie de la letra, con los mismos ingredientes, (en el símil, el código), o el horno (temperatura, etc) no era exactamente igual.

No entiendo esto de que el código no es el mismo...

Lo difícil, realmente, es hacer que lo sea. Imagina una web, en un servidor X, antes (y todavía en muchos casos), la gente para hacer un cambio en esa web, copiaría los ficheros a local, cambiaría lo que fuera y los volvería a subir cambiados.

Lo difícil trabajando de este modo, y más cuando hay varias personas cambiando código a la vez, es garantizar que lo que hemos probado en local es lo mismo que se ha subido a Producción. Hay muchas cosas que pueden pasar entre lo que has probado a las 10am y lo que subes a las 11am, la clave es que no hay una forma científica, replicable, de asegurar que las dos cosas son iguales (o no se te ha olvidado subir una parte).

Empaquetar

Digamos que, para garantizar que lo que probamos en un sitio A y lo que subimos a un sitio B es exactamente lo mismo, la única forma es que realmente sea lo mismo. Es decir, que nosotros creamos un paquete, objeto, artefacto, que incluye todo lo necesario para que nuestro programa, web, funcione y es eso lo que vamos a desplegar. De primeras podría valer con un zip, tar.gz o fichero comprimido con todo lo que tenemos, luego iremos viendo qué otras cosas vamos a necesitar.

Si trabajamos (que es lo suyo), con control de versiones, lo mejor es crear el artefacto a partir del repositorio de código. Esto hay tantas maneras de hacerlo que darían para otro post, pero una opción es vincular la creación de artefactos a tags en el repositorio. Esto se puede hacer tanto en Cloud Build, por ejemplo, https://cloud.google.com/cloud-build/docs/running-builds/automate-builds como en Jenkins: https://comquent.de/de/de-triggering-jenkins-when-new-tags-are-created/

Si no trabajamos con Jenkins ni nada similar, hasta ahora arrastrábamos ficheros y esta es nuestra primera incursión con los artefactos, una opción intermedia para empezar es copiar nuestro paquete al servidor, descomprimir en un directorio de nueva versión y hacer un enlace simbólico entre el directorio que sirve la web y el nuevo (por ejemplo, en vez de servir la web desde /var/www/web sirves desde /var/www/web/current y subes tu código a /var/www/web/v1.1 y haces un enlace simbólico que apunte current a v1.1, si algo falla tendrás la versión anterior en v1.0). Esto que parece sencillo, en seguida se lía y se hace infinitamente más cómodo gestionarlo desde tags de control de versiones con un jenkins o similar.

Aquí solo un apunte, es muy probable que la tarea de hacer el artefacto no sea solo empaquetar, comprimir, si no que queramos aprovechar ese proceso para ofuscar código, compactar y juntar ficheros de estilos, u otro sinfín de cosas que podemos querer hacerle al código antes de subirlo a Producción (por ejemplo, es muy probable que haya muchas librerías asociadas a nuestro proyecto que no vamos a tener subidas al repositorio de control de versiones y, parte del proceso de generar el artefacto, sea la descarga de esas librerías).  

Un artefacto para gobernarlos a todos

Se suele señalar como antipatrón (algo a evitar), el hacer un artefacto distinto para cada entorno. Es decir, que si tenemos un entorno de pruebas hagamos un paquete A para desplegar en el entorno de pruebas y, posteriormente, hagamos un paquete B para desplegar eso mismo en Producción. La razón fundamental es que es al final vamos a estar probando algo diferente a lo que finalmente entregamos, que es justo lo que los artefactos evitan.

Lo suyo es desplegar exactamente lo mismo, pero que todos los parámetros del entorno (direcciones de bases de datos, API's, contraseñas, etc), vengan dados por variables de entorno o ficheros de configuración por entorno.

Resolver también que la máquina no sea la misma

Dije entre medias, que los artefactos siempre resuelven el problema de probar exactamente el mismo código y que, a veces, resuelven también el problema de que la máquina no sea la misma. Esto se consigue haciendo que el artefacto contenga la máquina también.

Trabajando con máquinas físicas y despliegues en máquinas físicas es imposible, claro, pero trabajando con Docker y despliegues de contenedores, lo que se hace es que el artefacto sea en sí mismo un contenedor (o varios) de Docker. De este modo, el propio artefacto lleva implícita la configuración de la máquina en la que funciona y puede probarse exactamente con las mismas condiciones (versión de servidor web, versión de PHP, librerías, etc) en local, en entornos de pruebas y en Producción.

Pero dejaremos Docker para más adelante :), cualquier duda, pregunta, consulta o corrección, por favor, dejadnos un correíto.