Compartir vía


Tutorial: uso de una estrategia de implementación de valor controlado para implementaciones de Kubernetes.

Azure DevOps Services | Azure DevOps Server 2022

En esta guía paso a paso se explica cómo utilizar la tarea de manifiesto de Kubernetes con la estrategia canary. Una estrategia de implementación de valor controlado implementa nuevas versiones de una aplicación junto a versiones estables de producción.

Use el flujo de trabajo asociado para implementar el código y comparar las implementaciones de aplicaciones de línea base y de valor controlado. En función de la evaluación, decida si va a promover o rechazar la implementación de valor controlado.

En este tutorial se usan Docker Registry y las conexiones de servicio de Azure Resource Manager para conectarse a los recursos de Azure. En el caso de un clúster privado de Azure Kubernetes Service (AKS) o un clúster que tiene cuentas locales deshabilitadas, una conexión de servicio de Azure Resource Manager es la mejor manera de conectarse.

Requisitos previos

Archivos del repositorio de GitHub

El repositorio de GitHub contiene los siguientes archivos:

Archivo Descripción
./app/app.py Un servidor web simple basado en Flask. El archivo configura un contador personalizado para el número de respuestas buenas y malas, en función del valor de la variable success_rate.
./app/Dockerfile Se utiliza para construir la imagen con cada cambio en app.py. Cada cambio desencadena la canalización de compilación para compilar la imagen e insertarla en el registro de contenedor.
./manifests/deployment.yml Contiene la especificación de la carga de trabajo de implementación sampleapp correspondiente a la imagen publicada. Este archivo de manifiesto se utiliza para la versión estable del objeto de implementación y para obtener las variantes de línea base y valor controlado de las cargas de trabajo.
./manifests/service.yml Crea el servicio sampleapp. Este servicio enruta las solicitudes a los pods activados por las implementaciones estables, de línea base y de valor controlado.
./misc/fortio.yml Configura una implementación de fortio. Esta implementación es una herramienta de prueba de carga que envía un flujo de solicitudes al servicio sampleapp implementado. El flujo de solicitud se enruta a los pods de las tres implementaciones: estable, de línea base y de valor controlado.

Creación de conexiones de servicio

  1. En el proyecto en Azure DevOps, vaya a Configuración del proyecto>Canalizaciones>Conexiones de servicio.
  2. Cree una conexión del servicio Docker Registry denominada azure-pipelines-canary-acr que esté asociada a la instancia de Azure Container Registry.
  3. Cree una Conexión de servicio de Azure Resource Manager con la identidad de carga de trabajo denominada azure-pipelines-canary-k8s para el grupo de recursos.

Adición de la fase de compilación

  1. En el proyecto de Azure DevOps, vaya a Canalizaciones>Crear canalización o Nueva canalización.

  2. Seleccione GitHub para la ubicación del código y seleccione el repositorio azure-pipelines-canary-k8s bifurcado.

  3. En la pestaña Configurar, elija Canalización inicial.

  4. En la pestaña Revisar, reemplace el YAML de la canalización con el código siguiente.

    trigger:
    - main
    
    pool:
      vmImage: ubuntu-latest
    
    variables:
      imageName: azure-pipelines-canary-k8s # name of ACR image
      dockerRegistryServiceConnection: azure-pipelines-canary-acr # name of ACR service connection
      imageRepository: 'azure-pipelines-canary-k8s' # name of image repository
      containerRegistry: example.azurecr.io # name of Azure container registry
      tag: '$(Build.BuildId)'
    
    stages:
    - stage: Build
      displayName: Build stage
      jobs:  
      - job: Build
        displayName: Build
        pool:
          vmImage: ubuntu-latest
        steps:
        - task: Docker@2
          displayName: Build and push image
          inputs:
            containerRegistry: $(dockerRegistryServiceConnection)
            repository: $(imageName)
            command: buildAndPush
            Dockerfile: app/Dockerfile
            tags: |
              $(tag)
    

    Si la conexión del servicio de registro de Docker que ha creado está asociada a un registro de contenedor con nombre example.azurecr.io, la imagen se establece en example.azurecr.io/azure-pipelines-canary-k8s:$(Build.BuildId).

  5. Seleccione Guardar y ejecutar y asegúrese de que el trabajo se ejecuta correctamente.

