Azure Data Factory(三)集成 Azure Devops 实现CI/CD
一,引言
由于上一节文章内容过长,无法分享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的更多相关文章
- Azure Data Factory(一)入门简介
一,引言 今天分享一个新的Azure 服务-----Azure Data Factory(Azure 数据工厂),怎么理解,参考根据官方解释-----数据工厂解释:大数据需要可以启用协调和操作过程以将 ...
- Azure Data Factory(四)集成 Logic App 的邮件通知提醒
一,引言 上一篇有介绍到使用Azure Data Factory 复制数据,然后有集成 Azure DevOps 实现CI/CD,但是对于真正的项目来说,这些肯定是不够的,比如说在执行 Azure P ...
- Azure Data Factory(二)复制数据
一,引言 上一篇主要只讲了Azure Data Factory的一些主要概念,今天开始新的内容,我们开始通过Azure DevOps 或者 git 管理 Azure Data Factory 中的源代 ...
- Azure Data Factory(五)Blob Storage 密钥管理问题
一,引言 之前讲解的ADF 集成Azure DevOps 实现CI/CD,在 Releases Pipeline 阶段,我们是将两个 Blob Storage 的链接字符串复制.粘贴到 "O ...
- ADF 第一篇:Azure Data Factory介绍
Azure Data Factory(简写 ADF)是Azure的云ETL服务,简单的说,就是云上的SSIS.ADF是基于云的ETL,用于数据集成和数据转换,不需要代码,直接通过UI(code-fre ...
- 持续集成、持续交付(CI/CD)开篇,先来唠唠嗑
前言 现在稍微有点规模的系统,很多都是采用分布式/微服务架构,将一个大系统拆分为很多个功能模块进行开发.测试.发布.管理等,如果全部流程都采用人工的形式进行的话,效率肯定是超级不高效滴.而且现在很多项 ...
- Azure 静态 web 应用集成 Azure 函数 API
前几次我们演示了如果通过Azure静态web应用功能发布vue跟blazor的项目.但是一个真正的web应用,总是免不了需要后台api服务为前端提供数据或者处理数据的能力.同样前面我们也介绍了Azur ...
- Azure基础(三)- Azure的物理架构和服务保证
Azure fundamentals - Core Cloud Services - Azure architecture and service guarantees Azure provides ...
- Devops、CI\CD、Jenkins
Devops DevOps对应用程序发布的影响 在很多企业中,应用程序发布是一项涉及多个团队.压力很大.风险很高的活动.然而在具备DevOps能力的组织中,应用程序发布的风险很低,原因如下 [2] : ...
随机推荐
- Linux 串口工具 lsz lrz 移植
//之前写的,刚才不小心误删了,所以重新再发出来. 1 下载源码包 首先下载最新版的lrzsz,地址:https://ohse.de/uwe/software/lrzsz.html.下面以 0.12. ...
- 小白也能看懂的ArrayList的扩容机制
来,话不多说进入正题!我们下面用最简单的代码创建ArrayList并添加11个元素,并 一 一 讲解底层源码:在说之前,给大家先普及一些小知识: >ArrayList底层是用数组来实现的 > ...
- MySQL数据库入侵及防御方法
来自:http://blog.51cto.com/simeon/1981572 作者介绍 陈小兵,高级工程师,具有丰富的信息系统项目经验及18年以上网络安全经验,现主要从事网络安全及数据库技术研究工作 ...
- P1297 单选错位 题解
这是一道我们的考试题 前置芝士 期望 定义:试验中每次可能结果的概率乘以其结果的总和(来自百度某科 滑稽) 性质:\(E(ax+by)\) = \(xE(a)\) * \(yE(b)\) 计算式: \ ...
- C#实现——十大排序算法之选择排序
选择排序法 1.工作原理(算法思路) 给定一个待排序数组,找到数组中最小的那个元素 如果最小元素不是待排序数组的第一个元素,则将其和第一个元素互换 在剩下的元素中,重复1.2过程,直到排序完成. 2. ...
- mac常用指令
mkdir demo //创建一个文件夹 touch index.html // 创建一个html文件 rm rouch index.html //删除找个index.html文件 rmdir dem ...
- 远程触发Jenkins的Pipeline任务
场景 虽然能配置提交代码时触发Jenkins任务,但有时并不需要每次提交代码都触发,而是仅在有需要时才执行. 除了在Jenkins页面上手动执行任务,还可以向Jenkins网站发起HTTP请求,触发指 ...
- 极简 Node.js 入门 - 5.1 创建 HTTP 服务器
极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node 本文更佳阅读体验:https://www.yuque.com/sunluyong/node ...
- Python:MySQL数据库环境相关问题
系统环境 Ubuntu 16.04.2 LTS mysql Ver 14.14 Distrib 5.7.18, for Linux (x86_64) using EditLine wrapper P ...
- 是时候更新手里的武器了—Jetpack最全简析
前言 Android Jetpack想必大家都耳熟能详了,Android KTX,LiveData,Room等等一系列库都是出自 Jetpack.那么 Jetpack到底是什么?又包含哪些你还没用过的 ...