Saltar a contenido

CI/CD App Service

Para desplegar una aplicación web simple se puede hacer fácilmente en forma de contenedor Docker en un Azure App Service.

Pipeline YAML CI/CD

A continuación se muestra un ejemplo de una app con Streamlit desplegada mediante una pipeline en Azure DevOps que incluye el proceso de CI/CD:
- CI: Construcción de una imagen de Docker a partir de Dockerfile personalizado del proyecto, y push a un Azure Container Registry.
- CD: Despliegue de la imagen en un Azure App Service for Containers.

trigger: #(1)!
  - main
  - develop

pool: #(2)!
  vmImage: ubuntu-latest

stages: #(3)!
  - stage: Build_Push_Image
    jobs:
      - job:
        steps:
          - task: DownloadSecureFile@1 #(4)!
            displayName: "Download secrets secure file"
            name: "SecretsAIPlayground"
            inputs:
              secureFile: "secrets-aiplayground.toml"
          - script: | #(5)!
              cp "$(SecretsAIPlayground.secureFilePath)" "$(Build.SourcesDirectory)/.streamlit/secrets.toml"
            displayName: "Copy and rename secure file to .streamlit folder"
          - task: Docker@2 #(6)!
            displayName: "Build & push to AAA ACR"
            inputs:
              containerRegistry: "SogetiAAA Docker Registry"
              repository: "sogeti.aiplayground.app"
              command: "buildAndPush"
              Dockerfile: "**/Dockerfile"
              tags: | #(7)!
                $(Build.BuildId)
                $(Build.SourceBranchName)
  - stage: Deploy_App_Service_For_Containers
    jobs:
      - job:
        steps:
          - task: PowerShell@2 #(8)!
            inputs:
              targetType: "inline"
              script: |
                $envName = If ("$(Build.SourceBranchName)" -eq "main") {"p"} Else {"d"}
                Write-Host "##vso[task.setvariable variable=envName;]$envName"
          - task: AzureRmWebAppDeployment@4 #(9)!
            inputs:
              ConnectionType: "AzureRM"
              azureSubscription: "SogetiAAASPN"
              appType: "webAppContainer"
              WebAppName: "sogeti-app-playground-$(envName)"
              DockerNamespace: "sogetiacranalytics.azurecr.io"
              DockerRepository: "sogeti.aiplayground.app"
              DockerImageTag: "$(Build.SourceBranchName)"
              AppSettings: "-WEBSITES_PORT 8501" #(10)!
  1. Ejecución automática de la pipeline por cada push en las ramas seleccionadas, ya que la pipeline se mantiene como código YAML en el repositorio del proyecto para todos sus ramas.
  2. Se recomienda el uso de Ubuntu como SO en el Agent de la pipeline por su eficiencia.
  3. Definición de 2 stages para los respectivos procesos de CI y CD y poder evaluar mejor los resultados de la ejecución visualmente en Azure DevOps.
  4. (Opcional) Si el proyecto requiere inyeción de variables o ficheros de configuración, pueden ser descargados de forma segura (ocultos) de un fichero seguro previamente subido a Azure DevOps Library (Azure Pipelines).
  5. (Opcional) El fichero de configuración puede ser copiado a la estructura del proyecto mediante referencia a él por el nombre especificado en la tarea anterior.
  6. Build y push de la imagen al Azure Container Registry conectado mediante Service Connection (previamente creado en la configuración del proyecto en Azure DevOps).
  7. Se tagean las imágenes siempre con el id de la build para mantener trazabilidad histórica y en este caso con el nombre de la rama, que corresponderá a los entornos de la app.
  8. Script inline de PowerShell para la creación de una variable en tiempo de ejecución de la pipeline que determinará el nombre del entorno de la App Service a partir del nombre de la rama de la build actual.
  9. Despliegue de la imagen como contenedor en una App Service (Web App) for Containers. La conexión a la suscripción de Azure se hace conectado mediante Service Connection de ARM(previamente creado en la configuración del proyecto en Azure DevOps). Nota: El Resource Group, App Service Plan y App Service deben existir previamente, ya que esta tarea sólo despliega la imagen en el servicio, no lo crea de cero.
  10. Puerto externo expuesto en el App Service para acceder al contenedor desde el exterior.

IMPORTANTE:

Los App Service for Containers exponen al exterior los puertos 80/443 por defecto. En caso de querer acceder a un servicio (contenedor) que se levanta en un puerto personalizado, expuesto o no en su Dockerfile mediante la sentencia EXPOSE, éste puerto debería indicarse al app service mediante la variable de configuración WEBSITES_PORT o PORT.

En este caso, la app de Streamlit arranca por defecto en el puerto 8501, también expuesto con EXPOSE 8501 en el Dockerfile del proyecto. Sin embargo, la app no es accesible desde la URL del App Service, hasta que no se inyecta la variable de configuración WEBSITES_PORT con el puerto 8501.