Implementar un modelo CI/CD para la ingesta y ETL hacia ambientes productivos con Azure Datafactory y Azure DevOps.

ESCENARIO:

En el contexto de una aqruitectura de datos LakeHouse se requiere configurar ciclos de vida que permitan que los ETL sean automatizables y promovidos a ambientes superiores a desarrollo.

El propósito de este artículo es diseñar y poner en marcha una estrategia de versionamiento y ciclo de vida CI/CD para azure datafactory.

Se requiere diseñar una modelo que permita promover el código y desarrollo trabajado desde DEV hasta PROD e implementar prácticas CD/CD para el proyecto mediante Azure Datafactory y Azure DevOps.


REQUERIMIENTOS Y PLAN DE ACCIÓN : 


- Existirán 2 entornos de desarrollo y por tanto 2 Azure Datafactory correspondiente a Desarrollo, y Producción.
- El Datafactory correspondiente al entorno de desarrollo estará integrado con GIT a un repositorio de Azure DevOps.
- El flujo para promover desde DEV a PROD debe ser completamente automatizado mediante integración continua y despliegue continuo y sólo podrá ser detenido mediante una aprobación al momento de llevar a PROD.
- Se debe configurar una rama de colaboración para los desarrolladores integrar continuamente el código con ramas feature.
- El pipeline debe publicar el artefacto que se usará para promover a ambientes superiores usando AZ Artifacts.
- Dejar habilitadas las opciones técnicas para establecer un posterior plan de recuperación o backups mediante Azure Artifacts.

ASPECTOS A TENER EN CUENTA:


1. Al usarse 3 ambientes para este proyecto es importante definir la organización mediante suscripciones y/o grupos de recursos.

2. La estrategia de branching para este servicio distatotalmente de las conocidas como GitFlow u otras, puesto que corresponde a una funcionalidad de colaboración explicada más adelante, por tanto se tendrán sólo dos ramas, la de colaboración o develop y la rama master para promover a ambientes superiores.

3. Se utilizará una máquina virtual como Integration Runtime, es importante que este sea un recurso a tener en cuenta a la hora de crear la infraestructura, preferiblemente mediante IaC.

4. Este proyecto será de carácter público, es decir, no tendrá infraestructura privada con puntos de conexión privados o zonas DNS específicas. 

5. Al ser un proyecto de carácter infraestructura no privada se usarán los agentes de despliegue libres de Azure DevOps.


ARQUITECTURA DE DESPLIEGUE 




¡A LA CARGA!

La infraestructura necesaria se puede crear mediante un proyecto de IaC con herramientas como Terraform o Bicep. 

Una vez tengamos el ADF de DEV listo, podremos configurar un repositorio de nuestra organización de AZ DEVOPS.




Para ello vamos al proyecto en devops y creamos un repositorio y una rama develop basada en master que nos funcionará como rama de colaboración.


Configuramos el Datafactory de Desarrollo integrando GIT con el repositorio del proyecto en el repositorio de AZ DEVOPS.



Con esto ya tenemos el ambiente de desarrollo listo para integrar los Linked Services, Integration Runtime, Triggers y crear los data pipelines que los equipos de desarrolladores de datos suelen implementar.

Para este ejemplo crearemos un Linked Service hacia un Key Vault del mismo ambiente de desarrollo, esto lo haremos directamente en la rama develop, mas adelante crearemos la rama feature para implementar los datapipelines.






Al hacer clic en "PUBLISH" veremos que hay un cambio en nuestro repositorio.
Sobre la rama de develop, en adelante rama de colaboración, hay cambios sincronizados con el dataactory del ambiente DEV, además se crea una rama adf_publish donde constantemente se publicará el ARM Template como backup.




El siguiente paso es desarrollar! Ya podemos implementar los datapipelines o canalizaciones de data factory para ingestar o mover los datos, para este ejemplo usaremos elementos muy sencillos, solo para demostrar la efectividad de la promoción entre ambientes, sin embargo hay operaciones más complejas como implementar una fuente mediante una stotrage account o ejecutar un notebook de databricks.

Lo primero que haría el desarrollador es crear la rama feature para implementar sus nuevos desarrollos.




