Integração Contínua e Entrega Contínua (CI/CD) para Azure Data Factory
Published Mar 07 2023 04:58 AM 4,191 Views
Microsoft

Integração Contínua e Entrega Contínua (CI/CD) para Azure Data Factory

 

Azure Data Factory

 

O Azure Data Factory ou simplesmente (ADF) é o serviço ETL (do inglês Extract Transform Load) de nuvem do Azure para integração e transformação de dados sem servidor. Ele oferece uma interface de usuário intuitiva e sem código para criação, monitoramento e gerenciamento tudo em um painel único. Você também pode carregar e transferir pacotes SQL Server Integration Services (SSIS) existentes para o Azure e executá-los com total compatibilidade no ADF. O SSIS Integration Runtime oferece um serviço totalmente gerenciado, para que você não precise se preocupar com o gerenciamento da infraestrutura.

 

CI/CD

 

No Azure Data Factory, integração contínua e entrega contínua (CI/CD) significa mover pipelines, datasets e outras entidades do Data Factory de um ambiente, como desenvolvimento, teste e produção, para outro. O Azure Data Factory usa modelos do Azure Resource Manager (modelos ARM) para armazenar a configuração de suas várias entidades do Data Factory, como pipelines, conjuntos de dados e fluxos de dados.

 

Abaixo segue um exemplo de como o Azure Data factory usa modelos ARM para armazenar a configuração de suas várias entidades:

