Los despliegues de aplicaciones Java suelen ser complicados, propensos a errores, y manuales, de forma que se generan demoras en hacer que el software quede disponible para los usuarios. En este artículo identificaremos una colección de patrones claves para crear un proceso de despliegue seguro, repetible y consistente capaz de generar despliegues de aplicaciones Java con sólo hacer un click.
Los patrones de despligue
El despligue de software se suele tratar como un mal necesario que se puede hacer a último momento antes de entrar en vivo en producción. Pero deberían aplicarse técnicas y principios de ingeniería de software también a la etapa de despligue, como una parte más del ciclo de desarrollo. Cuando se realizan despliegues manuales, esta tarea se convierte en un proceso repetitivo y propenso a errores. Así como podemos automatizar la compilación y la construcción de software para reducir los errores y aumentar la velocidad de desarrollo, también podemos automatizar el proceso de despliegue para reducir las equivocaciones y entregar software rápidamente.
Existen patrones para el desarrollo de software que son bien conocidos, pero también existen patrones para el despligue de aplicaciones. A continuación analizaremos ocho patrones de despligue, brindando ejemplos para cada uno:
- Gestión de todos los archivos de configuración en un Repositorio centralizado, lo que permite utilizar un Despliegues por Scripts para crear software que funcione.
- Despliegues por Scripts, lo que automatiza todas las acciones de despliegue de manera que no haya intervención humana cuando se ejecuta un despliegue.
- Comando único, lo que reduce la complejidad del despligue y permite realizar una Ejecución sin humanos durante el proceso de despligue.
- Configuración con Tokens, lo que brinda una forma repetible de inyectar información variable dentro de los archivos de configuración.
- Configuración externalizada, que simplifica el ingreso de información variable para los ambientes destino.
- Plantilla de verificación, que ayuda a asegurar que todas las propiedades de los ambientes destino sean iguales.
- Ejecución sin humanos, que brinda una forma segura de acceder a múltiples equipos en un proceso automatizado.
- Despliegue unificado, que promueve un único script de despligue que puede ejecutarse en distintos ambientes de destino.
Todos estos patrones se relacionan entre si para poder lograr una solución completa de automatización de despliegues. Repasemos entonces cada uno de los patrones, su motivo de ser y cómo se relaciona con el resto.
Subir todos los archivos a un repositorio de control de versiones
Nombre: Repositorio
Patrón: se suben todos los archivos a un repositorio de control de versiones - en el entorno de despliegue, nos referimos a todos los archivos de configuración y herramientas.
Anti-patrón: algunos equipos de desarrollo dejan esta información en una unidad compartida con acceso controlado. Otros mantienen la información en sus máquinas locales y luego la copian al ambiente de destino.
Como regla general se recomienda que los equipos de desarrollo suban todos los archivos necesarios para crear un software que funcione. Muy pocas veces hay excepciones a esta regla. En el contexto del despligue, algunos equipos creen equivocadamente que los servidores y la configuración de los servidores es fija - que no cambia. Aunque a veces hay restricciones para subir archivos binarios grandes, la configuración, los scripts de bases de datos, y todos los scripts de construcción y despliegue deben estar subidos a un repositorio de control de versiones. El patrón Repositorio asiste a los demás patrones que veremos a continuación, en especial a Despliegue por Scripts y Comando único.
Crear scripts para todo el proceso de despliegue
Nombre: Despliegue por scripts
Patrón: todos los procesos de despliegue se escriben en un script.
Anti-patrón: algunos pueden hacer tareas manuales de configuración, como instalar y configurar un contenedor web. Otros pueden usar herramientas visuales provistas por el contenedor para modificar el contenedor para un ambiente específico. Es facil modificar la configuración de las tareas manuales la primera vez, pero no escala cuando hay que hacer múltiples despligues hacia muchos ambientes de destino, varias veces por semana. Más aún, la herramienta de administración visual puede ser muy útil para el despligue - la primera vez que se usa. Sin embargo, este enfoque no escala y es propenso a errores, porque varias personas tienen que repetir el mismo procedimiento una y otra vez.
De esta manera, el patrón de Despliegue por script nos insita a, por ejemplo, automatizar el proceso de (re)iniciar un Tomcat usando un script de despliegue. Este proceso se puede escribir usando Apache Ant como lenguaje de scripting.
<available file="@{tomcat.home}/server/@{tomcat.server.name}/bin" property="tomcat.bin.exists"/> <if> <isset property="tomcat.bin.exists"/> <then> <echo message="Starting tomcat instance at @{tomcat.home} with start_tomcat" /> <exec executable="@{tomcat.home}/server/@{tomcat.server.name}/bin/start_tomcat" osfamily="unix" /> </then> <else> <echo message="Starting tomcat instance at @{tomcat.home} with startup.sh" /> <exec osfamily="unix" executable="chmod" spawn="true"> <arg value="+x" /> <arg file="@{tomcat.home}/bin/startup.sh" /> <arg file="@{tomcat.home}/bin/shutdown.sh" /> </exec> <exec executable="sh" osfamily="unix" dir="@{tomcat.home}/bin" spawn="true"> <env key="NOPAUSE" value="true" /> <arg line="startup.sh" /> </exec> <exec osfamily="windows" executable="cmd" dir="@{tomcat.home}/bin" spawn="true" > <env key="NOPAUSE" value="true" /> <arg line="/c startup.bat" /> </exec> <sleep seconds="15" /> </else> </if>
Al crear un script de este proceso eliminamos la necesidad de ir haciendo clicks a través de la consola de administración de Tomcat. Más aún, al está dentro de un script, puede ejecutarse en una Ejecución sin humanos como parte de un despliegue automatizado completo.
Crear despliegues que se ejecuten con un único comando
Nombre: Comando único
Patrón: quienes realizan el despligue, o procesos automáticos, pueden escribir un único comando para generar software funcionando para los clientes.
Anti-patrón: algunos procesos de despliegue necesitan que las personas ingresen múltiples comandos y procedimientos tales como copiar archivos, modificar archivos de configuración, reiniciar un servidor, definir contraseñas, y otras acciones repetitivas y prontas a error. Con suerte, estas personas tienen acceso a documentación paso-a-paso para realizar estas acciones. Igualmente, el hacer que los humanos realicen procedimientos de despliegue introduce un mayor riesgo de errores, y causa cuellos de botella que demoran la instalación de software en múltiples ambientes de destino.
Cuando se escribe un despliegue, los clientes suelen ser otras personas del equipo, la organización o incluso otra computadora. Mientras más complejo sea ejecutar el despliegue, menos probable que un proceso automatizado pueda ejecutarlo con éxito sin cometer errores.
Un ejemplo de comando único para ejecutar un despliegue podría ser:
ant -Dproperties.file=$USERHOME/mi-proyecto/properties/dev-install.properties \ deploy:remote:install
Este comando ejecuta una tarea Ant llamada deploy:remote:install
a la que se le pasa un archivos de propiedades con todas la configuración específica del ambiente (dev-install.properties), y realiza el despliegue del software remotamente a otros equipos. Esta tarea realiza acciones como copiar archivos usando un protocolo seguro (SCP), ejecución remota de comandos usando Secure Shell (SSH), instalación, configuración y reinicio del Contendor Web, y muchos otros procesos - todo sin intervención humana. Obviamente, un usuario puede ingresar este comando, pero es tan simple que puede ser ejecutado por un proceso automático, como ser un Servidor de Integración Continua o un servidor de construcción de software.
Inyectar información variable dentro de archivos de configuración
Nombre: Configuración por tokens
Patrón: se ingresan nombres de tokens dentro de archivos de configuración, y luego se reemplazan durante el Despliegue por Scripts basándose en propiedades de Configuración externalizada subidas a un Repositorio.
Anti-patrón: los datos específicos del destino se ingresan en archivos de configuración para cada ambiente.
A continuación vemos un XML que administra la configuración de acceso a datos entre un contenedor web y una base de datos. En este archivo se ubican los tokens usando signos @. Durante el proceso de despliegue automatizado, un script reemplaza los tokens con los valores reales de archivos de Configuración externalizada.
<datasources> <local-tx-datasource> <jndi-name>@application.context.name@</jndi-name> <use-java-context>false</use-java-context> <connection-url>@database.url@</connection-url> <user-name>@database.user@</user-name> <password>@database.password@</password> <driver-class>@database.driver@</driver-class> </local-tx-datasource> </datasources>
Al crear tokens de lo que serán valores específicos para un ambiente nos permite crear un Despliegue por scripts que soporte múltiples ambientes con un Despliegue unificado.
Extraer todas las propiedades específicas para un ambiente
Nombre: Configuración externalizada
Patrón: todos los valores variables de la configuración de la aplicación se externalizan hacia archivos de propiedades que se modifican en tiempo de construcción.
Anti-patrón: algunos hardcodean estos valores, manualmente, para cada ambiente destino, o utilizan herramientas visuales para hacer lo mismo.
Como ejemplo veremos algunas propiedades que se suelen encontrar en archivos de configuración específicos para una aplicación. Al centralizar todos los valores variables en un único archivo de propiedades, logramos desacoplar los datos (las propiedades variables) del comportamiento (los scripts de despligue). En otras palabras, sin importar el ambiente de destino, el proceso automatizado de despligue se ejecuta de la misma forma cada vez.
authentication.type=db application.url=http://${tomcat.server.hostname}:${tomcat.server.port}/mi-webapp database.type=mysql database.server=localhost database.port=3306 database.name=mydb database.user=myuser! database.password=mypa$$! database.url=jdbc:mysql://${database.server}:${database.port}/${database.name} tomcat.server.hostname=localhost tomcat.server.name=default tomcat.web.password=pa$$123! tomcat.cobraorb.port=12748
A menudo, los valores externalizados están presentes a través de todo el código fuente, configuración de servidores, XML, archivos .properties, y otros archivos. Más aún, es común encontrar a estos datos duplicados en el sistema, llevando a problemas complejos de despliegue que son dificiles de depurar. Al extraer esta información de todos estos orígenes disintos en un único archivo .properties, reducimos la diversidad de problemas que puedan ocurrir.
Evitar problemas haciendo ejecuciones sin humanos
Nombre: Ejecución sin humanos
Patrón: establecer una interfaz segura con múltiples computadoras sin tipear ningún comando
Anti-patrón: personas que manualmente acceden a computadoras haciendo un login en cada uno de los equipos con usuarios distintos; luego copiando archivos, configurando valores, y demás.
A pesar de tener un nombre casi barbárico, la Ejecución sin humanos es una solución muy efectiva cuando se necesita acceder a otras computadoras remotas a través de un proceso automatizado. Al usar una infraestructura de clave pública (PKI), se pueden orquestrar comandos dentro de una solución automatizada que sino normalmente recaerían en un desarrollador, ingeniero de construcción, software de gestión de configuraciones (SCM), o personal de operaciones.
Por ejemplo, se puede instalar un archivo de clave-privada en la máquina de construcción y SSH. Los valores específicos se definen en cada uno de los archivos .properties de cada ambiente. Esto suele incluir el nombre de archivo de la clave-privada, el puerto de SSH, y el nombre del equipo remoto. Esta máquina de destino tiene el archivo de clave pública de SSH para completar el handshake SSH.
Si se utiliza este enfoque, un Despliegue por scripts puede ejecutar procesos del ambiente de construcción hacia el ambiente destino (o ambientes) sin intervención humana.
Verificar que las propiedades sean las mismas a través de los ambientes
Nombre: Plantilla de verificación
Patrón: crear un único archivo de plantilla en el cual se basan todas las propiedades de los ambientes de destino.
Anti-patrón: algunos usan una verificación manual, prueba y error (cuando un despliegue falla, verificar el por qué), o mantiene archivos "ocultos" en la máquina.
El problema es que se necesita asegurar que se tienen exactamente los mismos atributos en cada ambiente de destino. ¿Pero cómo verificar todo esto en un ambiente automatizado? Si se utiliza un único archivo .properties como plantilla contra la cual se verifican todos los archivos de los ambientes destino, entonces se puede garantizar que todos los atributos sean iguales sin importar el ambiente en el cual se ejecutan.
Por ejemplo, un script de construcción ejecuta una tarea Ant que compara los atributos (no los valores) entre el archivo plantilla.properties y el archivo .properties específico para un ambiente (dev.properties, qa.properties y así). Si se encuentra alguna diferencia, el despligue falla.
Un archivo plantilla.properties de ejemplo podría ser el siguiente. Notar que solamente se incluyen los atributos, porque los valores son irrelevantes.
db.database= db.username= db.password= db.hostname= db.driver= db.port= db.url=
A continuación vemos el archivo dev.properties (o qa.properties, y así). Este archivo incluye los atributos y los valores. Estos valores son específicos para el ambiente destino.
db.database=brewery db.username=root db.password=p@ssword db.hostname=dev1.domain.com db.driver=com.mysql.jdbc.Driver db.port=3306 db.url=jdbc:mysql://${db.hostname}:${db.port}/${db.database}
Desplegar una vez hacia mútiples ambientes de destino
Nombre: Despliegue unificado
Patrón: crear un único script de despliegue capaz de ejecutarse en distintas plataformas y ambientes de destino.
Anti-patrón: algunos usan scripts de despliegue distintos para cada ambiente de destino, o incluso para una máquina específica.
Aunque algunos procesos de despliegue pueden ejecutarse en ciertos ambientes, todos los procesos deberían ser capaces de ejecutarse en cualquier ambiente de destino. Por ejemplo, el mismo Despliegue por script se ejecuta en los ambientes de desarrollo, testing, y producción, pero usando un archivo de Configuración externalizada diferente. Los atributos de la Configuración externalizada se verifican usando una Plantilla de verificación.
Conclusión
El despliegue de aplicaciones es otro aspecto más de la creación de software, y debe prestársele la misma atención que al resto de los procesos. A su vez, por su naturaleza, el despliegue se presta muy bien a ser automatizado. La automatización del despliegue cosecha los beneficios de un proceso confiable y repetible: se mejora la certeza, velocidad y control.
En este artículo cubrimos ocho patrones que pueden resultar efectivos para la automatización de despliegue de software. Hay más patrones relacionados (como ser el Despliegue Remoto, Contenedores Descartables, Prueba de Despliegue, y Rollback de Ambientes) que veremos en el próximo artículo de esta serie.