Ahora crearemos un pipeline con algunos elementos.




Para guardar este cambio en la rama recién creada vamos a dejar un elemento de espera con el nombre "Wait_data_devops1". Damos en "VALIDAR" y "SAVE ALL".



Bien, en este punto tenemos ya un ambiente de desarrollo entregado al equipo de DEV DATA, en donde han estado desarrollando algunas canalizaciones para promover a ambientes posteriores.

Para conseguir este objetivo necesitamos continuar con el desarrollo del flujo devops creando un pipeline de integración continua que detecte los cambios en la rama master para promover hacia los datafactories de TEST y PROD respectivamente.


PIPELINE AZURE DATACTORY CI


La función de esta canalización es leer el ARM Template y generar el artefacto o archivos json que se usarán para desplegar en el siguiente ambiente (TEST) y generar la plantilla de parámetros a reemplazar con la herramienta de despliegue de azure devops.

IMPORTANTE: Usaremos una variable llamada packageLocation y otra llamada ADF_DEV_ID referente al ID del ADF de DEV:



    
Crear el feed de azure artifacts y ejecutar el pieline.



Configurar el scope a nivel de proyecto u organización según se necesite.



Otorgar permiso para publicar artefactos al grupo del proyecto, para ello ve al feed que creaste en azure artifacts, clic en el icono de rueda de configuración, añade el permiso de contributor publisher.




A continuación se relaciona el código explicado:



trigger:
develop #rama con cambios aprobados.

pool:
  vmImagewindows-latest

  
variables:
groupdatafactory-vars #Grupo de Variables de Proyecto

#Inicio de Tareas del Pipeline.
# Se requiere paquete package.json para automatizar el publish y generar el ARM template

steps:

# Instalar Node y los paquetes npm referidos en el archivo package.json 
taskNodeTool@0
  inputs:
    versionSpec'18.x'
  displayName'Instalar Node.js'


# Validar y Exportar plantilla ARM
taskNpm@1
  inputs:
    command'install'
    workingDir'$(Build.Repository.LocalPath)/$(packageLocation)' #replace with the package.json folder
    verbosetrue
  displayName'Instalar Paquete npm'

# Validar los recursos de datafactory en el repositorio

taskNpm@1
  inputs:
    command'custom'
    workingDir'$(Build.Repository.LocalPath)/$(packageLocation)' #replace with the package.json folder
    customCommand'run build validate $(Build.Repository.LocalPath)/ /subscriptions/xxxxx-cd4e-xxxx-xxxx-xxxxx/resourceGroups/data-devops-project/providers/Microsoft.DataFactory/factories/adf-data-devops-dev'
  displayName'Validar ARM Template'

# Exportar ARM Template en la ubicación de destino.
taskNpm@1
  inputs:
    command'custom'
    workingDir'$(Build.Repository.LocalPath)/$(packageLocation)' 
    customCommand'run build export $(Build.Repository.LocalPath)/ /subscriptions/xxxxx-cd4e-xxxxx-xxxx-xxxxxx/resourceGroups/data-devops-project/providers/Microsoft.DataFactory/factories/adf-data-devops-dev "ArmTemplate"'
  displayName'Exportar ARM Template'

# Publicar el artefacto localmente. 
taskPublishPipelineArtifact@1
  inputs:
    targetPath'$(Build.Repository.LocalPath)/$(packageLocation)/ArmTemplate' 
    artifact'ArmTemplates'
    publishLocation'pipeline'
  displayName'Publicar artefacto localmente'

#Copiar Archivos
taskCopyFiles@2
  inputs:
    SourceFolder'$(Build.Repository.LocalPath)/$(packageLocation)/ArmTemplate'
    Contents'**'
    TargetFolder'$(Build.ArtifactStagingDirectory)'
  displayName'Copiar Artefacto'