{
  "name": "myPipeline",
  "type": "Microsoft.DataFactory/factories/pipelines",
  "apiVersion": "2018-06-01",
  "properties": {
    "activities": [
      {
        "name": "CopyFromBlobToBlob",
        "type": "Copy",
        "dependsOn": [],
        "policy": {
          "timeout": "7.00:00

 

Fluxos de trabalho de CI/CD

 

Atualmente existem dois fluxos de trabalho para CI/CD para o Azure Data Factory:

  • Um fluxo que possui um processo manual para que os arquivos ARM sejam copiados para um repositório de controle de versão, como o Azure Repos ou GitHub. Em seguida, você pode usar o Azure Pipelines para implantar os arquivos ARM para o Data Factory.
current-ci-cd-flow
Imagem 1 - Fluxo do Azure Data Factory onde há uma interação manual para inciar o processo de CD.

Onde:

  1. Cada analista faz alterações em suas features branches.
  2. Fazer o push na Collaboration branch não é permitido. Os analistas devem criar uma solicitação pull para fazer alterações.
  3. Os usuários devem carregar o Azure Data Factory Studio e selecionar Publish para implantar alterações no Data Factory e gerar os arquivos ARM na Publish branch.
  4. Um pipeline de Release no Azure DevOps é configurado para criar uma nova versão e implantar os arquivos ARM sempre que uma nova alteração é enviada por push para a Publish branch.
  • E um segundo fluxo totalmente automatizado que usa o Azure Pipelines para gerar e validar a criação dos arquivos ARM e em seguida, implantar os arquivos ARM para o Data Factory.
new-ci-cd-flow
Imagem 2 - Fluxo do Azure Data Factory onde não há interação manual para o processo de CI/CD.

Onde:

  1. Cada analista faz alterações em suas features branches.
  2. Fazer o push na Collaboration branch não é permitido. Os analistas devem criar uma solicitação pull para fazer alterações.
  3. Um pipeline do Azure DevOps é acionado sempre que uma nova alteração é realizada na Collaboration branch. Ele valida os recursos e gera um modelo ARM como um artefato se a validação for bem-sucedida.
  4. o pipeline de deploy é configurado para criar implantar os arquivos ARM sempre que a etapa anterior form bem-sucedida.

É no segundo fluxo que vamos focar nesse artigo.

 

Preparando o ambiente

 

Na criação do pipeline de CI/CD será necessário utilizar o pacote @microsoft/azure-data-factory-utilities que é um pacote de utilitários para o Azure Data Factory. Esse pacote contém um conjunto de ferramentas para ajudar a exportar e validar pipelines do Data Factory. Um arquivo package.json deve ser criado na raiz do repositório e adicionado a seguinte dependência:

{
    "scripts":{
        "build":"node node_modules/@microsoft/azure-data-factory-utilities/lib/index"
    },
    "dependencies":{
        "@microsoft/azure-data-factory-utilities":"^0.1.6"
    }
}

Uma das tarefas do pipeline será copiar os arquivos ARM para um Storage Account. Há alguns limites para a utilização dos arquivos ARM. O tamanho máximo de um arquivo é de 4MB e quantidade de recursos em um arquivo é 800, para conhecer mais sobre os limites dos arquivos ARM acesse esse link. Para contornar esse problema, os arquivos serão divididos em pacotes de 4MB e armazenados no Storage Account.

Para isso, será necessário criar um Service Principal com permissão de acesso ao Storage Account. Para criar o Service Principal, execute o seguinte comando no Azure CLI:

Caso não tenha o Azure CLI instalado, você pode instalar seguindo as instruções aqui.

az ad sp create-for-rbac --name "api://ADF-SP" --role "Storage Blob Data Contributor" --scopes "/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.Storage/storageAccounts/<storage-account>"

O comando acima irá retornar um JSON com as credenciais do Service Principal criado. Anote o appId, tenantId, e o password.

Crie uma service connection no Azure DevOps para o Service Principal criado. Para criar a service connection, acesse o Azure DevOps e acesse o projeto que o ADF foi conectado e clique em Project settings e em seguida em Service connections. Clique em New service connection e selecione Azure Resource Manager e clique em Next. Selecione Service principal (manual) e clique em Next. Preencha os campos com as informações do Service Principal criado e clique em Verify and save.

Caso não tenha o Azure Storage Account, acesse esse link e siga as instruções.

Um SAS Token também será necessário para que o processo de CI/CD possa acessar o Storage Account. Para criar o SAS Token, acesse esse link e siga as instruções.

Com o SAS Token em mãos e o Storage Account criado, vamos criar o pipeline de CI/CD.

 

Criando o pipeline de CI/CD

 

Para criar o pipeline de CI/CD, acesse o Azure DevOps e acesse o projeto que o ADF foi conectado e clique em Pipelines e em seguida em New pipeline. Certifique-se de que o repositório correto está selecionado e clique em Starter pipeline.

StarterPipelines
Imagem 3 - Print de um modelo inicial de pipeline YAML do Azure DevOps.

Substitua o conteúdo do arquivo azure-pipelines.yml pelo seguinte:

trigger: 
  - main
    
variables:
  - group: adf
  - name: subscriptionId
    value: <Subscription Id>
  - name: serviceConnection
    value: <Service Connection Id>
  - name: dataFactoryNameDev
    value: <Data Factory Name Dev>
  - name: dataFactoryNameHml
    value: <Data Factory Name Hml>
  - name: datafactoryRgName
    value: <Resource Group Name>
  - name: dataFactoryID
    value: /subscriptions/$(subscriptionId)/resourceGroups/$(datafactoryRgName)/providers/Microsoft.DataFactory/factories/$(dataFactoryNameDev)
  - name: blobContainerName
    value: armartifacts
  - name: storageAccountName
    value: <Storage Account Name>
  - name: StorageURL
    value: https://$(storageAccountName).blob.core.windows.net/$(blobContainerName)/ARMTemplate/linkedTemplates
  - name: storageAccountUri
    value: https://$(storageAccountName).blob.core.windows.net
  - name: location
    value: <location>
  - name: NewAzResourceLock
    value: 'False'
  - name: LockLevel
    value: '--'
  - name: LockNotes
    value: '--'
  - name: LockName
    value: '--'

stages:
- stage: Build
  displayName: Build ADF

  jobs:
  - template: Template/build-adf.yml
    parameters: 
      devDataFactoryID: $(dataFactoryID)

- stage: DeployToDev
  displayName: Deploy em Dev
  dependsOn: Build
  condition: succeeded()

  jobs:
  - template: Template/deploy-adf.yml
    parameters:
      datafactoryRgName: $(datafactoryRgName)
      resourceManagerConnection: $(serviceConnection)
      location: $(location)
      subscriptionId: $(subscriptionId)
      subscription: $(serviceConnection)
      dataFactoryName: $(dataFactoryNameDev)
      dataFactoryNameDev: $(dataFactoryNameDev)
      storageAccountName: $(storageAccountName)
      blobContainerName: $(blobContainerName)
      StorageURL: $(StorageURL)
      StorageSASToken: $(StorageSASToken)
      environment: dev
      automatePublish: true

- stage: DeployToHml
  displayName: Deploy em Hml
  dependsOn: DeployToDev
  condition: succeeded()

  jobs:
  - template: Template/deploy-adf.yml
    parameters:
      datafactoryRgName: $(datafactoryRgName)
      resourceManagerConnection: $(serviceConnection)
      location: $(location)
      subscriptionId: $(subscriptionId)
      subscription: $(serviceConnection)
      dataFactoryName: $(dataFactoryNameHml)
      dataFactoryNameDev: $(dataFactoryNameDev)
      storageAccountName: $(storageAccountName)
      blobContainerName: $(blobContainerName)
      StorageURL: $(StorageURL)
      StorageSASToken: $(StorageSASToken)
      environment: hml

Substitua os valores das variáveis <Subscription Id>, <Service Connection Id>, <Data Factory Name Dev> (ambiente de desenvolvimento), <Data Factory Name Hml> (ambiente de homologação), <location> (ex. brazilsouth, eastus, …), <Resource Group Name> e <Storage Account Name> pelos valores correspondentes.

Salve o arquivo, mas não execute o pipeline ainda.

O pipeline de CI/CD criado acima possui 3 stages:

  • Build: Responsável por executar o processo de build do ADF. O stage Build possui um job que executa o template build-adf.yml, onde o processo de exportação e validação do ADF é executado. Após a execução os arquivos ARM são armazenados no Azure Pipelines e o job é finalizado.
  • DeployToDev: Responsável por executar o processo de deploy do ADF em Dev. O stage deployToDev possui um job que executa o template deploy-adf.yml, onde o processo de deploy do ADF atualiza o ambiente de Dev com as alterações realizadas. Após a execução o job é finalizado.
  • DeployToHml: Responsável por executar o processo de deploy do ADF em Hml. O stage deployToHml possui um job que executa o template deploy-adf.yml, onde o processo de deploy do ADF atualiza o ambiente de Hml com as alterações realizadas. Após a execução o job é finalizado.

No repositório crie duas pastas chamadas Template e Scripts.

Navegue a até a pasta Template e crie um novo arquivo chamado build-adf.yml. Substitua o conteúdo do arquivo pelo seguinte:

parameters:
- name: devDataFactoryID

jobs:
  - job: BuildADFDev
    displayName: Build Adf Dev
    pool:
      vmImage: 'ubuntu-latest'
    steps:  
      - task: NodeTool@0
        inputs:
          versionSpec: '16.x'
        displayName: 'Install Node.js'

      - task: Npm@1
        inputs:
          command: 'install'
          workingDir: '$(Build.Repository.LocalPath)' 
          verbose: true
        displayName: 'Install npm package'

      - task: Npm@1
        inputs:
          command: 'custom'
          workingDir: '$(Build.Repository.LocalPath)'
          customCommand: 'run build validate $(Build.Repository.LocalPath) ${{ parameters.devDataFactoryID }}'
        displayName: 'Validate'

      - task: Npm@1
        inputs:
          command: 'custom'
          workingDir: '$(Build.Repository.LocalPath)' 
          customCommand: 'run build export $(Build.Repository.LocalPath) ${{ parameters.devDataFactoryID }} "ArmTemplate"'
        displayName: 'Generate ARM template'

      - task: CopyFiles@2
        displayName: Copiando os arquivos do IaC
        inputs:
          SourceFolder: '$(Build.Repository.LocalPath)'
          Contents: |
            ArmTemplate/**/*
            Scripts/**/*
          TargetFolder: '$(Build.ArtifactStagingDirectory)/dropIAC'

      - task: PublishPipelineArtifact@1
        inputs:
          targetPath: '$(Build.ArtifactStagingDirectory)/dropIAC' 
          artifact: 'dropIAC'
          publishLocation: 'pipeline'

Na sequência, crie um novo arquivo chamado deploy-adf.yml e substitua o conteúdo do arquivo pelo seguinte:

parameters:
- name: datafactoryRgName
- name: resourceManagerConnection
- name: location
- name: subscriptionId
- name: subscription
- name: dataFactoryNameDev
- name: dataFactoryName
- name: storageAccountName
- name: blobContainerName
- name: StorageURL
- name: StorageSASToken
- name: environment
- name: automatePublish
  type: boolean
  default: false

jobs:
- deployment: Deploy
  displayName: Deploy do Data Factory
  pool:
    vmImage: 'windows-latest'
  environment: ${{ parameters.environment }}
  strategy:
    runOnce:
      deploy:
        steps:
          - task: DownloadPipelineArtifact@2
            displayName: Download do artefato ArmTemplate
            inputs:
              buildType: 'current'
              artifactName: 'dropIAC'
              targetPath: '$(Build.ArtifactStagingDirectory)'

          - task: AzureFileCopy@4
            displayName: 'Copy ARMTemplates to Storage Account'
            inputs:
              SourcePath: '$(Build.ArtifactStagingDirectory)/ARMTemplate'
              azureSubscription: ${{ parameters.subscription }}
              Destination: AzureBlob
              storage: ${{ parameters.storageAccountName }}
              ContainerName: '${{ parameters.blobContainerName }}'

          - task: AzurePowerShell@5
            displayName: 'Script Pré-Deployment'
            inputs:
              azureSubscription: ${{ parameters.subscription }}
              ScriptType: FilePath
              ScriptPath: $(Build.ArtifactStagingDirectory)/Scripts/Pre-Pos-Deployment.ps1
              ScriptArguments: -armTemplate $(Build.ArtifactStagingDirectory)/ARMTemplate/ARMTemplateForFactory.json -ResourceGroupName ${{ parameters.datafactoryRgName }} -DataFactoryName ${{ parameters.dataFactoryName }} -predeployment $true -deleteDeployment $false
              azurePowerShellVersion: LatestVersion
              workingDirectory: $(Build.ArtifactStagingDirectory)
              pwsh: true

          - task: AzurePowerShell@5
            displayName: 'Remove Resource Group Lock'
            inputs:
              azureSubscription: ${{ parameters.subscription }}
              ScriptType: 'FilePath'
              ScriptPath: '$(Build.ArtifactStagingDirectory)/Scripts/verifyResourceLock.ps1'
              ScriptArguments: '-removeLock "True" -ResourceGroupName ${{ parameters.datafactoryRgName }}'
              azurePowerShellVersion: 'LatestVersion'
              pwsh: true

          - task: AzureResourceManagerTemplateDeployment@3
            displayName: ARM Template - Deploy do ADF ${{ parameters.dataFactoryName }}
            inputs:
              deploymentScope: 'Resource Group'
              azureResourceManagerConnection: ${{ parameters.resourceManagerConnection }}
              subscriptionId: ${{ parameters.subscriptionId }}
              action: 'Create Or Update Resource Group'
              resourceGroupName: ${{ parameters.datafactoryRgName }}
              location: ${{ parameters.location }}
              templateLocation: 'Linked artifact'
              csmFile: '$(Build.ArtifactStagingDirectory)/ARMTemplate/linkedTemplates/ArmTemplate_master.json'
              csmParametersFile: '$(Build.ArtifactStagingDirectory)/ARMTemplate/linkedTemplates/ArmTemplateParameters_master.json'
              overrideParameters: >- 
                  -factoryName ${{ parameters.dataFactoryName }} -containerUri ${{ parameters.StorageURL }} -containerSasToken ${{ parameters.StorageSASToken }}
              deploymentMode: 'Incremental'

          - task: AzurePowerShell@5
            displayName: 'Script Pos-Deployment'
            inputs:
              azureSubscription: ${{ parameters.subscription }}
              ScriptType: 'FilePath'
              ScriptPath: '$(Build.ArtifactStagingDirectory)/Scripts/Pre-Pos-Deployment.ps1'
              ScriptArguments: '-armTemplate $(Build.ArtifactStagingDirectory)/ARMTemplate/ARMTemplateForFactory.json -ResourceGroupName ${{ parameters.datafactoryRgName }} -DataFactoryName ${{ parameters.dataFactoryName }} -predeployment $false -deleteDeployment $true'
              azurePowerShellVersion: 'LatestVersion'
              pwsh: true

          - ${{ if eq(parameters.automatePublish, 'true') }}:
            - task: AzurePowerShell@5
              displayName: 'Automate Publish'
              inputs:
                azureSubscription: ${{ parameters.subscription }}
                ScriptType: 'FilePath'
                ScriptPath: '$(Build.ArtifactStagingDirectory)/Scripts/UpdateLastCommitId.ps1'
                ScriptArguments: '-ResourceGroupName ${{ parameters.datafactoryRgName }} -DataFactoryName ${{ parameters.dataFactoryName }} -LastCommitId $(Build.SourceVersion)'
                azurePowerShellVersion: 'LatestVersion'
                pwsh: true

          - task: AzurePowerShell@5
            displayName: 'Create Resource Group Lock'
            inputs:
              azureSubscription: ${{ parameters.subscription }}
              ScriptType: 'FilePath'
              ScriptPath: '$(Build.ArtifactStagingDirectory)/Scripts/verifyResourceLock.ps1'
              ScriptArguments: '-newLock $(NewAzResourceLock) -ResourceGroupName ${{ parameters.datafactoryRgName }} -LockLevel $(LockLevel) -LockNotes $(LockNotes) -LockName $(LockName)'
              azurePowerShellVersion: 'LatestVersion'
              pwsh: true

O template deploy-adf.yml utiliza alguns scripts que estão na pasta Scripts do repositório, eles são necessários para que o processo de deploy funcione corretamente. Cada script tem uma função específica, abaixo estão as descrições e conteúdo de cada script.

Script para parar a execução das triggers do Data Factory O script Pre-Pos-Deployment.ps1 é responsável por parar a execução das triggers do Data Factory. Esse script é utilizado para que a publicação do Data Factory não apresente erro por estar em execução no momento do deploy, esse script também é responsável por reativar as trigger do Data Factory após o deploy e por deletar o deployment do Data Factory após o deploy. para ter acesso ao script acesse esse repositório no Github Azure/Azure-DataFactory.

Script para atualizar o commit id do Data Factory O script UpdateLastCommitId.ps1 é responsável por atualizar o commit id do Data Factory. Esse script é utilizado para que o Data Factory seja publicado automaticamente após o deploy.

param(
    [parameter(Mandatory = $true)] [String]$ResourceGroupName,
    [parameter(Mandatory = $true)] [String]$DataFactoryName,
    [parameter(Mandatory = $true)] [String]$LastCommitId
)

$var = Get-AzDataFactoryV2 -ResourceGroupName $ResourceGroupName -Name $DataFactoryName

Get-AzDataFactoryV2 -ResourceGroupName $ResourceGroupName -Name $DataFactoryName | Set-AzDataFactoryV2 -AccountName $var.RepoConfiguration.AccountName -RepositoryName $var.RepoConfiguration.RepositoryName -CollaborationBranch $var.RepoConfiguration.CollaborationBranch -RootFolder / -ProjectName $var.RepoConfiguration.ProjectName -LastCommitId $LastCommitId -Force

Script para remover o lock do Resource Group O script verifyResourceLock.ps1 é responsável por remover o lock do Resource Group e criar um novo lock com as informações passadas como parâmetro.

param (
    [parameter(Mandatory = $false)] [System.String] $removeLock = "False",
    [parameter(Mandatory = $false)] [System.String] $newLock = "False",
    [parameter(Mandatory = $false)] [System.String] $ResourceGroupName = "rg-name",
    [parameter(Mandatory = $false)] [System.String] $LockLevel = "CanNotDelete",#CanNotDelete / ReadOnly
    [parameter(Mandatory = $false)] [System.String] $LockNotes = "Azure-DevOps-Pipeline",
    [parameter(Mandatory = $false)] [System.String] $LockName = "ProductionLocked"
    )

function RemoveAzResourceLock {
    param(
        [System.String] $ResourceGroupName
    )
    $AzResourceLock = Get-AzResourceLock -ResourceGroupName $ResourceGroupName -AtScope
    # verify if exists an resource lock
    if (!$AzResourceLock) {
        Write-Host "There is no Resource Lock for Resource Group: " $ResourceGroupName
        $return = $false
        $return = $return | Select-Object @{Name = 'Removed';Expression = {$_}}

        $NewAzResourceLock = "False"

        Write-Host "##vso[task.setvariable variable=NewAzResourceLock;]$NewAzResourceLock"

        return $return
    } else {
        $RemoveAzResourceLock = Remove-AzResourceLock -ResourceGroupName $AzResourceLock.ResourceGroupName -LockName $AzResourceLock.Name -Force
        Write-Host "Resource Lock Removed? " $RemoveAzResourceLock
        $return = $AzResourceLock | Select-Object Name, @{Name = 'Level';Expression = {"$($_.Properties.level)"}}, @{Name = 'Notes';Expression = {"$($_.Properties.notes)"}}, @{Name = 'Removed';Expression = {"True"}}

        $ResourceGroupName = $AzResourceLock.ResourceGroupName
        $NewAzResourceLock = "True"
        $LockLevel = $AzResourceLock.Properties.level
        $LockNotes = $AzResourceLock.Properties.notes ? $AzResourceLock.Properties.notes : "Azure-DevOps-Pipeline"
        $LockName  = $AzResourceLock.Name

        Write-Host "##vso[task.setvariable variable=NewAzResourceLock;]$NewAzResourceLock"
        Write-Host "##vso[task.setvariable variable=ResourceGroupName;]$ResourceGroupName"
        Write-Host "##vso[task.setvariable variable=LockLevel;]$LockLevel"
        Write-Host "##vso[task.setvariable variable=LockNotes;]$LockNotes"
        Write-Host "##vso[task.setvariable variable=LockName;]$LockName"

        return $return
    }
}

function NewAzResourceLock {
    param(
        [System.String] $NewAzResourceLock,
        [System.String] $ResourceGroupName,
        [System.String] $LockLevel,
        [System.String] $LockNotes,
        [System.String] $LockName
    )
    if ($NewAzResourceLock -eq 'True'){
        $ResourceLock = New-AzResourceLock -ResourceGroupName $ResourceGroupName -LockLevel $LockLevel -LockNotes $LockNotes -LockName $LockName -Force
        Write-Host "Resource Lock Created: " $ResourceLock.ResourceId
    } else {
        Write-Host "There is no Resource Lock for Resource Group: " $ResourceGroupName
    }
}

if ($removeLock -eq 'True') {
    Write-Host "Remove lock"
    RemoveAzResourceLock -ResourceGroupName $ResourceGroupName
} 

if ($newLock -eq 'True') {
    Write-Host "Create lock"
    NewAzResourceLock -NewAzResourceLock $newLock -ResourceGroupName $ResourceGroupName -LockLevel $LockLevel -LockNotes $LockNotes -LockName $LockName
}

Agora que já todos os scripts estão criados é necessário criar um variable group no Azure DevOps para armazenar o SAS Token criado anteriormente.

Para criar o variable group no Azure DevOps basta clicar em Library > Variable Groups > New Variable Group, preencha o nome do variable group com adf e clique em Add Variable. Adicione a variável abaixo:

StorageSASToken | ? + Token gerado anteriormente*

Variable-Group
Imagem 4 - Print da tela de criação de Variable Group, destacado a criação da variável StorageSASToken.

nota: Não esqueça de clicar no cadeado para ocultar o Token.

 

Executando o Pipeline

 

Após todos os passos anteriores, o pipeline de CI/CD está pronto para ser executado. Clique em Pipelines > selecione o pipeline criado > Run pipeline.

Um exemplo de execução com sucesso do pipeline pode ser visto abaixo:

BuildSuccess
Imagem 5 - Print das tarefas do estágio de Build ADF, todas com sucesso.
DeployDevSuccess
Imagem 6 - Print das tarefas do estágio de Deploy em Dev, todas com sucesso.
DeployHmlSuccess
Imagem 7 - Print das tarefas do estágio de Deploy em Hml, todas com sucesso.
Stages_Pipeline
Imagem 8 - Print do resultado dos stages de um Pipeline com sucesso.

 

Conclusão

 

A utilização do Azure DevOps para o CI/CD de Data Factory é uma ótima opção para quem deseja automatizar o processo de deploy de Data Factory. O pipeline criado neste artigo é um exemplo , mas existem outras formas de automação, como por exemplo, utilizando o Azure Data Factory V2 REST API.

 

Referências

  1. Azure Data Factory
  2. Azure DevOps
  3. Azure DevOps Variable Groups
  4. Azure DevOps Pipeline
  5. Automatizar a integração contínua usando versões do Azure Pipelines
  6. Integração e entrega contínuas no Azure Data Factory
  7. Controle do código-fonte no Azure Data Factory
  8. Linked Resource Manager templates with CI/CD
  9. Usar parâmetros personalizados com o modelo do Resource Manager
  10. CLI Az.DataFactory
  11. Melhorias de implantação contínua
  12. Script para o Pré e Pós Deployment Versão II
  13. Início Rápido: criar um Azure Data Factory usando o Bicep
  14. Criar tokens SAS para os contêineres de armazenamento
Co-Authors
Version history
Last update:
‎Mar 06 2023 01:13 PM
Updated by: