一,引言

  由于上一节文章内容过长,无法分享Azure Data Factory 的持续集成,持续发布。今天将着重介绍一下在使用 Azure DevOps Pipeline 发布,自动进行持续集成,并且已自动化发布,将Azure Data Factory 部署到多个环境中。

  其实大家也不必惊讶,这里的部署其实也没有多么神秘的,我们在ADF中的 master 分支发布之后,其实会将ADF中所有的配置信息打包,编译到adf_master 分支下面,如果大家仔细看过发布之后的代码,就很很容易发现,都是一些 ARM 模板资源。以当前我创建的demo为例

这是就有人在问了,什么是ARM模板?这里就先见到你的概规一下:

  针对于Azure上一些基础设施资源的部署,可以通过运用基础架构即代码,可是实现部署自动化,在代码中定义需要部署的基础架构资源。将这些基础架构资源代码变成项目的一部分,与应用程序代码一样。通过代码管理工具,管理起来,方便部署,通过代码的方式创建、删除资源。而ARM模板就是基础架构即代码的一种形式(另外一种是 Terraform),该模板是一个定义项目基础结构和配置的 JavaScript 对象表示法 (JSON) 文件。 该模板使用声明性语法,使你可以指明要部署的内容,而不需要编写一系列编程命令来创建内容。 在该模板中,指定要部署的资源以及这些资源的属性。

说人话,就是ARM模板中描述了我们需要部署的云资源以及其资源所需要的参数,比如说通过使用ARM不是一台VM,那么ARM模板中就描述了VM资源以及其创建VM所需要的必要的参数。

回到ADF中,也就是说我们最终通过master分支发布到 adf_master 分支的代码,其实就是一堆描述ADF资源以及ADF配置的属性及参数。我们今天的内容也就是通过ARM去实现ADF的 UAT,PRO 环境的部署。

--------------------我是分割线--------------------

1,Azure Data Factory(一)入门简介

2,Azure Data Factory(二)复制数据

3,Azure Data Factory(三)集成 Azure Devops 实现CI/CD

二,正文

1,创建ADF的 UAT 环境

我们通过资源名+UAT的方式来模拟测试环境,如下新创建了一个叫 "ADF-CnBateBlogWeb-UAT" 的 Azure Data Factory 和 两个UAT 环境的 Blob Storage

”cnbateblogwebaccount1dev“ 作为UAT 环境的数据源,我们也为UAT环境创建叫 “resformfolder” 的容器

“cnbateblogwebaccount2dev” 作为UAT 环境的目标源,我们也为UAT环境创建叫 “restofolder” 的容器

2,初始化部署前后脚本

实际中,我们在部署ADF 甚至其他项目代码时,都是需要将AFD的触发器停止,等到部署完成后,我们就得重启ADF中配置的触发器。微软有帮助我们提供了部署前后可以使用的脚本

  1 param