#Publicar artefacto a usar en el pipeline de releaseen AZ Artifacts.
taskUniversalPackages@0
  inputs:
    command'publish'
    publishDirectory'$(Build.ArtifactStagingDirectory)'
    feedsToUsePublish'internal'
    vstsFeedPublish'xxxxxx-9c96-42a9-xxxx-xxxxxxx/xxxxxxx-b5b2-xxx-xxxx-xxxxxxxx'
    vstsFeedPackagePublish'datafactory_artifact'
    versionOption'patch'
    versionPublish'latest'
    packagePublishDescription'Arm Template ADF'
  displayName'Publicar en AZ Artifacts'
    

Ejecuta el pipeline y revisa que se ejecuten todas las tareas:



Verifica que se haya generado el artefacto y se haya pubicado en AZ Artifacts feed:






PIPELINE AZURE DATACTORY CICD AMBIENTE TESTING / PROD


Ahora que tenemos ya el pipeline de CI y el artefacto a desplegar, revisemos el contenido del mismo para empezar a promover a ambientes superiores como test/uat o producción.


Vamos a preparar el pipeline YAML de release a ambientes posteriores, en nuestro caso a producción.
Para ello construiremos una canalización con 2 stages, uno que nos descargue y publique el artefacto a utilizar para el despliegue y asi tenemos un control de lo que se despliega mediante el uso y control de az artifacts y el segundo stage usado para probar y descargar el artefacto, este último stage es el que va a interactuar con la consola de despliegue y usará el Service Connection hacia la suscripción a desplegar.

Preparamos entonces el primer stage:

trigger:
develop

variables:
groupdatafactory-vars

pool:
  vmImageubuntu-latest

stages:
  - stageartifacts
    displayNameDescargar Artefacto y Publicar Localmente
    jobs:
      - job:
        displayNamePreparar y Publicar Artefacto
        steps:
        - taskUniversalPackages@0
          inputs:
            command'download'
            downloadDirectory'$(System.DefaultWorkingDirectory)/artifacts'
            feedsToUse'internal'
            vstsFeed'xxxx-xxx-xxxxx-xxxx-c00404c2ab7f/xxxxxx-b5b2-4686-xxxx-xxxxxxx'
            vstsFeedPackage'xxxxxx-c03c-xxxx-9491-xxxxx'
            vstsPackageVersion'$(artifact_version)'
          displayNameDescargar Artefacto localmente


Verifica que se ejecute con éxito y que publique los archivos necesarios para la parte del despliegue:

Valida el contenido del artefacto en su interior:



En este punto es importante asegurarse de crear el service connection para el despliegue, crear el role assignment para desplegar en la suscripción de azure y crear el grupo de variables en azure devops:


Ahora vamos a preparar la segunda parte o stage 2 en donde vamos a tomar el artefacto y a desplegar en el datafactory que tengamos destinado ya sea con testing o producción, podemos hacer uso de la opción overrite parametros para editarlos en el siguiente orden:

Primero: Ve al ADF de desarrollo y descarga la plantilla de parametros para validarlos.

Alli podrás descargar la plantilla y validar los parametros a sobreescribir y tambien personalizar la configuración de qué parámetros exportar o no a la plantilla de parametros general, por ejemplo clusters de databricks, linked services, etc.


Segundo: Valida los parametros a reemplazar, siempre se incluirá el nombre del RG, el nombre del ADF y los parametros de la platilla exportada: 


En este caso el deber es reemplazar estos valores en el grupo de variables de Prod por los valores de ese ambiente y continuar:


Puedes ir dando control de la versión del artefacto mediante AZ Artifacts y colocando manualmente en la variable artifact_version, de esta manera se reducen errores humanos en lo que vaya hacia producción, también se puede configurar aprobaciones o intervenciones manuales al pipeline en cualquiera de sus jobs :




Asi quedaría la estructura del YAML CI CD hacia ambientes posteriores a Dev.

# Starter pipeline
# Start with a minimal pipeline that you can customize to build and deploy your code.
# Add steps that build, run tests, deploy, and more:
# https://aka.ms/yaml

trigger:
master

variables:
groupdatafactory-vars

pool:
  vmImageubuntu-latest