Edición del archivo de manifiesto

En la bifurcación del repositorio, edite manifests/deployment.yml para reemplazar <foobar> por la dirección URL del registro de contenedor, por ejemplo example.azurecr.io/azure-pipelines-canary-k8s.

Configurar la implementación continua

Ahora, configure la implementación continua, implemente la fase de valor controlado y promueva o rechace el valor controlado a través de la aprobación manual.

Creación de un entorno

Puede realizar la implementación con YAML o clásico.

  1. En el proyecto de Azure DevOps, vaya a Canalizaciones>Entornos y seleccione Crear entorno o Nuevo entorno.
  2. En la primera pantalla de Nuevo entorno, escriba akscanary en Nombre, seleccione Kubernetes en Recurso y seleccione Siguiente.
  3. Rellene la pantalla Recursos de Kubernetes de la siguiente manera:
    • Proveedor: seleccione Azure Kubernetes Service.
    • Suscripción de Azure: seleccione su suscripción de Azure.
    • Clúster: Seleccione el clúster de AKS.
    • Espacio de nombres: seleccione Nuevo y escriba canarydemo.
  4. Seleccione Validar y crear.

Adición de la fase de valor controlado

  1. Vaya a Canalizaciones, seleccione la canalización que ha creado y seleccione Editar.

  2. Reemplace todo el YAML de la canalización con el siguiente código.

    Este código cambia el paso Docker@2 que ejecutó anteriormente para usar una fase y agrega dos pasos más para copiar los manifiestos y directorios misc como artefactos para las fases consecutivas que se van a usar.

    El código también mueve algunos valores a variables para facilitar el uso más adelante en la canalización. En la variable containerRegistry, sustituya <example> por el nombre de su registro de contenedor.

    trigger:
    - main
    
    pool:
      vmImage: ubuntu-latest
    
    variables:
      imageName: azure-pipelines-canary-k8s
      dockerRegistryServiceConnection: azure-pipelines-canary-acr
      imageRepository: 'azure-pipelines-canary-k8s'
      containerRegistry: <example>.azurecr.io
      tag: '$(Build.BuildId)'
    
    stages:
    - stage: Build
      displayName: Build stage
      jobs:  
      - job: Build
        displayName: Build
        pool:
          vmImage: ubuntu-latest
        steps:
        - task: Docker@2
          displayName: Build and push image
          inputs:
            containerRegistry: $(dockerRegistryServiceConnection)
            repository: $(imageName)
            command: buildAndPush
            Dockerfile: app/Dockerfile
            tags: |
              $(tag)
    
        - publish: manifests
          artifact: manifests
    
        - publish: misc
          artifact: misc
    
  3. Agregue otra fase al final del archivo YAML para implementar la versión canary. Reemplace los valores my-resource-group y my-aks-cluster por el grupo de recursos y el nombre del clúster de Azure Kubernetes Service.

    trigger:
    - main
    
    pool:
      vmImage: ubuntu-latest
    
    variables:
      imageName: azure-pipelines-canary-k8s
      dockerRegistryServiceConnection: azure-pipelines-canary-acr
      imageRepository: 'azure-pipelines-canary-k8s'
      containerRegistry: yourcontainerregistry.azurecr.io #update with container registry
      tag: '$(Build.BuildId)'
    
    stages:
    - stage: Build
      displayName: Build stage
      jobs:  
      - job: Build
        displayName: Build
        pool:
          vmImage: ubuntu-latest
        steps:
        - task: Docker@2
          displayName: Build and push image
          inputs:
            containerRegistry: $(dockerRegistryServiceConnection)
            repository: $(imageName)
            command: buildAndPush
            Dockerfile: app/Dockerfile
            tags: |
              $(tag)
    
        - publish: manifests
          artifact: manifests
    
        - publish: misc
          artifact: misc
    
    - stage: DeployCanary
      displayName: Deploy canary
      dependsOn: Build
      condition: succeeded()
    
      jobs:
      - deployment: Deploycanary
        displayName: Deploy canary
        pool:
          vmImage: ubuntu-latest
        environment: 'akscanary'
        strategy:
          runOnce:
            deploy:
              steps:
              - task: KubernetesManifest@1
                displayName: Create Docker Registry Secret
                inputs:
                  action: 'createSecret'
                  connectionType: 'azureResourceManager'
                  azureSubscriptionConnection: 'azure-pipelines-canary-sc'
                  azureResourceGroup: 'my-resource-group'
                  kubernetesCluster: 'my-aks-cluster'
                  secretType: 'dockerRegistry'
                  secretName: 'my-acr-secret'
                  dockerRegistryEndpoint: 'azure-pipelines-canary-acr'
    
              - task: KubernetesManifest@1
                displayName: Deploy to Kubernetes cluster
                inputs:
                  action: 'deploy'
                  connectionType: 'azureResourceManager'
                  azureSubscriptionConnection: 'azure-pipelines-canary-sc'
                  azureResourceGroup: 'my-resource-group'
                  kubernetesCluster: 'my-aks-cluster'
                  strategy: 'canary'
                  percentage: '25'
                  manifests: |
                    $(Pipeline.Workspace)/manifests/deployment.yml
                    $(Pipeline.Workspace)/manifests/service.yml
                  containers: '$(containerRegistry)/$(imageRepository):$(tag)'
                  imagePullSecrets: 'my-acr-secret'
    
              - task: KubernetesManifest@1
                displayName: Deploy Forbio to Kubernetes cluster
                inputs:
                  action: 'deploy'
                  connectionType: 'azureResourceManager'
                  azureSubscriptionConnection: 'azure-pipelines-canary-sc'
                  azureResourceGroup: 'my-resource-group'
                  kubernetesCluster: 'my-aks-cluster'
                  manifests: '$(Pipeline.Workspace)/misc/*'
    
  4. Seleccione Validar y guardar y guarde la canalización directamente en la rama principal.