2 (
3 [parameter(Mandatory = $false)] [String] $armTemplate,
4 [parameter(Mandatory = $false)] [String] $ResourceGroupName,
5 [parameter(Mandatory = $false)] [String] $DataFactoryName,
6 [parameter(Mandatory = $false)] [Bool] $predeployment=$true,
7 [parameter(Mandatory = $false)] [Bool] $deleteDeployment=$false
8 )
9
10 function getPipelineDependencies {
11 param([System.Object] $activity)
12 if ($activity.Pipeline) {
13 return @($activity.Pipeline.ReferenceName)
14 } elseif ($activity.Activities) {
15 $result = @()
16 $activity.Activities | ForEach-Object{ $result += getPipelineDependencies -activity $_ }
17 return $result
18 } elseif ($activity.ifFalseActivities -or $activity.ifTrueActivities) {
19 $result = @()
20 $activity.ifFalseActivities | Where-Object {$_ -ne $null} | ForEach-Object{ $result += getPipelineDependencies -activity $_ }
21 $activity.ifTrueActivities | Where-Object {$_ -ne $null} | ForEach-Object{ $result += getPipelineDependencies -activity $_ }
22 return $result
23 } elseif ($activity.defaultActivities) {
24 $result = @()
25 $activity.defaultActivities | ForEach-Object{ $result += getPipelineDependencies -activity $_ }
26 if ($activity.cases) {
27 $activity.cases | ForEach-Object{ $_.activities } | ForEach-Object{$result += getPipelineDependencies -activity $_ }
28 }
29 return $result
30 } else {
31 return @()
32 }
33 }
34
35 function pipelineSortUtil {
36 param([Microsoft.Azure.Commands.DataFactoryV2.Models.PSPipeline]$pipeline,
37 [Hashtable] $pipelineNameResourceDict,
38 [Hashtable] $visited,
39 [System.Collections.Stack] $sortedList)
40 if ($visited[$pipeline.Name] -eq $true) {
41 return;
42 }
43 $visited[$pipeline.Name] = $true;
44 $pipeline.Activities | ForEach-Object{ getPipelineDependencies -activity $_ -pipelineNameResourceDict $pipelineNameResourceDict} | ForEach-Object{
45 pipelineSortUtil -pipeline $pipelineNameResourceDict[$_] -pipelineNameResourceDict $pipelineNameResourceDict -visited $visited -sortedList $sortedList
46 }
47 $sortedList.Push($pipeline)
48
49 }
50
51 function Get-SortedPipelines {
52 param(
53 [string] $DataFactoryName,
54 [string] $ResourceGroupName
55 )
56 $pipelines = Get-AzDataFactoryV2Pipeline -DataFactoryName $DataFactoryName -ResourceGroupName $ResourceGroupName
57 $ppDict = @{}
58 $visited = @{}
59 $stack = new-object System.Collections.Stack
60 $pipelines | ForEach-Object{ $ppDict[$_.Name] = $_ }
61 $pipelines | ForEach-Object{ pipelineSortUtil -pipeline $_ -pipelineNameResourceDict $ppDict -visited $visited -sortedList $stack }
62 $sortedList = new-object Collections.Generic.List[Microsoft.Azure.Commands.DataFactoryV2.Models.PSPipeline]
63
64 while ($stack.Count -gt 0) {
65 $sortedList.Add($stack.Pop())
66 }
67 $sortedList
68 }
69
70 function triggerSortUtil {
71 param([Microsoft.Azure.Commands.DataFactoryV2.Models.PSTrigger]$trigger,
72 [Hashtable] $triggerNameResourceDict,
73 [Hashtable] $visited,
74 [System.Collections.Stack] $sortedList)
75 if ($visited[$trigger.Name] -eq $true) {
76 return;
77 }
78 $visited[$trigger.Name] = $true;
79 if ($trigger.Properties.DependsOn) {
80 $trigger.Properties.DependsOn | Where-Object {$_ -and $_.ReferenceTrigger} | ForEach-Object{
81 triggerSortUtil -trigger $triggerNameResourceDict[$_.ReferenceTrigger.ReferenceName] -triggerNameResourceDict $triggerNameResourceDict -visited $visited -sortedList $sortedList
82 }
83 }
84 $sortedList.Push($trigger)
85 }
86
87 function Get-SortedTriggers {
88 param(
89 [string] $DataFactoryName,
90 [string] $ResourceGroupName
91 )
92 $triggers = Get-AzDataFactoryV2Trigger -ResourceGroupName $ResourceGroupName -DataFactoryName $DataFactoryName
93 $triggerDict = @{}
94 $visited = @{}
95 $stack = new-object System.Collections.Stack
96 $triggers | ForEach-Object{ $triggerDict[$_.Name] = $_ }
97 $triggers | ForEach-Object{ triggerSortUtil -trigger $_ -triggerNameResourceDict $triggerDict -visited $visited -sortedList $stack }
98 $sortedList = new-object Collections.Generic.List[Microsoft.Azure.Commands.DataFactoryV2.Models.PSTrigger]
99
100 while ($stack.Count -gt 0) {
101 $sortedList.Add($stack.Pop())
102 }
103 $sortedList
104 }
105
106 function Get-SortedLinkedServices {
107 param(
108 [string] $DataFactoryName,
109 [string] $ResourceGroupName
110 )
111 $linkedServices = Get-AzDataFactoryV2LinkedService -ResourceGroupName $ResourceGroupName -DataFactoryName $DataFactoryName
112 $LinkedServiceHasDependencies = @('HDInsightLinkedService', 'HDInsightOnDemandLinkedService', 'AzureBatchLinkedService')
113 $Akv = 'AzureKeyVaultLinkedService'
114 $HighOrderList = New-Object Collections.Generic.List[Microsoft.Azure.Commands.DataFactoryV2.Models.PSLinkedService]
115 $RegularList = New-Object Collections.Generic.List[Microsoft.Azure.Commands.DataFactoryV2.Models.PSLinkedService]
116 $AkvList = New-Object Collections.Generic.List[Microsoft.Azure.Commands.DataFactoryV2.Models.PSLinkedService]
117
118 $linkedServices | ForEach-Object {
119 if ($_.Properties.GetType().Name -in $LinkedServiceHasDependencies) {
120 $HighOrderList.Add($_)
121 }
122 elseif ($_.Properties.GetType().Name -eq $Akv) {
123 $AkvList.Add($_)
124 }
125 else {
126 $RegularList.Add($_)
127 }
128 }
129
130 $SortedList = New-Object Collections.Generic.List[Microsoft.Azure.Commands.DataFactoryV2.Models.PSLinkedService]($HighOrderList.Count + $RegularList.Count + $AkvList.Count)
131 $SortedList.AddRange($HighOrderList)
132 $SortedList.AddRange($RegularList)
133 $SortedList.AddRange($AkvList)
134 $SortedList
135 }
136
137 $templateJson = Get-Content $armTemplate | ConvertFrom-Json
138 $resources = $templateJson.resources
139
140 #Triggers
141 Write-Host "Getting triggers"
142 $triggersInTemplate = $resources | Where-Object { $_.type -eq "Microsoft.DataFactory/factories/triggers" }
143 $triggerNamesInTemplate = $triggersInTemplate | ForEach-Object {$_.name.Substring(37, $_.name.Length-40)}
144
145 $triggersDeployed = Get-SortedTriggers -DataFactoryName $DataFactoryName -ResourceGroupName $ResourceGroupName
146
147 $triggersToStop = $triggersDeployed | Where-Object { $triggerNamesInTemplate -contains $_.Name } | ForEach-Object {
148 New-Object PSObject -Property @{
149 Name = $_.Name
150 TriggerType = $_.Properties.GetType().Name
151 }
152 }
153 $triggersToDelete = $triggersDeployed | Where-Object { $triggerNamesInTemplate -notcontains $_.Name } | ForEach-Object {
154 New-Object PSObject -Property @{
155 Name = $_.Name
156 TriggerType = $_.Properties.GetType().Name
157 }
158 }
159 $triggersToStart = $triggersInTemplate | Where-Object { $_.properties.runtimeState -eq "Started" -and ($_.properties.pipelines.Count -gt 0 -or $_.properties.pipeline.pipelineReference -ne $null)} | ForEach-Object {
160 New-Object PSObject -Property @{
161 Name = $_.name.Substring(37, $_.name.Length-40)
162 TriggerType = $_.Properties.type
163 }
164 }
165
166 if ($predeployment -eq $true) {
167 #Stop all triggers
168 Write-Host "Stopping deployed triggers`n"
169 $triggersToStop | ForEach-Object {
170 if ($_.TriggerType -eq "BlobEventsTrigger") {
171 Write-Host "Unsubscribing" $_.Name "from events"
172 $status = Remove-AzDataFactoryV2TriggerSubscription -ResourceGroupName $ResourceGroupName -DataFactoryName $DataFactoryName -Name $_.Name
173 while ($status.Status -ne "Disabled"){
174 Start-Sleep -s 15
175 $status = Get-AzDataFactoryV2TriggerSubscriptionStatus -ResourceGroupName $ResourceGroupName -DataFactoryName $DataFactoryName -Name $_.Name
176 }
177 }
178 Write-Host "Stopping trigger" $_.Name
179 Stop-AzDataFactoryV2Trigger -ResourceGroupName $ResourceGroupName -DataFactoryName $DataFactoryName -Name $_.Name -Force
180 }
181 }
182 else {
183 #Deleted resources
184 #pipelines
185 Write-Host "Getting pipelines"
186 $pipelinesADF = Get-SortedPipelines -DataFactoryName $DataFactoryName -ResourceGroupName $ResourceGroupName
187 $pipelinesTemplate = $resources | Where-Object { $_.type -eq "Microsoft.DataFactory/factories/pipelines" }
188 $pipelinesNames = $pipelinesTemplate | ForEach-Object {$_.name.Substring(37, $_.name.Length-40)}
189 $deletedpipelines = $pipelinesADF | Where-Object { $pipelinesNames -notcontains $_.Name }
190 #dataflows
191 $dataflowsADF = Get-AzDataFactoryV2DataFlow -DataFactoryName $DataFactoryName -ResourceGroupName $ResourceGroupName
192 $dataflowsTemplate = $resources | Where-Object { $_.type -eq "Microsoft.DataFactory/factories/dataflows" }
193 $dataflowsNames = $dataflowsTemplate | ForEach-Object {$_.name.Substring(37, $_.name.Length-40) }
194 $deleteddataflow = $dataflowsADF | Where-Object { $dataflowsNames -notcontains $_.Name }
195 #datasets
196 Write-Host "Getting datasets"
197 $datasetsADF = Get-AzDataFactoryV2Dataset -DataFactoryName $DataFactoryName -ResourceGroupName $ResourceGroupName
198 $datasetsTemplate = $resources | Where-Object { $_.type -eq "Microsoft.DataFactory/factories/datasets" }
199 $datasetsNames = $datasetsTemplate | ForEach-Object {$_.name.Substring(37, $_.name.Length-40) }
200 $deleteddataset = $datasetsADF | Where-Object { $datasetsNames -notcontains $_.Name }
201 #linkedservices
202 Write-Host "Getting linked services"
203 $linkedservicesADF = Get-SortedLinkedServices -DataFactoryName $DataFactoryName -ResourceGroupName $ResourceGroupName
204 $linkedservicesTemplate = $resources | Where-Object { $_.type -eq "Microsoft.DataFactory/factories/linkedservices" }
205 $linkedservicesNames = $linkedservicesTemplate | ForEach-Object {$_.name.Substring(37, $_.name.Length-40)}
206 $deletedlinkedservices = $linkedservicesADF | Where-Object { $linkedservicesNames -notcontains $_.Name }
207 #Integrationruntimes
208 Write-Host "Getting integration runtimes"
209 $integrationruntimesADF = Get-AzDataFactoryV2IntegrationRuntime -DataFactoryName $DataFactoryName -ResourceGroupName $ResourceGroupName
210 $integrationruntimesTemplate = $resources | Where-Object { $_.type -eq "Microsoft.DataFactory/factories/integrationruntimes" }
211 $integrationruntimesNames = $integrationruntimesTemplate | ForEach-Object {$_.name.Substring(37, $_.name.Length-40)}
212 $deletedintegrationruntimes = $integrationruntimesADF | Where-Object { $integrationruntimesNames -notcontains $_.Name }
213
214 #Delete resources
215 Write-Host "Deleting triggers"
216 $triggersToDelete | ForEach-Object {
217 Write-Host "Deleting trigger " $_.Name
218 $trig = Get-AzDataFactoryV2Trigger -name $_.Name -ResourceGroupName $ResourceGroupName -DataFactoryName $DataFactoryName
219 if ($trig.RuntimeState -eq "Started") {
220 if ($_.TriggerType -eq "BlobEventsTrigger") {
221 Write-Host "Unsubscribing trigger" $_.Name "from events"
222 $status = Remove-AzDataFactoryV2TriggerSubscription -ResourceGroupName $ResourceGroupName -DataFactoryName $DataFactoryName -Name $_.Name
223 while ($status.Status -ne "Disabled"){
224 Start-Sleep -s 15
225 $status = Get-AzDataFactoryV2TriggerSubscriptionStatus -ResourceGroupName $ResourceGroupName -DataFactoryName $DataFactoryName -Name $_.Name
226 }
227 }
228 Stop-AzDataFactoryV2Trigger -ResourceGroupName $ResourceGroupName -DataFactoryName $DataFactoryName -Name $_.Name -Force
229 }
230 Remove-AzDataFactoryV2Trigger -Name $_.Name -ResourceGroupName $ResourceGroupName -DataFactoryName $DataFactoryName -Force
231 }
232 Write-Host "Deleting pipelines"
233 $deletedpipelines | ForEach-Object {
234 Write-Host "Deleting pipeline " $_.Name
235 Remove-AzDataFactoryV2Pipeline -Name $_.Name -ResourceGroupName $ResourceGroupName -DataFactoryName $DataFactoryName -Force
236 }
237 Write-Host "Deleting dataflows"
238 $deleteddataflow | ForEach-Object {
239 Write-Host "Deleting dataflow " $_.Name
240 Remove-AzDataFactoryV2DataFlow -Name $_.Name -ResourceGroupName $ResourceGroupName -DataFactoryName $DataFactoryName -Force
241 }
242 Write-Host "Deleting datasets"
243 $deleteddataset | ForEach-Object {
244 Write-Host "Deleting dataset " $_.Name
245 Remove-AzDataFactoryV2Dataset -Name $_.Name -ResourceGroupName $ResourceGroupName -DataFactoryName $DataFactoryName -Force
246 }
247 Write-Host "Deleting linked services"
248 $deletedlinkedservices | ForEach-Object {
249 Write-Host "Deleting Linked Service " $_.Name
250 Remove-AzDataFactoryV2LinkedService -Name $_.Name -ResourceGroupName $ResourceGroupName -DataFactoryName $DataFactoryName -Force
251 }
252 Write-Host "Deleting integration runtimes"
253 $deletedintegrationruntimes | ForEach-Object {
254 Write-Host "Deleting integration runtime " $_.Name
255 Remove-AzDataFactoryV2IntegrationRuntime -Name $_.Name -ResourceGroupName $ResourceGroupName -DataFactoryName $DataFactoryName -Force
256 }
257
258 if ($deleteDeployment -eq $true) {
259 Write-Host "Deleting ARM deployment ... under resource group: " $ResourceGroupName
260 $deployments = Get-AzResourceGroupDeployment -ResourceGroupName $ResourceGroupName
261 $deploymentsToConsider = $deployments | Where { $_.DeploymentName -like "ArmTemplate_master*" -or $_.DeploymentName -like "ArmTemplateForFactory*" } | Sort-Object -Property Timestamp -Descending
262 $deploymentName = $deploymentsToConsider[0].DeploymentName
263
264 Write-Host "Deployment to be deleted: " $deploymentName
265 $deploymentOperations = Get-AzResourceGroupDeploymentOperation -DeploymentName $deploymentName -ResourceGroupName $ResourceGroupName
266 $deploymentsToDelete = $deploymentOperations | Where { $_.properties.targetResource.id -like "*Microsoft.Resources/deployments*" }
267
268 $deploymentsToDelete | ForEach-Object {
269 Write-host "Deleting inner deployment: " $_.properties.targetResource.id
270 Remove-AzResourceGroupDeployment -Id $_.properties.targetResource.id
271 }
272 Write-Host "Deleting deployment: " $deploymentName
273 Remove-AzResourceGroupDeployment -ResourceGroupName $ResourceGroupName -Name $deploymentName
274 }
275
276 #Start active triggers - after cleanup efforts
277 Write-Host "Starting active triggers"
278 $triggersToStart | ForEach-Object {
279 if ($_.TriggerType -eq "BlobEventsTrigger") {
280 Write-Host "Subscribing" $_.Name "to events"
281 $status = Add-AzDataFactoryV2TriggerSubscription -ResourceGroupName $ResourceGroupName -DataFactoryName $DataFactoryName -Name $_.Name
282 while ($status.Status -ne "Enabled"){
283 Start-Sleep -s 15
284 $status = Get-AzDataFactoryV2TriggerSubscriptionStatus -ResourceGroupName $ResourceGroupName -DataFactoryName $DataFactoryName -Name $_.Name
285 }
286 }
287 Write-Host "Starting trigger" $_.Name
288 Start-AzDataFactoryV2Trigger -ResourceGroupName $ResourceGroupName -DataFactoryName $DataFactoryName -Name $_.Name -Force
289 }
290 }

