Y ahora verificando la performance (II)

Ok, esta vez si me he demorado en la segunda parte de esta serie sobre como agregar pruebas de performance a nuestros procesos de despliegue, en nuestro articulo anterior vimos como agregar configurar una prueba de carga sencilla, básicamente registrábamos una URL, el volumen de la prueba y listo… ya podíamos hacer una prueba preliminar que nos podría ser muy útil en algunos casos (como cuando todos los parámetros de una búsqueda están en el QueryString, por ejemplo), pero si queremos mayor granularidad en los parámetros de la prueba la alternativa es usar los Web Performance and Load Test Project que han ido evolucionando y que mediante el uso de Azure nos permiten desde Visual Studio tener unos resultados de prueba muy configurables, así:

Clipboard26

Y eso esta genial, pues nos permite (mediante nuestra cuenta de VSTS) provisionar recursos Azure que hagan la respectiva prueba mientras sea necesario, y que podamos ver dichos resultados desde nuestro Visual Studio, pero… ¿que tal si queremos que esta validación de carga decida si un despliegue ha ido bien o no? Pues eso es lo que trataremos de conseguir en este post.

En concreto lo que haremos sera agregar un proyecto de carga a nuestra solución, incluirla en el repositorio y de esta manera valernos de sus archivos para incluir un nuevo tipo de tarea durante nuestro proceso de despliegue, asumiremos que estamos trabajando con una solución Web que ya tiene configurado su repositorio asi como sus procesos de Build y Despliegue como hemos visto en anteriores artículos, ¿ok? Finish Reading: Y ahora verificando la performance (II)

Los dilemas de la Gestión de la Configuración en Entornos de despliegue

Si, se que les debo el como configurar la prueba de performance avanzada, pero en el interin quiero compartir unas reflexiones a propósito de la gestión de la configuración que vino a mi mente durante el DevDays.

Quienes han ido a mis diversas sesiones sobre VSTS o DevOps, sabrán que siempre hago referencia al lio que nos significa el gestionar los parámetros de configuración conforme una aplicación pasa de un entorno, el como manualmente uno tenia que tener mucho cuidado para asegurarse que la aplicación en Producción no apunte a la BD incorrecta, por mencionar el ejemplo mas claro.

Al empezar usar técnicas de Integración y Entrega Continua el primer enfoque que utilice para aliviar estos problemas fue el basarme en las Transformaciones, de esta manera se gestionaba un Web.Config “maestro” (en el caso de Java y Maven el escenario es muy similar solo que en este caso se trata de “pom”s”), que podía ser usado sin problemas en los equipos de desarrollo, pero al momento de efectuar la construcción de una nueva versión el compilador modificaba el Web.Config reemplazando porciones de este con contenidos especialmente definidos en archivos “delta” que contenían las variantes de cada destino al cual se iba a destinar la versión respectiva, en consecuencia ocurrían los siguientes hechos:

  • Se requiere hacer una Build Definition por cada potencial entorno al cual se iba destinar la aplicación, para de esta manera indicar que la construcción cogiera el “delta” correcto.
  • Si una versión puesta en un entorno es aprobada para ser “promovida” a un entorno superior, es necesario que dicha versión haya sido etiquetada o identificada adecuadamente a fin de poder recuperar el código fuente vigente entonces a fin de generar un paquete para el destino indicado.
  • Todos los “deltas” tienen que estar versionados en el código fuente, lo cual puede ser un problema si se desea mantener reserva sobre las cadenas de conexión a los entornos de Producción.

Aun así esto significa un gran avance con respecto a la gestión usual de editar y copiar a mano los archivos de configuración, donde revisas varias veces para ver que todo esta Ok. Otra opción, que no me gusta, es el de gestionar un repositorio (a veces separado del de código fuente) con todos los archivos de configuración de las diversas aplicaciones y que el proceso de despliegue simplemente copie el archivo respectivo en destino, y en algunos casos efectuar las mezclas necesarias de archivos.