Adición de aprobación manual para promover o rechazar la implementación de valor controlado

Puede intervenir manualmente con YAML o Clásico.

  1. Cree un nuevo entorno de Kubernetes denominado akspromote.
  2. Abra el nuevo entorno akspromote en la lista de entornos y seleccione Aprobaciones en la pestaña Aprobaciones y comprobaciones.
  3. En la pantalla Aprobaciones, agregue su propia cuenta de usuario en Aprobadores.
  4. Expanda Avanzado y asegúrese de que la opción Permitir que los aprobadores aprueben sus propias ejecuciones esté seleccionada.
  5. Seleccione Crear.

Adición de fases de promoción y rechazo a la canalización

  1. Vaya a Canalizaciones, seleccione la canalización que ha creado y seleccione Editar.

  2. Agregue la siguiente fase PromoteRejectCanary al final del archivo YAML que promueve los cambios.

    - stage: PromoteRejectCanary
      displayName: Promote or Reject canary
      dependsOn: DeployCanary
      condition: succeeded()
    
      jobs:
      - deployment: PromoteCanary
        displayName: Promote Canary
        pool: 
          vmImage: ubuntu-latest
        environment: 'akspromote'
        strategy:
          runOnce:
            deploy:
              steps:      
              - task: KubernetesManifest@1
                displayName: Create Docker Registry Secret for akspromote
                inputs:
                  action: 'createSecret'
                  connectionType: 'azureResourceManager'
                  azureSubscriptionConnection: 'azure-pipelines-canary-sc'
                  azureResourceGroup: 'my-resource-group'
                  kubernetesCluster: 'my-aks-cluster'
                  secretType: 'dockerRegistry'
                  secretName: 'my-acr-secret'
                  dockerRegistryEndpoint: 'azure-pipelines-canary-acr'
    
              - task: KubernetesManifest@1
                displayName: promote canary
                inputs:
                  action: 'promote'
                  connectionType: 'azureResourceManager'
                  azureSubscriptionConnection: 'azure-pipelines-canary-sc'
                  azureResourceGroup: 'my-resource-group'
                  kubernetesCluster: 'my-aks-cluster'
                  strategy: 'canary'
                  manifests: '$(Pipeline.Workspace)/manifests/*'
                  containers: '$(containerRegistry)/$(imageRepository):$(tag)'
                  imagePullSecrets: 'my-acr-secret'
        ```
    
    
  3. Agregue la siguiente fase RejectCanary al final del archivo que revierte los cambios.

    - stage: RejectCanary
      displayName: Reject canary
      dependsOn: PromoteRejectCanary
      condition: failed()
    
      jobs:
      - deployment: RejectCanary
        displayName: Reject Canary
        pool: 
          vmImage: ubuntu-latest
        environment: 'akscanary'
        strategy:
          runOnce:
            deploy:
              steps:        
              - task: KubernetesManifest@1
                displayName: Create Docker Registry Secret for reject canary
                inputs:
                  action: 'createSecret'
                  connectionType: 'azureResourceManager'
                  azureSubscriptionConnection: 'azure-pipelines-canary-sc'
                  azureResourceGroup: 'kubernetes-testing'
                  kubernetesCluster: 'my-aks-cluster'
                  secretType: 'dockerRegistry'
                  secretName: 'my-acr-secret'
                  dockerRegistryEndpoint: 'azure-pipelines-canary-acr'    
              - task: KubernetesManifest@1
                displayName: Reject canary deployment
                inputs:
                  action: 'reject'
                  connectionType: 'azureResourceManager'
                  azureSubscriptionConnection: 'azure-pipelines-canary-sc'
                  azureResourceGroup: 'my-resource-group'
                  kubernetesCluster: 'my-aks-cluster'
                  namespace: 'default'
                  strategy: 'canary'
                  manifests: '$(Pipeline.Workspace)/manifests/*'
        ```
    
  4. Seleccione Validar y guardar y guarde la canalización directamente en la rama principal.