adf_ci_cd.sh

我们将当前powershell 脚本添加到代码中。文件命名为 “adf_ci_cd.sh”

将,上面的脚本文件的内容贴进去,点击 “Commit”,并且提交保存到 “master” 分支中

3,配置Azure DevOps Pipeline 环境

回到Azure DevOps 中,选择 “Pipelines=》Releases”,点击 “New pipeline”

此时需要我们选择模板,我们先点击 “Empty job” 创建一个空的 job

修改补助名称为 “UAT”

接下来选择添加 “artifact”,先添加一个afd_master 发布产品源

Source Type 选择:”Azure Repos Git“

Project 选择:”CnBateBlogWeb_Proj“

Source(reposity)选择:”CnBateBlogWeb_Proj“

Default branch:”adf_publish“

Source alias(源别名):”_CnBateBlogWeb_Proj_Publish“

点击 ”Add“ 进行添加操作。

再添加 “artifact”,先添加一个ADF的 ”master“ 分布作为产品发布源,大家注意里面的参数

Default branch:”master“

Source alias:”_CnBateBlogWeb_Proj_Master“

点击 ”OK“ 进行添加操作。

最后,让我们给 ”UAT“ stages 添加 task,点击图中圈起来的部分

点击 ”+“,进行添加 ”Azure PowerShell“ Task,同时PowerShell 脚本去停止目前所有正在运行的 Triggers