La nube viene a significar una mejora en estos problemas, como vimos anteriormente  es muy sencillo configurar para que sea el Entorno (en este caso un Azure Web App, aunque AWS ofrece algo similar en su Elastic Beanstalk) sea quien almacene los mencionados parametros, y mas aun… gestionar ranuras de despliegue que permitan mover de manera sencilla el paquete de un lado a otro (en realidad mediante un cambio de DNS), conservando cada entorno su propio conjunto de parametros, sin que estos tengan que almacenarse en el código fuente.

Muy bien, parte de los problemas simplificados, uno solo creaba una Build Definition con paso de despliegue a un entorno y luego mediante la consola del entorno se encargaba de hacer los respectivos swaps o intercambios de contenidos, pero eso nos dejaba con los siguientes hechos:

  • Se salia fuera del ciclo automatizado de Integración y Entrega Continua para hacer el movimiento entre entornos.
  • Solo funciona en un entorno PaaS, si se trabaja con IaaS u On Premise, esta ventaja esta totalmente fuera de nuestro alcance.
  • Si se trabaja con AWS, hay que tener cuidado con no publicar valores en los archivos de configuración, pues (a diferencia de Azure) las variables definidas en el entorno solo funcionan si NO están definidas en los archivos de configuración, siendo que lo que este en los archivos tiene prioridad sobre el entorno.

El escenario ha mejorado bastante con la introducción de Release Management, que permite manejar el proceso de Build de una manera separada del de Despliegue, para que de esta manera uno genere un paquete, lo despliegue (cogiéndolo de un punto de contacto común), y si luego se aprueba su paso a otro entorno (mediante el flujo de aprobadores que ya hemos visto) el sistema efectuara la copia respectiva del paquete, y claro si seguimos trabajando aprovechando las ventajas de la gestión de parametros en el entorno… pues ya tenemos casi todo solucionado, solo que entre otras cosas… esto sigue siendo valido solo para PaaS.

En el ultimo DevDays tuve la ocasión de conversar con el gran Donovan Brown, el cual me ayudo con unos detalles de Release Management que no había configurado del todo bien, y en adición a ello le resumí brevemente sobre el enfoque de uso de Azure Web Apps para guardar parametros, y me dijo que es una buena opción para soluciones no complejas, pues solo podemos guardar AppSettings y Cadenas de Conexión, siendo que si requerimos grabar una entrada compleja (como la configuración de Redis) esto solo podríamos hacerlo mediante archivos de configuración, y como de nuevo esto nos regresa al tema de las transformaciones y las build independientes, me sugirió revisar el concepto de tokenización.

Investigando, pude entender (gracias a este interesante articulo) que mediante la tokenización lo que se pretende es que se despliegue un archivo de configuración con marcas (tokens) que luego en el proceso de despliegue (no en la compilación, ojo) sean sobreescritas por parámetros definidas en la Release Definition, resultando en que el web.config (por ejemplo) que llega al entorno destino ya tiene todos los valores correctos para dicho entorno, siendo que estos valores ya no son gestionados por el repositorio de código fuente, sino por el motor de Entrega Continua (en nuestro caso VSTS, pero el concepto es aplicable a otros motores), esta tendencia recién esta avanzando pero se simplifica mucho ahora que es posible definir tareas personalizadas a nuestro VSTS (y me imagino que ya habrá algún plugin Jenkins que logre el mismo efecto), ya que de momento no vienen de serie… pero eso no quita que en un futuro el proceso de tokenización venga de serie, de momento… tocara toquetear un poco… en el caso de ser necesario (cuando no se este usando PaaS y/o necesitemos gestionar valores complejos).

Asi pues, siempre hay formas de mejorar y afinar la solución para casos no cubiertos plenamente ¿qué otras opciones se les ocurren para estos dilemas?