Implementación de una versión estable

Para la primera ejecución de la canalización, la versión estable de las cargas de trabajo y sus versiones de línea de base o de valor controlado no existen en el clúster. Implemente una versión estable de la carga de trabajo sampleapp como se indica a continuación.

Puede implementar una versión estable con YAML o Clásico.

  1. En app/app.py, cambie success_rate = 50 por success_rate = 100. Este cambio desencadena la canalización, compilando e insertando la imagen en el registro de contenedor, y también desencadena la fase DeployCanary.
  2. Dado que configuró una aprobación en el entorno akspromote, la versión espera antes de ejecutar esa fase. En la página resumen de la ejecución de compilación, seleccione Revisar y, a continuación, seleccione Aprobar.

Una vez aprobada, la canalización implementa la versión estable de la carga de trabajo sampleapp de manifests/deployment.yml en el espacio de nombres.

Inicio del flujo de trabajo de valor controlado y rechazo de la aprobación

La versión estable de la carga de trabajo sampleapp ahora existe en el clúster. A continuación, realice el siguiente cambio en la aplicación de simulación.

  1. En app/app.py, cambie success_rate = 50 por success_rate = 100. Este cambio desencadena la canalización, compilando e insertando la imagen en el registro de contenedor, y también desencadena la fase DeployCanary.
  2. Dado que configuró una aprobación en el entorno akspromote, la versión espera antes de ejecutar esa fase.
  3. En la página de resumen de la ejecución de compilación, seleccione Revisar y, a continuación, seleccione Rechazar en el cuadro de diálogo posterior. Esto rechaza la implementación.

Una vez rechazada, la canalización impide la implementación de código.

Limpiar

Si no va a seguir usando esta aplicación, elimine el grupo de recursos en Azure Portal y el proyecto de Azure DevOps.