对于当前停止Trigger的 Task,有些需要我们留意的属性配置

1,Display name 可以改为 ”Stop Triggers“(表面当前Task具体干了什么事)

2,选择 ”UAT“ 环境所在的Azure 订阅

3,Script Path(脚本路径)

4,Script Arguments(脚本参数)

上面提到的脚本文件说明一下,就是我们刚刚在 ”master“ 分支提交的 adf_ci_cd.sh 这个文件,我们可以进行选择

部署前,需要停止所有Trigger,关于脚本参数(停止Trigger)

-armTemplate "$(System.DefaultWorkingDirectory)/<your-arm-template-location>" -ResourceGroupName <your-resource-group-name> -DataFactoryName <your-data-factory-name> -predeployment $true -deleteDeployment $false

部署完成后,需要启动所有Trigger,关于脚本参数(启动Trigger)

-armTemplate "$(System.DefaultWorkingDirectory)/<your-arm-template-location>" -ResourceGroupName <your-resource-group-name> -DataFactoryName <your-data-factory-name> -predeployment $false -deleteDeployment $true

大家将上面对应的的脚本参数贴上自己的实际的UAT环境所在的资源组,资源名称,以及模板所在路径

以下是我当前的模板参数;大家可以作为参考:

-armTemplate "$(System.DefaultWorkingDirectory)/_CnBateBlogWeb_Proj_Publish/ADF-CnBateBlogWeb-Dev/ARMTemplateForFactory.json" -ResourceGroupName "Web_Test_DF_RG_UAT" -DataFactoryName "ADF-CnBateBlogWeb-AUT" -predeployment $true -deleteDeployment $false

