Creación de una canalización de CI/CD para microservicios en Kubernetes mediante Azure DevOps y Helm

La creación de un proceso confiable de integración continua y entrega continua (CI/CD) para una arquitectura de microservicios puede ser difícil. Cada equipo necesita liberar servicios de forma rápida y confiable, sin interrumpir a otros equipos ni desestabilizar la aplicación en su conjunto.

En este artículo se describe un ejemplo de canalización de CI/CD para implementar microservicios en Azure Kubernetes Service (AKS). Cada equipo y cada proyecto son diferentes, por lo que no debe tomar este artículo como un conjunto de reglas absolutas. En su lugar, úselo como punto de partida para diseñar su propio proceso de CI/CD.

En la lista siguiente se resumen los objetivos de una canalización de CI/CD para microservicios hospedados en Kubernetes:

  • Los equipos pueden compilar e implementar sus servicios de manera independiente.
  • Cambios de código que pasan el proceso de CI se implementan automáticamente en un entorno similar a producción.
  • Cada fase de la canalización aplica puertas de calidad.
  • Una nueva versión de un servicio se puede implementar en paralelo con la versión anterior.

Para obtener más información, consulte CI/CD para arquitecturas de microservicios.

Supuestos

Para este ejemplo, estas son algunas suposiciones sobre el equipo de desarrollo y la base de código:

  • El repositorio de código es un repositorio único y sus carpetas están organizadas por microservicio.
  • La estrategia de ramificación del equipo se basa en el desarrollo basado en el tronco.
  • El equipo utiliza ramas de versión para administrar las versiones. Se crean versiones independientes para cada microservicio.
  • El proceso de CI/CD usa Azure Pipelines para compilar, probar e implementar los microservicios en AKS.
  • Las imágenes de contenedor de todos los microservicios se almacenan en una única instancia de Azure Container Registry compartida, con un repositorio independiente para cada microservicio. Use Container Registry Azure permisos de repositorio de ABAC para definir el ámbito de cada identidad de canalización en su propio repositorio o use registros independientes en los que se requieran límites de confianza más sólidos.
  • El equipo usa gráficos de Helm para empaquetar cada microservicio.
  • Se utiliza un modelo de despliegue por inserción, en el que Azure Pipelines y los agentes asociados realizan los despliegues conectándose directamente al clúster de AKS.

Estas suposiciones guían muchos de los detalles específicos de la canalización de CI/CD. Sin embargo, puede adaptar el enfoque básico que se describe aquí para otros procesos, herramientas y servicios, como Acciones de GitHub, Jenkins o Docker Hub.

Alternatives

Al elegir una estrategia de CI/CD con AKS, tenga en cuenta las siguientes alternativas comunes:

  • En lugar de usar Helm como una herramienta de implementación y administración de paquetes, puede usar Kustomize, una herramienta de administración de configuración nativa de Kubernetes que introduce una manera sin plantilla de personalizar y parametrizar la configuración de la aplicación.

  • En lugar de usar Azure DevOps para repositorios y canalizaciones de Git, puede usar GitHub repositorios para repositorios git privados y públicos y Acciones de GitHub para canalizaciones de CI/CD.

    Acciones de GitHub proporciona integración con AKS con flujos de trabajo de inicio y admite OpenID Connect (OIDC) para la autenticación segura y sin secretos para Azure.

  • En lugar de usar un modelo de implementación de inserción, considere la posibilidad de administrar la configuración de Kubernetes a gran escala mediante GitOps (modelo de implementación de extracción). Un operador de Kubernetes en clúster como Flux o Argo CD sincroniza el estado del clúster en función de la configuración almacenada en un repositorio de Git. GitOps elimina la necesidad de que las canalizaciones tengan acceso directo al clúster, reduce la superficie expuesta a ataques y proporciona funcionalidades de detección de desfase y recuperación automática.

    Tip

    Al evaluar modelos de implementación basados en inserción frente a modelos de implementación basados en extracción (GitOps), tenga en cuenta los requisitos de carga de trabajo. Las implementaciones basadas en inserción ofrecen actualizaciones deterministas y control directo de canalización, que se adapta a los procedimientos de implementación seguros. Las implementaciones basadas en extracción (GitOps) ofrecen coherencia, auditabilidad y recuperación automática, lo que hace que sean ideales para entornos en los que los clústeres necesitan conciliarse con un estado deseado sin acceso directo de canalización a clúster.

