Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Los ciclos de versión más rápidos son una de las principales ventajas de las arquitecturas de microservicios. Pero sin un buen proceso de CI/CD, no logrará la agilidad que prometen los microservicios. En este artículo se describen los desafíos y se recomiendan algunos enfoques para el problema.
¿Qué es CI/CD?
Cuando hablamos de CI/CD, realmente estamos hablando de varios procesos relacionados: integración continua, entrega continua e implementación continua.
integración continua. Los cambios de código se fusionan frecuentemente en la rama principal. Los procesos de compilación y prueba automatizados garantizan que el código de la rama principal siempre sea de calidad de producción.
entrega continua. Los cambios de código que pasan el proceso de CI se publican automáticamente en un entorno similar a producción. La implementación en el entorno de producción en vivo puede requerir la aprobación manual, pero de lo contrario se automatiza. El objetivo es que el código siempre esté listo para implementar en producción.
implementación continua. Los cambios de código que pasan los dos pasos anteriores se implementan automáticamente en producción.
Estos son algunos objetivos de un proceso sólido de CI/CD para una arquitectura de microservicios:
Cada equipo puede crear e implementar los servicios que posee de forma independiente, sin afectar a otros equipos ni interrumpirlos.
Antes de implementar una nueva versión de un servicio en producción, se implementa en entornos de desarrollo, pruebas y control de calidad para la validación. Los puntos de control de calidad se aplican en cada fase.
Una nueva versión de un servicio se puede implementar en paralelo con la versión anterior.
Se han implementado directivas de control de acceso suficientes.
En el caso de las cargas de trabajo contenarizadas, se puede confiar en las imágenes contenarizadas que se implementan en producción.
¿Por qué es importante una canalización sólida de CI/CD?
En una aplicación monolítica tradicional, hay una única canalización de compilación cuya salida es el ejecutable de la aplicación. Todo el trabajo de desarrollo se alimenta en esta canalización. Si se encuentra un error de alta prioridad, se debe integrar, probar y publicar una corrección, lo que puede retrasar la versión de las nuevas características. Puede mitigar estos problemas teniendo módulos bien factorados y usando ramas de características para minimizar el impacto de los cambios de código. Pero a medida que la aplicación crece más compleja y se agregan más características, el proceso de liberación de un monolito tiende a ser más frágil y probablemente romperse.
Siguiendo la filosofía de los microservicios, nunca debe haber un proceso de lanzamiento extenso en el que todos los equipos tengan que esperar su turno. El equipo que compila el servicio "A" puede publicar una actualización cuando elija, sin esperar a que los cambios en el servicio "B" se combinen, prueben e implementen.
Para minimizar el riesgo, el pipeline de lanzamiento debe estar automatizado y ser altamente confiable para lograr una alta velocidad de versión. Si despliega en producción una vez o más al día, las regresiones o las interrupciones del servicio deben ser poco frecuentes. Al mismo tiempo, si se implementa una actualización incorrecta, debe contar con una manera confiable de revertir rápidamente a una versión anterior o adelantar a una versión posterior de un servicio.
Desafíos
Muchas bases de código independientes pequeñas. Cada equipo es responsable de crear su propio servicio, con su propia canalización de compilación. En algunas organizaciones, los equipos pueden usar repositorios de código independientes. Los repositorios independientes pueden provocar una situación en la que el conocimiento de cómo compilar el sistema se distribuye entre equipos y nadie de la organización sabe cómo implementar toda la aplicación. Por ejemplo, ¿qué ocurre en un escenario de recuperación ante desastres, si necesita implementar rápidamente en un nuevo clúster?
Mitigación: Tener una canalización unificada y automatizada para desarrollar e implementar servicios, de modo que este conocimiento no esté oculto dentro de cada equipo.
varios lenguajes y marcos. Con cada equipo con su propia combinación de tecnologías, puede ser difícil crear un único proceso de compilación que funcione en toda la organización. El proceso de compilación debe ser lo suficientemente flexible como para que cada equipo pueda adaptarlo para su elección de lenguaje o marco.
Mitigación: Containerizar el proceso de construcción para cada servicio. De este modo, el sistema de compilación solo debe poder ejecutar los contenedores.
integración y pruebas de carga. Con los equipos que publiquen actualizaciones a su propio ritmo, puede ser difícil diseñar pruebas completas sólidas, especialmente cuando los servicios tienen dependencias en otros servicios. Además, la ejecución de un clúster de producción completo puede ser costosa, por lo que es poco probable que cada equipo ejecute su propio clúster completo a escalas de producción, solo para pruebas.
Administración de versiones. Cada equipo debe poder implementar una actualización en producción. Esto no significa que todos los miembros del equipo tengan permisos para hacerlo. Pero tener un rol centralizado del Administrador de versiones puede reducir la velocidad de las implementaciones.
mitigación: cuanto más automatizado y confiable sea el proceso de CI/CD, menos necesidad habrá de una autoridad central. Dicho esto, es posible que tenga directivas diferentes para publicar actualizaciones de características principales frente a correcciones de errores menores. Estar descentralizado no significa que la gobernanza sea cero.
Actualizaciones de servicio. Al actualizar un servicio a una nueva versión, no debe interrumpir otros servicios que dependan de él.
Mitigación: use técnicas de implementación como blue-green o canary release para cambios que no interrumpan el servicio. Para realizar cambios importantes en la API, implemente la nueva versión en paralelo con la versión anterior. De este modo, los servicios que consumen la API anterior se pueden actualizar y probar para la nueva API. Para obtener más información, consulte la sección Actualizar servicios de este artículo.
Monorepo vs. varios repositorios
Antes de crear un flujo de trabajo de CI/CD, debe saber cómo se estructura y administra la base de código.
- ¿Los equipos funcionan en repositorios independientes o en un monorepo (repositorio único)?
- ¿Cuál es la estrategia de bifurcación?
- ¿Quién puede desplegar código a producción? ¿Hay un rol de administrador de versiones?
El enfoque monorepo ha estado recibiendo aceptación, pero hay ventajas y desventajas para ambos.
| Monorepo | Varios repositorios | |
|---|---|---|
| ventajas | Uso compartido de código Más fácil de estandarizar el código y las herramientas Más fácil de refactorizar código Detectabilidad: vista única del código |
Definir la propiedad por equipo Potencialmente menos conflictos de fusiones Ayuda a aplicar el desacoplamiento de microservicios |
| Desafíos | Los cambios en el código compartido pueden afectar a varios microservicios Mayor potencial para conflictos de combinación Las herramientas deben escalarse a una base de código grande Control de acceso Proceso de implementación más complejo |
Más difícil compartir código Más difícil de aplicar estándares de codificación Administración de dependencias Base de código difuso, mala detectabilidad Falta de infraestructura compartida |
Actualización de servicios
Hay varias estrategias para actualizar un servicio que ya está en producción. Aquí se describen tres opciones comunes: Actualización gradual, implementación azul-verde y lanzamiento canario.
Actualizaciones graduales
En una actualización gradual, se implementan nuevas instancias de un servicio y las nuevas instancias comienzan a recibir solicitudes inmediatamente. A medida que aparezcan las nuevas instancias, se quitan las instancias anteriores.
Ejemplo. En Kubernetes, las actualizaciones graduales son el comportamiento predeterminado al actualizar la especificación del pod para un Deployment. El controlador de implementación crea un nuevo ReplicaSet para los pods actualizados. A continuación, incrementa el número de réplicas del nuevo ReplicaSet mientras disminuye el del anterior, para mantener el recuento de réplicas deseado. No elimina los pods antiguos hasta que los nuevos estén listos. Kubernetes mantiene un historial de la actualización, por lo que puede revertir una actualización si es necesario.
Ejemplo. Azure Container Apps usa revisiones para administrar las actualizaciones graduales . Al implementar una nueva revisión, Container Apps puede cambiar gradualmente el tráfico de la revisión anterior a la nueva mediante reglas de división de tráfico. Si la nueva revisión encuentra problemas, puede revertir redireccionando el tráfico a la revisión anterior. Puede configurar varias revisiones activas simultáneamente y controlar el porcentaje de tráfico que recibe cada revisión.
Un desafío de las actualizaciones graduales es que durante el proceso de actualización, se está ejecutando y recibiendo tráfico una combinación de versiones antiguas y nuevas. Durante este período, cualquier solicitud podría enrutarse a cualquiera de las dos versiones.
Para realizar cambios importantes en la API, se recomienda admitir ambas versiones en paralelo hasta que se actualicen todos los clientes de la versión anterior. Vea versionado de API.
Implementación azul-verde
En una implementación azul-verde, se implementa la nueva versión junto con la versión anterior. Después de validar la nueva versión, cambie todo el tráfico a la vez de la versión anterior a la nueva. Después del cambio, supervisas la aplicación para detectar cualquier problema. Si algo va mal, puede volver a cambiar a la versión anterior. Suponiendo que no hay problemas, puede eliminar la versión anterior.
Con una aplicación monolítica o de N niveles más tradicional, la implementación azul-verde generalmente significaba el aprovisionamiento de dos entornos idénticos. Implementaría la nueva versión en un entorno de ensayo y, a continuación, redirigiría el tráfico de cliente al entorno de ensayo; por ejemplo, intercambiando direcciones VIP. En una arquitectura de microservicios, las actualizaciones se producen en el nivel de microservicio, por lo que normalmente implementaría la actualización en el mismo entorno y usaría un mecanismo de detección de servicios para intercambiar.
ejemplo. En Kubernetes, no es necesario aprovisionar un clúster independiente para realizar implementaciones azules y verdes. En su lugar, puede aprovechar las ventajas de los selectores. Cree un nuevo recurso Deployment con una nueva especificación de pod y otro conjunto de etiquetas. Cree esta implementación, sin eliminar la implementación anterior ni modificar el servicio que apunte a ella. Una vez que se ejecutan los nuevos pods, puede actualizar el selector del servicio para que coincida con la nueva implementación.
Una desventaja de la implementación azul-verde es que, durante la actualización, se ejecutan el doble de pods para el servicio (actual y siguiente). Si los pods requieren recursos sustanciales de CPU o memoria, puede que necesites escalar horizontalmente el clúster temporalmente para manejar el consumo de recursos.
Lanzamiento canario
En un lanzamiento canario, primero se implementa una versión actualizada en un pequeño subconjunto de clientes. Después, supervise el comportamiento del nuevo servicio antes de implementarlo en todos los clientes. Este enfoque le permite implementar gradualmente de forma controlada, supervisar datos reales e identificar problemas antes de que afecten a todos los clientes.
Una versión canary es más compleja de administrar que un despliegue azul-verde o una actualización continua, ya que debe enrutar dinámicamente las solicitudes a diferentes versiones del servicio.
ejemplo. En Kubernetes, puede configurar un Service para abarcar dos conjuntos de réplicas (uno para cada versión) y ajustar los recuentos de réplicas manualmente. Sin embargo, este enfoque es más bien de grano grueso, debido a la manera en que Kubernetes realiza el balanceo de carga entre pods. Por ejemplo, si tiene un total de 10 réplicas, solo puede redireccionar el tráfico en incrementos del 10%. Si utiliza una malla de servicios, puede usar las reglas de enrutamiento del servicio de malla para implementar una estrategia de despliegue canario más sofisticada.
Pasos siguientes
- Ruta de aprendizaje: definir e implementar la integración continua
- aprendizaje : Introducción a la entrega continua
- Arquitectura de microservicios
- Por qué usar un enfoque de microservicios para compilar aplicaciones