接下来就是添加 ARM 模板部署了,搜索 ”ARM template deployment“,找到 ARM 模板部署,点击 ”Add“ 进行添加

修改当前Task属性

Display name:”ARM Template deployment:ADF Deploy“

Subscription 选择:当前需要UAT环境所在的订阅

Resource group 选择:”Web_Test_DF_RG_UAT“(也就是当前UAT环境 ADF所在的资源组)

Loaction 选择:”East Asia“

Template 以及 Template parameters 分别选择 ”_CnBateBlog_Proj_Publish“ 下的 ”ARMTemplateForFactory.json“,"ARMTemplateParametersForFactory.json"

而 Override template parameters(替换模板参数)则指我们需要把模板参数文件中的一些参数替换掉,如需要部署的ADF的名称,数据源、目标源的blob Storage 的链接字符串

如下,我演示的覆盖模板参数实例(大家需要将UAT环境的ADF 名称换成自己创建命名的,以及两个链接字符参数名称需要在模板参数文件中找到自己对应的名称,链接字符串复制粘贴自己UAT环境的两个Blob Storage的链接字符串):

-factoryName "ADF-CnBateBlogWeb-AUT" -CnBateBlogFromBlobStorage_connectionString "DefaultEndpointsProtocol=https;AccountName=cnbateblogwebaccount1uat;AccountKey=XF7XkFsnEdIGZT8CCUJs7At1E/Ni9k/XJBtwWaKvwAuBnp3cCN6e2CYiV2uzsq2iI0vI2eZVHS8Kh9CvcuoNcg==;EndpointSuffix=core.windows.net" -CnBateBlobToBlobStorage_connectionString "DefaultEndpointsProtocol=https;AccountName=cnbateblogwebaccount2uat;AccountKey=E5z+q7XL7+8xTlqHsyaIGr0Eje/0DhT9+/E+oro4D57tsSuEchmnjLiK8zftTtyvQKLQUvTGJEsAOFCBGdioHw==;EndpointSuffix=core.windows.net"