Compilaciones de validación

Supongamos que un desarrollador está trabajando en un microservicio denominado Delivery Service. Al desarrollar una nueva característica, el desarrollador comprueba el código en una rama de características. Por convención, las ramas de funcionalidades se denominan feature/*.

Diagrama de un flujo de trabajo de rama de características.

En el diagrama se muestran dos líneas de rama horizontales de Git y una canalización de compilación debajo de ellas. En la parte superior se encuentra la rama principal, representada como una línea horizontal. La rama feature/8150 se diferencia de main. Esta rama tiene tres puntos colocados en él, con la etiqueta colectiva confirmaciones. De cada una de las tres confirmaciones, una flecha apunta hacia abajo hacia un cuadro situado en la parte inferior del diagrama. El cuadro está etiquetado como Canalización de compilación y contiene el nombre de canalización ci-delivery-validation. Las tres flechas discontinuas convergen en este único cuadro de canalización de compilación, lo que indica que cada confirmación en la rama feature/8150 desencadena una ejecución de la canalización ci-delivery-validation.

El archivo de definición de compilación incluye un trigger que filtra por el nombre de rama y la ruta de origen.

trigger:
  batch: true
  branches:
    include:
    # for new release to production: release flow strategy
    - release/delivery/v*
    - refs/release/delivery/v*
    - main
    - feature/delivery/*
    - topic/delivery/*
  paths:
    include:
    - /src/shipping/delivery/

Cuando se usa este enfoque, cada equipo puede tener su propia canalización de compilación. Solo el código que está protegido en la /src/shipping/delivery carpeta desencadena una compilación de Delivery Service. La inserción de confirmaciones en una rama que coincide con el filtro desencadena una compilación de CI. En este punto del flujo de trabajo, la compilación de CI ejecuta una comprobación mínima del código:

  1. Compilación del código.
  2. Ejecución de pruebas unitarias.

El objetivo es que las compilaciones tarden poco en completarse, para que el desarrollador pueda obtener comentarios rápidamente. Cuando la característica esté lista para combinarse en main, el desarrollador abre una solicitud de incorporación de cambios. Esta operación desencadena otra compilación (o construcción) de CI que realiza algunas verificaciones adicionales:

  1. Compilación del código.
  2. Ejecución de pruebas unitarias.
  3. Ejecute pruebas estáticas de seguridad de aplicaciones (SAST) en el código fuente.
  4. Compilación de la imagen de contenedor en tiempo de ejecución.
  5. Ejecución de exámenes de vulnerabilidades en la imagen.

Diagrama que muestra ci-delivery-full en el pipeline de compilación.

En el diagrama se muestran dos líneas de rama horizontales de Git y una canalización de compilación debajo de ellas. En la parte superior se encuentra la rama principal, representada como una línea horizontal. Debajo, la rama feature/8150 se ejecuta en paralelo a ella y tiene tres puntos en él que representan confirmaciones. En el extremo derecho de la rama feature/8150, una flecha discontinua se conecta a un punto de la rama principal. Ese punto se marca con otro punto con la etiqueta PR, lo que indica que se ha abierto una solicitud de incorporación de cambios en main. Desde el punto de solicitud de incorporación de cambios de la rama principal, una flecha discontinua apunta hacia abajo a un cuadro con la etiqueta Canalización de compilación, que contiene el nombre de canalización ci-delivery-full. En esta línea se muestra que al abrir una solicitud de incorporación de cambios de la rama de características a main se desencadena la canalización ci-delivery-full, que ejecuta el conjunto extendido de comprobaciones de CI.

Nota:

En Azure Repos, uno de los servicios de Azure DevOps, puede definir directivas para proteger las ramas. Por ejemplo, la directiva podría requerir una compilación de CI correcta y un cierre de sesión de un aprobador antes de una combinación en main.

Compilación de CI/CD completa

Cuando el equipo esté listo para implementar una nueva versión de Delivery Service, el administrador de versiones crea una rama desde la rama principal, con este patrón de nomenclatura: release/<microservice name>/<semver>. Por ejemplo: release/delivery/v1.0.2.

Diagrama que muestra una rama de versión que desencadena una canalización de compilación seguida de una canalización de versión.

En el diagrama se muestran tres líneas de rama horizontales de Git y dos canalizaciones debajo de ellas. En el centro se encuentra la rama principal, representada como una línea horizontal. A continuación se muestra la rama feature/8150, que tiene tres puntos en ella que representan confirmaciones. La rama feature/8150 se conecta a la rama principal en un punto con la etiqueta merge, lo que indica que la rama de características se combina en main. Encima y a la derecha de la rama principal, una nueva rama etiquetada release/delivery/v1.0.2 se extiende a la derecha. Esta rama de versión se origina desde main en un punto a la derecha de la combinación. Desde la rama release/delivery/v1.0.2, una línea discontinua apunta hacia abajo a un cuadro con la etiqueta ci-delivery-full, que está encima de la etiqueta Canalización de compilación. A la derecha de ci-delivery-full, una flecha horizontal apunta a un segundo cuadro etiquetado cd-delivery, que está encima de la etiqueta Canalización de versión.

La creación de esta rama desencadena una compilación de CI completa que ejecuta todos los pasos anteriores y estos pasos:

  1. Inserte la imagen de contenedor en Container Registry. La imagen se etiqueta con el número de versión en el nombre de la rama.
  2. Ejecución de helm package para empaquetar el gráfico de Helm para el servicio. El gráfico también se etiqueta con un número de versión.
  3. Empuja el paquete de Helm al Registro de Contenedores.

Si esta compilación se realiza correctamente, desencadena un proceso de implementación (CD) mediante una canalización de versión de Azure Pipelines. Esta canalización contiene los pasos siguientes:

  1. Implementación del gráfico de Helm en un entorno de control de calidad.
  2. Un aprobador aprueba antes de que el paquete pase a producción. Consulte Release deployment control using approvals (Liberación del control de implementación mediante aprobaciones).
  3. Vuelva a etiquetar la imagen de Docker para el espacio de nombres de producción en Container Registry. Por ejemplo, si la etiqueta actual es myrepo.azurecr.io/delivery:v1.0.2, la etiqueta de producción es myrepo.azurecr.io/prod/delivery:v1.0.2.
  4. Implementación del gráfico de Helm en el entorno de producción.

Incluso en un monorepo, deba limitar estas tareas a microservicios individuales para que los equipos puedan implementarse de forma independiente. El proceso incluye algunos pasos manuales: aprobar solicitudes de incorporación de cambios, crear ramas de versión y aprobar implementaciones en el clúster de producción. Los equipos de cargas de trabajo pueden automatizar estos pasos si quieren.

Aislamiento de los entornos

Los servicios se implementan en varios entornos, incluidos los entornos para desarrollo, pruebas de humo, pruebas de integración, pruebas de carga y producción. Estos entornos necesitan cierto nivel de aislamiento. En Kubernetes, puede elegir entre el aislamiento físico y el aislamiento lógico. El aislamiento físico se implementa en clústeres independientes. El aislamiento lógico usa espacios de nombres y directivas.

Nuestra recomendación es crear un clúster de producción dedicado junto con un clúster independiente para los entornos de desarrollo y pruebas. Use el aislamiento lógico para separar los entornos dentro del clúster de desarrollo y pruebas. Los servicios implementados en el clúster de desarrollo y pruebas nunca deben tener acceso a almacenes de datos que contengan datos empresariales.

Para aplicar el aislamiento dentro de un clúster, siga estos pasos:

  • Espacios de nombres: use espacios de nombres de Kubernetes para separar lógicamente entornos (por ejemplo, dev, staging, qa).
  • Directivas de red: aplique directivas de red de Kubernetes para denegar la comunicación entre pods entre espacios de nombres.
  • Cuotas de recursos: aplique cuotas de recursos por espacio de nombres para evitar problemas ruidosos y vecinos en clústeres compartidos.
  • Microsoft Entra ID integración: combine Microsoft Entra ID autenticación con RBAC de Kubernetes y Microsoft Entra ID para controlar qué usuarios y grupos de Microsoft Entra pueden acceder a cada espacio de nombres.

Autenticación y autorización

Use la autenticación sin secreto siempre que sea posible, tanto para las canalizaciones que implementan los microservicios como para las cargas de trabajo que implementan esas canalizaciones:

  • Federación de identidades de carga de trabajo para canalizaciones: para Azure Pipelines, use una conexión de servicio de federación de identidad de carga de trabajo para autenticarse en Azure sin almacenar secretos de entidad de servicio de larga duración. Para Acciones de GitHub, configure OIDC para lograr la misma autenticación sin secretos.
  • Id. de carga de trabajo de Microsoft Entra para cargas de trabajo implementadas: configure los microservicios que implementa la canalización para usar Id. de carga de trabajo de Microsoft Entra en lugar de insertar credenciales a través de manifiestos, valores de Helm o secretos de Kubernetes. El identificador de carga de trabajo federa las cuentas de servicio de Kubernetes con Microsoft Entra ID para que los pods se puedan autenticar en Azure servicios (como Azure Key Vault, Container Registry o Azure SQL) sin que la canalización administre ningún secreto.

Administración de secretos

Nunca inserte secretos (cadenas de conexión, claves de API, contraseñas de base de datos) directamente en código fuente, Dockerfiles, archivos de valores de Helm o definiciones de canalización. En lugar de:

Importante

Evite almacenar credenciales de larga duración (secretos de cliente, certificados o contraseñas) en variables de canalización, variables de entorno o secretos de Kubernetes. En su lugar, use identidades administradas y credenciales federadas para reducir la carga de rotación de credenciales y la superficie expuesta a ataques.

Proceso de construcción

Cuando sea posible, empaquete el proceso de compilación en un contenedor de Docker. Esta configuración permite compilar artefactos de código mediante Docker sin configurar un entorno de compilación en cada máquina de compilación. Un proceso de compilación mediante contenedores simplifica el escalado horizontal de la canalización de integración continua (CI) al agregar nuevos agentes de compilación. Además, cualquier desarrollador del equipo puede compilar el código ejecutando el contenedor de compilación.

Mediante el uso de compilaciones de varias fases en Docker, puede definir el entorno de compilación y la imagen en tiempo de ejecución en un único Dockerfile. Por ejemplo, el siguiente Dockerfile compila una aplicación de .NET 10:

FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
USER app
WORKDIR /app
EXPOSE 8080

FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src/Fabrikam.Workflow.Service

COPY Fabrikam.Workflow.Service/Fabrikam.Workflow.Service.csproj .
RUN dotnet restore Fabrikam.Workflow.Service.csproj

COPY Fabrikam.Workflow.Service/. .
RUN dotnet build Fabrikam.Workflow.Service.csproj -c Release -o /app/build --no-restore

FROM build AS testrunner
WORKDIR /src/tests

COPY Fabrikam.Workflow.Service.Tests/*.csproj .
RUN dotnet restore Fabrikam.Workflow.Service.Tests.csproj

COPY Fabrikam.Workflow.Service.Tests/. .
ENTRYPOINT ["dotnet", "test", "--logger:trx"]

FROM build AS publish
RUN dotnet publish Fabrikam.Workflow.Service.csproj -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Fabrikam.Workflow.Service.dll"]

Este Dockerfile define varias fases de compilación. Observe que la fase denominada usa la imagen en tiempo de ejecución de .NET 10 ASP.NET, mientras que la fase denominada basebuild usa el SDK completo de .NET 10. La build fase compila el proyecto de .NET. No obstante, el contenedor final en tiempo de ejecución se crea a partir de base, que solo contiene el tiempo de ejecución y es significativamente menor que la imagen completa del SDK.

Importante

A partir de .NET 8, las imágenes de contenedor de .NET basadas en Linux oficiales incluyen un usuario no raíz llamado app. La USER app instrucción del Dockerfile ejecuta el contenedor como este usuario sin privilegios, siguiendo el principio de privilegios mínimos. ASP.NET Core las imágenes de contenedor también cambiaron su puerto de escucha predeterminado de 80 a 8080.

Construcción de un Test Runner

Otro procedimiento recomendado es ejecutar pruebas unitarias en el contenedor. Por ejemplo, el código siguiente muestra parte de un Dockerfile que compila un ejecutor de pruebas:

FROM build AS testrunner
WORKDIR /src/tests

COPY Fabrikam.Workflow.Service.Tests/*.csproj .
RUN dotnet restore Fabrikam.Workflow.Service.Tests.csproj

COPY Fabrikam.Workflow.Service.Tests/. .
ENTRYPOINT ["dotnet", "test", "--logger:trx"]

Un desarrollador puede usar este Dockerfile para ejecutar las pruebas localmente:

docker build . -t delivery-test:1 --target=testrunner
docker run delivery-test:1

El pipeline de CI también debe ejecutar las pruebas como parte del paso de verificación del build.

Este archivo usa el comando docker ENTRYPOINT , no el comando docker RUN , para ejecutar las pruebas.

  • Si usa el comando RUN, las pruebas se ejecutan cada vez que se compila la imagen. Si usa ENTRYPOINT, las pruebas se participarán. Se ejecutan únicamente cuando se apunta explícitamente a la fase testrunner.
  • Una prueba con errores no hace que se produzca un error en el comando Docker build. Este comportamiento permite distinguir los errores de compilación del contenedor de los errores de prueba.
  • Los resultados de las pruebas se pueden guardar en un volumen montado.

Mejores prácticas de contenedores

Estos son otros procedimientos recomendados que se deben tener en cuenta para los contenedores:

  • Defina convenciones de toda la organización para etiquetas de contenedor, control de versiones y convenciones de nomenclatura para los recursos implementados en el clúster (por ejemplo, pods y servicios). El uso de estas convenciones puede facilitar el diagnóstico de problemas de implementación.
  • Durante el ciclo de desarrollo y prueba, el proceso de CI/CD compila muchas imágenes de contenedor. Solo algunas de esas imágenes son candidatas para lanzamiento, y solo algunas de esas candidatas de lanzamiento se promueven a producción. Tenga una estrategia clara de control de versiones para que sepa qué imágenes se implementan actualmente en producción y puede revertir fácilmente a una versión anterior si es necesario.
  • Implemente siempre etiquetas de versión de contenedor específicas, no latest.
  • Use espacios de nombres en Container Registry para aislar las imágenes aprobadas para producción de imágenes que todavía se están probando. No mueva una imagen al espacio de nombres de producción hasta que esté listo para implementarla en producción. La combinación de esta práctica con el control de versiones semánticos de imágenes de contenedor puede reducir las posibilidades de implementar accidentalmente una versión que no está aprobada para su lanzamiento.
  • Siga el principio de privilegios mínimos mediante la ejecución de contenedores como un usuario sin privilegios. En Kubernetes, use los estándares de seguridad de pod con la admisión de seguridad de pod (que reemplazó las directivas de seguridad de pod en desuso en Kubernetes 1.25) para aplicar restricciones como impedir que los contenedores se ejecuten como raíz. Use el restricted perfil para cargas de trabajo de producción.
  • Use imágenes base mínimas o sin distribución (por ejemplo, imágenes basadas en Alpine, Azure imágenes base o sin distribución de Linux oimágenes .NET chiseadas) para reducir la superficie expuesta a ataques de las imágenes de contenedor.
  • En el caso de los registros Premium, configure una directiva de retención de Container Registry para eliminar manifiestos sin etiquetar. Para purgar etiquetas por edad o nombre, programe una tarea de Container Registry que ejecute acr purge. Conserve las imágenes a las que hacen referencia las implementaciones activas y los planes de reversión.

Gráficos de Helm

Considere el uso de Helm para administrar la creación e implementación de servicios. Las siguientes características de Helm admiten una canalización de CI/CD:

  • A menudo, varios objetos de Kubernetes definen un solo microservicio. Helm permite empaquetar estos objetos en un único gráfico de Helm.
  • Puede implementar un gráfico mediante un único comando de Helm en lugar de una serie de comandos kubectl.
  • Los gráficos tienen versiones explícitas. Use Helm para publicar una versión, ver versiones y revertir a una versión anterior. Helm usa el control de versiones semántico para realizar un seguimiento de las actualizaciones y las revisiones.
  • Los gráficos de Helm usan plantillas para evitar la duplicación de información, como etiquetas y selectores, en muchos archivos.
  • Helm puede administrar dependencias entre gráficos.
  • Puede almacenar gráficos en un repositorio de Helm, como Container Registry, e integrarlos en la canalización de compilación.

Para más información, consulte Uso de Container Registry como repositorio de Helm para los gráficos de aplicaciones.

Un único microservicio puede requerir varios archivos de configuración de Kubernetes. Para actualizar un servicio, es posible que tenga que editar todos estos archivos para actualizar los selectores, las etiquetas y las etiquetas de imagen. Helm trata estos archivos como un único paquete denominado gráfico y facilita la actualización de los archivos YAML mediante variables. Helm usa un lenguaje de plantilla (basado en plantillas de Go) que permite escribir archivos de configuración yaML con parámetros.

Por ejemplo, a continuación se muestra una parte de un archivo YAML que define una implementación:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "package.fullname" . | replace "." "" }}
  labels:
    app.kubernetes.io/name: {{ include "package.name" . }}
    app.kubernetes.io/instance: {{ .Release.Name }}
  annotations:
    kubernetes.io/change-cause: {{ .Values.reason }}

...

spec:
  template:
    spec:
      containers:
      - name: &package-container_name fabrikam-package
        image: {{ .Values.dockerregistry }}/{{ .Values.image.repository }}:{{ .Values.image.tag }}
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        env:
        - name: LOG_LEVEL
          value: {{ .Values.log.level }}

Puede ver que el nombre de implementación, las etiquetas y la especificación de contenedor usan todos los parámetros de plantilla, que se proporcionan en el momento de la implementación. Por ejemplo, desde la línea de comandos:

helm install <release-name> oci://<registry>/<repository>/<package-chart-name> --version <desiredVersion> \
     --set image.tag=0.1.0 \
     --set image.repository=package \
     --set dockerregistry=$ACR_SERVER \
     --namespace backend

Aunque una canalización de CI/CD puede instalar un gráfico directamente en Kubernetes, cree un archivo de gráficos (archivo .tgz) e inserte el gráfico en un repositorio de Helm como Container Registry. Para obtener más información, consulte Empaquetar e implementar gráficos de Helm (tarea HelmDeploy).

Revisions

Los gráficos de Helm siempre tienen un número de versión que debe usar el control de versiones semántico. Un gráfico también puede tener un elemento appVersion. Este campo es opcional y no es necesario estar relacionado con la versión del gráfico. Es posible que algunos equipos quieran versionar las aplicaciones por separado de las actualizaciones de los gráficos. Un enfoque más sencillo es usar un número de versión, por lo que hay una relación 1:1 entre la versión del gráfico y la versión de la aplicación. De este modo, puede almacenar un gráfico por versión e implementar fácilmente la versión deseada:

helm install <package-chart-name> --version <desiredVersion>

Otro procedimiento recomendado es proporcionar una anotación de causa del cambio en la plantilla de implementación:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "delivery.fullname" . | replace "." "" }}
  labels:
     ...
  annotations:
    kubernetes.io/change-cause: {{ .Values.reason }}

Esta anotación permite ver el campo de causa de cambios para cada revisión mediante el kubectl rollout history comando . En el ejemplo anterior, la causa del cambio se proporciona como parámetro de gráfico de Helm.

kubectl rollout history deployments/delivery-v010 -n backend
deployment.apps/delivery-v010
REVISION  CHANGE-CAUSE
1         Initial deployment

También puede usar el comando helm list para ver el historial de revisiones:

helm list -n backend
NAME              NAMESPACE   REVISION    UPDATED                                 STATUS      CHART               APP VERSION
delivery-v0.1.0   backend     1           2024-04-07 00:25:30.000000 +0000 UTC    deployed    delivery-v0.1.0     v0.1.0

Azure Pipelines

Azure Pipelines, un servicio en Azure DevOps, tiene dos tipos de canalización: canalizaciones de compilación y canalizaciones de versión. La canalización de compilación ejecuta el proceso de CI y crea artefactos de compilación. En el caso de una arquitectura de microservicios en Kubernetes, estos artefactos son las imágenes de contenedor y los gráficos de Helm que definen cada microservicio. La canalización de versión ejecuta el proceso de CD que implementa un microservicio en un clúster.

Según el flujo de CI descrito anteriormente en este artículo, una canalización de compilación puede constar de las siguientes tareas:

  1. Compile el contenedor del ejecutor de pruebas mediante la Docker tarea .
  2. Ejecute las pruebas invocando docker run en el contenedor del ejecutor de pruebas mediante la Docker tarea .
  3. Publique los resultados de la prueba mediante la PublishTestResults tarea . Para obtener más información, consulte Compilación de una imagen.
  4. Ejecute SAST en el código fuente.
  5. Compile el contenedor en tiempo de ejecución mediante local docker build y la Docker tarea o mediante compilaciones de Container Registry y la AzureCLI tarea. Genere una lista de materiales de software (SBOM) para la imagen, por ejemplo, mediante el uso de la herramienta SBOM de Microsoft y publíquela como un artefacto de canalización asociado al resumen de imagen o adjunte a la imagen en Container Registry.
  6. Ejecute el examen de vulnerabilidades de la imagen de contenedor (por ejemplo, mediante Microsoft Defender para contenedores o una herramienta que no sea de Microsoft, como Trivy) para detectar vulnerabilidades conocidas antes de publicar la imagen.
  7. Inserte la imagen de contenedor en Container Registry (u otro registro de contenedor) mediante la Docker tarea o AzureCLI .
  8. Firme la imagen insertada por síntesis inmutable para garantizar su integridad y autenticidad. Para Azure Pipelines, siga las instrucciones de firma de notación.
  9. Empaquetar el gráfico de Helm mediante la HelmDeploy tarea .
  10. Inserte el paquete de Helm en Container Registry (u otro repositorio de Helm) mediante la HelmDeploy tarea .

La salida de la canalización de CI es una imagen de contenedor lista para producción y un gráfico de Helm actualizado para el microservicio. En este punto, el proceso de despliegue puede tomar el control. Hay una canalización de versión única para cada microservicio. La pipeline de lanzamiento está configurada para ser desencadenada por la pipeline de CI que publicó el artefacto. Esta canalización le permite implementar cada microservicio de forma independiente. La pipeline de lanzamiento realiza los siguientes pasos:

  1. Implementar el gráfico de Helm en entornos de desarrollo, control de calidad y ensayo. Puede usar el helm upgrade comando con la --install marca para admitir la primera instalación y las actualizaciones posteriores.
  2. Esperar que un aprobador apruebe o rechace la implementación.
  3. Vuelva a etiquetar la imagen de contenedor para su lanzamiento.
  4. Enviar la etiqueta de lanzamiento al registro de contenedor.
  5. Implementar el gráfico de Helm en el clúster de producción. Use La ratificación con Azure Policy para validar firmas de imagen durante la admisión y configurar por separado una directiva de imágenes permitidas para restringir las imágenes a registros de confianza.

Nota:

Para permitir que AKS extraiga imágenes de Container Registry sin secretos de extracción de imágenes independientes, use la integración de AKS aContainer-Registry para un registro que use RBAC para todo el registro. En el caso de un registro habilitado para ABAC, esta integración no se admite. En su lugar, asigne el Container Registry Repository Reader rol a la identidad administrada de kubelet del clúster.

Para obtener más información sobre la creación de un flujo de trabajo de versiones, consulte Flujos de trabajo de versiones, versiones de borrador y opciones de versiones.

En el diagrama siguiente se muestra el proceso de CI/CD de un extremo a otro que se describe en este artículo:

Diagrama de la canalización de CI/CD de un extremo a otro.

En el diagrama se muestra la canalización completa de CI/CD desde una confirmación del desarrollador a través de la implementación de producción. A la izquierda, comienza con un desarrollador que inserta una confirmación en un repositorio de Git. El repositorio de Git desencadena la primera canalización de CI. La canalización de CI contiene seis pasos secuenciales: Código de compilación, Ejecución de pruebas unitarias, Imagen de compilación, Imagen de inserción, Paquete de Helm e Inserción de gráfico. Cada uno de los tres primeros pasos tiene un cuadro de salida correspondiente a su derecha: El código de compilación genera artefactos de código, Ejecutar pruebas unitarias genera resultados de prueba y la imagen de compilación genera una imagen de contenedor. El paso Insertar imagen inserta la imagen en Container Registry. El paso del paquete de Helm genera un archivo de archivo de gráfico. El paso Insertar gráfico inserta el gráfico en un repositorio de Helm. Una segunda canalización de CI está por debajo de la primera. Contiene cinco pasos secuenciales: Implementar en QA, Pruebas de integración, Imagen de etiquetar, Insertar imagen e Implementar en producción. En el paso Implementar en QA, una línea etiquetada como actualización de Helm conduce a un clúster de Kubernetes con la etiqueta test/QA cluster. A la izquierda, debajo del desarrollador, una línea conduce desde un icono del aprobador de QA al paso Implementar en producción. Esta línea está etiquetada como aprobado. En el paso Implementar en producción, una línea etiquetada como Actualización de Helm conduce a un segundo icono de clúster de Kubernetes con la etiqueta clúster de producción.

Acciones de GitHub alternativa

Si el equipo usa GitHub para el control de código fuente, Acciones de GitHub proporciona una plataforma de CI/CD equivalente. Además de los flujos de trabajo de inicio y la autenticación de OIDC que se han indicado anteriormente, tenga en cuenta estas funcionalidades específicas de GitHub al dirigirse a AKS:

  • Entornos y reglas de protección. Si el plan de GitHub y la visibilidad del repositorio los admiten, use GitHub entornos con revisores necesarios, temporizadores de espera y ramas de implementación para implementar puertas de aprobación.
  • Examen de contenedores. Use Acciones de GitHub acciones de Marketplace para Trivy, Microsoft Defender para DevOps o herramientas similares para el examen de imágenes de contenedor directamente en el flujo de trabajo.

Observabilidad y supervisión

Implemente la observabilidad en toda la canalización de CI/CD y el entorno de tiempo de ejecución:

  • Supervisión de canalizaciones. Realice un seguimiento de las duraciones de compilación, las tasas de superación de pruebas, la frecuencia de implementación y las tasas de error. Azure DevOps proporciona análisis integrados. Acciones de GitHub puede usar paneles que no Microsoft.
  • Supervisión en tiempo de ejecución. Use Azure Monitor servicio administrado para Prometheus y Azure Managed Grafana para supervisar las métricas de estado y carga de trabajo del clúster de AKS.
  • Telemetría de la aplicación. Instrumente los microservicios con Azure Monitor Application Insights para el seguimiento distribuido, el registro de solicitudes y el seguimiento de dependencias.
  • Alertas. Configure alertas para errores de implementación, reinicios de pods, altas tasas de errores y saturación de recursos para permitir una respuesta rápida a incidentes.

alineación de Well-Architected Framework

Al diseñar la canalización de CI/CD para microservicios en Kubernetes, tenga en cuenta los pilares de Azure Well-Architected Framework:

Fundamento Considerations
Reliability Estrategias de reversión automatizadas, sondeos de estado en implementaciones, estrategias de versión azul-verde o controlado, presupuestos de interrupciones de pods.
Security Autenticación sin secretos (Id. de carga de trabajo, OIDC), firma de imágenes, seguridad de la cadena de suministro, RBAC con privilegios mínimos, directivas de red.
Optimización de costos Los agentes de compilación de ajuste de tamaño correcto, mediante ejecutores autohospedados efímeros, la implementación de directivas de retención de imágenes de Container Registry y el uso de grupos de nodos de acceso puntual solo para cargas de trabajo no de producción tolerantes a interrupciones.
Excelencia operativa GitOps para implementaciones declarativas, infraestructura como código, canalización como código (YAML), observabilidad y automatización de runbook.
Eficiencia del rendimiento Fases de canalización paralelas, almacenamiento en caché de compilación (almacenamiento en caché de capas de Docker, almacenamiento en caché de dependencias), escalado automático horizontal de pods.

Contributors

Microsoft mantiene este artículo. Los siguientes colaboradores escribieron este artículo.

Autor principal:

  • Ray Kao | Ingeniero principal de soluciones

Para ver los perfiles no públicos de LinkedIn, inicie sesión en LinkedIn.

Pasos siguientes