stages:
  - stageartifacts
    displayNameCompilacion y Preparacion
    jobs:
      - job:
        displayNamePreparar y Publicar Artefacto
        steps:
        - taskUniversalPackages@0
          inputs:
            command'download'
            downloadDirectory'$(System.DefaultWorkingDirectory)/artifacts'
            feedsToUse'internal'
            vstsFeed'xxxxx-xxxx-xxxx-xxxx-xxxxx/xxxxx-b5b2-xxxx-xxxx-xxxxx'
            vstsFeedPackage'xxxxxx-c03c-4712-9491-xxxx'
            vstsPackageVersion'$(artifact_version)'
          displayNameDescargar Artefacto localmente
        

        - taskPublishBuildArtifacts@1
          inputs:
            PathtoPublish'$(System.DefaultWorkingDirectory)/artifacts'
            ArtifactName'drop'
            publishLocation'Container'

          
  - stagedeploy
    dependsOnartifacts
    displayNameDesplegar en ADF PRODUCCION
    jobs:
      - deployment:
        environmentPROD
        strategy:
          runOnce:
            deploy:
              steps:

              - taskUsePythonVersion@0
                displayNameConfigurar version de python
                inputs:
                  versionSpec'3.8'
                  addToPathtrue
                  architecture'x64'
              
              - taskDownloadBuildArtifacts@1
                inputs:
                  buildType'current'
                  downloadType'single'
                  artifactName'drop'
                  downloadPath'$(System.ArtifactsDirectory)/artifacts'
              - taskAzurePowerShell@5
                displayName'Stop Triggers'
                inputs:
                  azureSubscription'sc-data-adf-prod'
                  ScriptPath'$(Agent.BuildDirectory)/drop/PrePostDeploymentScript.ps1'
                  ScriptArguments'-armTemplate "$(Agent.BuildDirectory)/drop/ARMTemplateForFactory.json" -ResourceGroupName $(ResourceGroupName) -DataFactoryName $(factoryNameProd) -predeployment $true -deleteDeployment $false -armTemplateParameters "$(Agent.BuildDirectory)/drop/ARMTemplateParametersForFactory.json" '
                  azurePowerShellVersionLatestVersion
                  pwshtrue
              - taskAzureResourceManagerTemplateDeployment@3
                displayName'Deploy ARM Template'
                inputs:
                  azureResourceManagerConnection'sc-data-adf-prod'
                  subscriptionId'xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx'
                  resourceGroupName'rg_pruebas_adf'
                  location'East US 2'
                  csmFile'$(Agent.BuildDirectory)/drop/ARMTemplateForFactory.json'
                  csmParametersFile'$(Agent.BuildDirectory)/drop/ARMTemplateParametersForFactory.json'
                  overrideParameters'-factoryName $(factoryNameProd)  -kv_data_01_properties_typeProperties_baseUrl $(kv_data_01_Prod)'
                

Revisa la ejecución del pipeline de CI CD que desplegará en producción, este pipeline ejecuta el script que detiene los triggers, la tarea de despliegue de la plantilla ARM, el reemplazo de parametros y el script que inicia nuevamente los triggers y registra el contenido interno del ADF.



Tenemos entonces todo el ciclo de vida de datafactory diseñado, un pipeline CI que escanea, genera el artefacto y lo publica, un almacén privado de AZ Artifacts para controlar y versionar lo que se  autorice en producción, un pipeline de despliegue continuo sobre el cual puede activarse o desactivar acorde con el trigger requerido y en general una plantilla con dos stages para agregar las tareas que se requieran en entornos reales, como las aprobaciones manuales, mejorar el uso de las ramas para ambientes staging/uat, implementar tareas adicionales en el flujo ETL, etc.




Finalmente podemos ir al ADF de PRODUCCIÓN y verificar que se haya realizado correctamente el despliegue, en nuestro caso el pipeline de prueba que tenemos y el cambio de parámetros del linked service correspondiente al key valut de producción.










https://artelecolombiadev@dev.azure.com/artelecolombiadev/ADF_CICD/_git/ADF_CICD_DATA

CONTACTAR WP +57 3016700780

dubercoder@gmail.com

Entradas populares de este blog

Desplegando Infraestructura como Código (IaC) con Terraform en Azure Devops

Automatizando infraestructura como Código para ambiente de desarrollo con Bicep en la nube de Azure