最近就是添加重启所有 Trigger 的 PowerShell 的 Task,具体参数如下图

Script Path 选择 :”_CnBateBlogWeb_Proj_Master“ 文件下的 “adf_ci_cd.sh” 文件

Script Path (需要清理资源、重启所有Trigger的脚本参数):

-armTemplate "$(System.DefaultWorkingDirectory)/<your-arm-template-location>" -ResourceGroupName <your-resource-group-name> -DataFactoryName <your-data-factory-name> -predeployment $false -deleteDeployment $true

大家将上面对应的的脚本参数贴上自己的实际的UAT环境所在的资源组,资源名称,以及模板所在路径

以下是我当前的模板参数;大家可以作为参考:

-armTemplate "$(System.DefaultWorkingDirectory)/_CnBateBlogWeb_Proj_Publish/ADF-CnBateBlogWeb-Dev/ARMTemplateForFactory.json" -ResourceGroupName "Web_Test_DF_RG_UAT" -DataFactoryName "ADF-CnBateBlogWeb-AUT" -predeployment $true -deleteDeployment $true

修改当前pipeline 的名称,点击 "Save” 进行保存。

接下来,就是设置 pipeline 的触发条件

开启持续部署触发,每次在所选存储库中发生Git推送时触发pipeline,接下来添加分支筛选条件

