Es difícil para el código proporcionar valor a menos que sea accesible para los usuarios. Si nuestro código no proporciona valor, ¿por qué lo escribimos? La forma en que obtenemos el código en nuestros entornos de producción ha cambiado con el tiempo y varía un poco de un equipo a otro, pero obtener código donde los usuarios pueden obtener valor de él es algo que es importante para nosotros en…
Entonces, ¿cómo llega el código de una máquina de desarrollo a una máquina de producción en?
Durante el desarrollo
El proceso comienza cuando se escribe el código. Tenemos la regla de que todo el código de producción debe tener al menos dos pares de ojos sobre él antes de que salga. Eso normalmente toma la forma de programación en pares, pero a veces ocurre a través de revisiones de código o programación de la mafia. Esa elección la hacen los equipos individuales. Normalmente realizamos todas las pruebas unitarias (no sólo las del código en el que estamos trabajando) antes de enviar el código a nuestro repositorio central en Github.
Cuando realmente empujamos el código, ¿a dónde va? Va en nuestra rama maestra, por supuesto. La maestra siempre debe ser desplegable. Si tu código no debe ser desplegado en producción, no debes empujarlo todavía. Eso no significa que debas pasar mucho tiempo entre empujar tu código. Significa que debes escribir tu código en trozos más pequeños. La razón por la que no usamos las ramas es porque tienden a ser de larga vida. Si tienes código en múltiples ramas de larga vida, entonces el código de esas ramas no se integra. No sé si el código de mi rama funcionará con el código de la tuya hasta que se fusionen en el mismo lugar.
En TeamCity usamos como servidor de integración continua. Cuando el código es empujado a un repositorio Git, se inicia automáticamente una compilación para ese código. Una compilación consiste en la compilación (o transpilación si es necesario) y la ejecución de todas las pruebas unitarias. Si cualquiera de esos pasos falla, la compilación falla y el código no va más allá. Para algunas bases de código tenemos tipos adicionales de pruebas automatizadas, no sólo pruebas unitarias. Para nosotros, éstas suelen tomar la forma de lo que llamamos pruebas de integración (pruebas de código que depende de un servicio de terceros como una base de datos o un servicio web externo) o pruebas de aceptación (pruebas de múltiples unidades de código desde una perspectiva empresarial, pero por debajo de la capa de interfaz de usuario y sin ejecutarse en un entorno completo).
Desplegándose a la etapa
Si el código se compila y todas las pruebas pasan, entonces el código se despliega automáticamente a nuestro entorno de montaje.Hay una construcción separada de Team City que se dispara cuando las construcciones previas tienen éxito y que inicia el despliegue.Para nuestros proyectos .NET (y algunos de nuestros proyectos de Nodo) usamos Octopus Deploy.Antes de que Octopus Deploy estuviera disponible teníamos una herramienta construida a medida que era similar pero no tan rica en características. Octopus no tiene todas las características posibles que podríamos soñar y ocasionalmente se confunde, pero el 99% de las veces simplemente funciona y es genial.Para nuestros proyectos que no usan Octopus Deploy, tenemos una construcción Team City separada para ese proyecto que usa SaltStack para empujar el código a las máquinas deseadas.
Una vez que el código se despliega en nuestro entorno de ensayo, podemos hacer cualquier prueba manual que creamos necesaria. Este esfuerzo suele ser bastante mínimo, pero a veces hay cosas que son imposibles, extremadamente difíciles o que consumen mucho tiempo para probarlas automáticamente o fuera de un entorno completamente funcional. Las pruebas de IU son notoriamente lentas y frágiles, por lo que tratamos de no tener demasiadas. Sólo queremos probar las cosas que DEBEN funcionar. Por ejemplo, tenemos pruebas para asegurarnos de que los nuevos usuarios pueden registrarse y que los usuarios existentes pueden ver videos. Si esas cosas no funcionan, nuestro sitio no es muy útil. Si estas pruebas de IU fallan, entonces esa construcción no se va a producir.
A la producción
Si todas nuestras pruebas automáticas (y cualquier prueba manual que consideremos necesaria) se ven bien, entonces tenemos la opción de desplegar nuestro código a la producción. El equipo también puede coordinar con otros equipos u otras partes interesadas si es necesario. Tratamos de hacerlo de manera que las decisiones puedan permanecer dentro del equipo en la medida de lo posible. Cuando nos desplegamos en la producción, utilizamos el mismo proceso (Octopus Deploy o TeamCity + SaltStack) que utilizamos cuando nos desplegamos en el escenario. Se trata de una operación de botón que hace que los mismos archivos binarios que ya están en la etapa sean enviados a las máquinas de producción, sólo que con una configuración diferente. Por ejemplo, para actualizar el código en una granja web, sacamos un conjunto de servidores web del grupo de balanceo de carga, esperamos a que las conexiones activas se agoten, actualizamos el código, ejecutamos potencialmente algunos scripts de calentamiento, y luego volvemos a poner los servidores web en el grupo de balanceo de carga. No actualizamos todos los servidores web a la vez, así que no hay tiempo de inactividad para nuestros usuarios.
¿Rompimos algo?
Cuando estamos haciendo despliegues frecuentes (y todo el tiempo realmente) queremos saber si hay problemas en la producción. Tenemos un gran grupo de apoyo que es súper receptivo a la hora de abordar los problemas de los clientes y de hacernos saber cuando ven problemas. Pero hacer de ellos nuestra primera línea de defensa cuando las cosas van mal no es justo para ellos. New Relic también nos da algunos extras como tiempos de respuesta y similares. Tenemos algunas métricas personalizadas en New Relic que hemos construido nosotros mismos para monitorear cosas específicas que son importantes para nosotros. Además de New Relic agregamos nuestros registros usando ELK (Elasticsearch, Logstash, Kibana). Si notamos un problema podemos acceder a todos nuestros registros de producción para obtener más información sobre lo que va mal. También podemos configurar una alerta en los registros (por ejemplo, dar una alerta si un cierto número de errores se registran en un período de tiempo determinado).
Así que con todas nuestras pruebas y monitoreo nada sale mal, ¿verdad? Bueno, las cosas no suelen salir mal. Según nuestras métricas internas, en septiembre de 2016 nos desplegamos a producción 418 veces. Eso es en todos los equipos y todas las unidades desplegables. De esos 418 despliegues, 10 de ellos fueron a una versión más antigua de la que ya estaba en producción. Eso es una tasa de retroceso de alrededor del 2%. Rara vez tenemos problemas críticos por los que hacemos retrocesos. La mayoría de ellos son por problemas pequeños, por ejemplo, texto incorrecto en una página, regresiones de rendimiento, etc. Con el Octopus Deploy (y la herramienta personalizada que usamos antes del Octopus Deploy), un retroceso está a un solo botón de distancia. Hasta ahora nuestro negocio ha encontrado que nuestra frecuencia, gravedad y dificultad de los retrocesos es aceptable.
Conclusión
Desplegarlo con frecuencia no sólo es posible, sino que es una ventaja. Nos permite obtener retroalimentación de los usuarios reales más pronto. Nos permite liberar sin temor porque lo que ha cambiado desde la última liberación suele ser tan pequeño. Nos permite responder a las situaciones comerciales cambiantes más rápidamente. Y personalmente, me hace más feliz.
Categorías: prácticasTags: testing, continuous integration, continuous deployment