Type:Include,Branch:“adf_master”,也就是说每当 “adf_publish” 发生git 推送的时候,触发此 pipeline

设置完毕后,点击 “Save” 进行保存

我们可以手动 “创建Release”,测试 pipeline 状态显示正常,成功

回到Azure UAT 环境中,我们可以发现 UAT 环境的ADF的 pipeline dataset 等也已经部署配置成功

4,测试ADF 自动化部署

我们回到ADF的 Dev 环境,我们尝试在ADF Dev 环境创建一个的新的 “Feature Branch” 尝试更改 pipeline 中复制数据的名称

我们将上图中的Copy Data 的名称由 “Copy data1” 改为 “Copy data2”,并且进行保存,验证操作。

验证没有问题后,我们就可以将当前 “allen/Feature_1” 分支上的更改合并到 “master” 分支上

通过提交 “Create pull request”

接下来我就不再演示了,有什么的不懂的,大家可以去看上一篇文章。等待合并完成后,我们回到Dev 环境的ADF 中就可以在 “master” 分支进行发布了。当发布完成后,就会将最新更改推送到 "adf_master" 分支上的 ARM 模板以及参数等。这个时候就会触发之前设置好的Azure DevOps pipeline 了,就可以自动就这些更改自动部署到UA环境了。

三,结尾

  今天的内容着重介绍了一下Azure Data Factory 与Azure Pipeline 的集成和自动化部署,但是同样的也遗留了一个问题,就是在部署ARM 模板的时候,我们时直接将Blob Storage 的链接字符串直接粘贴到覆盖模板参数一栏中,如果ADF 中添加很多数据源的化,使用直接这种方式也是不合适的,这个问题怎么解决,下一节我们继续。*★,°*:.☆( ̄▽ ̄)/$:*.°★* 。

作者:Allen

版权:转载请在文章明显位置注明作者及出处。如发现错误,欢迎批评指正。

Azure Data Factory(三)集成 Azure Devops 实现CI/CD的更多相关文章

  1. Azure Data Factory(一)入门简介

    一,引言 今天分享一个新的Azure 服务-----Azure Data Factory(Azure 数据工厂),怎么理解,参考根据官方解释-----数据工厂解释:大数据需要可以启用协调和操作过程以将 ...

  2. Azure Data Factory(四)集成 Logic App 的邮件通知提醒

    一,引言 上一篇有介绍到使用Azure Data Factory 复制数据,然后有集成 Azure DevOps 实现CI/CD,但是对于真正的项目来说,这些肯定是不够的,比如说在执行 Azure P ...

  3. Azure Data Factory(二)复制数据

    一,引言 上一篇主要只讲了Azure Data Factory的一些主要概念,今天开始新的内容,我们开始通过Azure DevOps 或者 git 管理 Azure Data Factory 中的源代 ...

  4. Azure Data Factory(五)Blob Storage 密钥管理问题

    一,引言 之前讲解的ADF 集成Azure DevOps 实现CI/CD,在 Releases Pipeline 阶段,我们是将两个 Blob Storage 的链接字符串复制.粘贴到 "O ...

  5. ADF 第一篇:Azure Data Factory介绍

    Azure Data Factory(简写 ADF)是Azure的云ETL服务,简单的说,就是云上的SSIS.ADF是基于云的ETL,用于数据集成和数据转换,不需要代码,直接通过UI(code-fre ...

  6. 持续集成、持续交付(CI/CD)开篇,先来唠唠嗑

    前言 现在稍微有点规模的系统,很多都是采用分布式/微服务架构,将一个大系统拆分为很多个功能模块进行开发.测试.发布.管理等,如果全部流程都采用人工的形式进行的话,效率肯定是超级不高效滴.而且现在很多项 ...

  7. Azure 静态 web 应用集成 Azure 函数 API

    前几次我们演示了如果通过Azure静态web应用功能发布vue跟blazor的项目.但是一个真正的web应用,总是免不了需要后台api服务为前端提供数据或者处理数据的能力.同样前面我们也介绍了Azur ...

  8. Azure基础(三)- Azure的物理架构和服务保证

    Azure fundamentals - Core Cloud Services - Azure architecture and service guarantees Azure provides ...

  9. Devops、CI\CD、Jenkins

    Devops DevOps对应用程序发布的影响 在很多企业中,应用程序发布是一项涉及多个团队.压力很大.风险很高的活动.然而在具备DevOps能力的组织中,应用程序发布的风险很低,原因如下 [2] : ...

随机推荐

  1. centos7安装YouCompleteMe,vim打造成C++的IDE

    一.安装python3 1.安装编译工具 yum -y groupinstall "Development tools" yum -y install zlib-devel bzi ...

  2. 027 01 Android 零基础入门 01 Java基础语法 03 Java运算符 07 逻辑“与”运算符

    027 01 Android 零基础入门 01 Java基础语法 03 Java运算符 07 逻辑"与"运算符 本文知识点:Java中的逻辑"与"运算符 逻辑运 ...

  3. sklearn训练模型的保存与加载

    使用joblib模块保存于加载模型 在机器学习的过程中,我们会进行模型的训练,最常用的就是sklearn中的库,而对于训练好的模型,我们当然是要进行保存的,不然下次需要进行预测的时候就需要重新再进行训 ...

  4. 【git】关联本地仓库与远程仓库

    1.在远程建立一个空项目[项目名称]2.git init3.git remote add origin [git 地址]4.git pull origin master5.git push origi ...

  5. 跨境 TCP 传输优化实录 — 使用 BBR 解决 LFN 问题

    背景 近期开通了一条访问美国机房的 1G 专线,用于提供行情数据备源,并基于 TCP 建立了一套数据传输服务.上线后发现一个严重的问题:应用程序发送队列中的数据大量积压,最终导致程序 OOM Kill ...

  6. 多测师讲解接口测试 —jmeter接数据库(004)_高级讲师肖sir

    1.连接数据库jar包 2. 3. jdbc:mysql://192.168.153.131:3306/baoan?zeroDateTimeBehavior=convertToNull&all ...

  7. Jenkins环境搭建(7)-集成钉钉消息推送

    在去年的时候,搭建了一套Jenkins环境,基本功能已实现,可以通过如下地址查阅. Jenkins环境搭建(1)-下载与安装 Jenkins环境搭建(2)-搭建jmeter+ant+jenkins自动 ...

  8. 什么是 C 和 C ++ 标准库?学编程的你应该知道这些知识!

    简要介绍编写C/C ++应用程序的领域,标准库的作用以及它是如何在各种操作系统中实现的. 我已经接触C++一段时间了,一开始就让我感到疑惑的是其内部结构:我所使用的内核函数和类从何而来? 谁发明了它们 ...

  9. linux(centos8):配置docker的cgroup driver为systemd

    一,为什么要修改docker的cgroup driver? 1,什么是cgroups? cgroups(Control Groups) 是 linux 内核提供的一种机制 它可以限制.记录任务组所使用 ...

  10. Excel中外部数据链接无法删除的解决方法【转】

    [摘要] 当Excel中公式引用了外部数据,每次打开时,总是自动弹出自动更新链接的对话框.如何找到这些链接?有没有办法实现断开原有链接,而保持数值不变? 有客户反应,当Excel无法链接到外部数据后, ...