? ? ? ? 最近工作上需要打架一個(gè)Azure pipeline,借此機(jī)會(huì)把Azure pipeline學(xué)習(xí)了一下。主要參考的資料是微軟官方文檔。感覺學(xué)習(xí)的過程還是有些痛苦的,主要原因是之前對(duì)pipeLine沒有太多概念。只是知道它可以自動(dòng)對(duì)程序進(jìn)行編譯。官方文檔知識(shí)點(diǎn)比較多,內(nèi)容寫的很詳細(xì)。我只是挑了些我目前用的到的內(nèi)容進(jìn)行了學(xué)習(xí)。學(xué)習(xí)后的感觸是,pipeLine功能確實(shí)很強(qiáng),可以做很多事情,對(duì)于整個(gè)項(xiàng)目開發(fā)流程都能提供很多幫助。我目前用涉及到的主要就是編譯程序,執(zhí)行前后處理操作,下載編譯好的程序文件等功能。其他關(guān)于測(cè)試,部署的內(nèi)容還沒有涉及。
一、yaml語言介紹
? ? ? ? 首先需要了解的是yaml語言。這個(gè)語言是目前官網(wǎng)上推薦的創(chuàng)建管道的描述語言。它的音標(biāo)是/?j?m?l/,尾音類似camel駱駝。這個(gè)語言是Json的一個(gè)超集。一個(gè)yaml文件中描述了一個(gè)數(shù)據(jù)對(duì)象。這個(gè)數(shù)據(jù)對(duì)象包含了一些鍵值對(duì)(可以把這個(gè)對(duì)象理解為一個(gè)map)。這個(gè)對(duì)象可能是嵌套結(jié)構(gòu)的,也就是說,有些key對(duì)應(yīng)的值可能也是對(duì)象。此外,在對(duì)象中還可以包含數(shù)組。
? ? ? ? yaml語言的語法比較簡(jiǎn)單,其中需要注意的是,不同層級(jí)鍵值對(duì)需要顯示進(jìn)行縮進(jìn)。以下是一個(gè)簡(jiǎn)單的yaml文檔示例。
house:
family:
name: Doe
parents:
- John
- Jane
children:
- Paul
- Mark
- Simone
address:
number: 34
street: Main Street
city: Nowheretown
zipcode: 12345
? ? ? ? yaml語言中,字符串首尾的單引號(hào)或雙引號(hào)是可選的。但是如果字符串中包含一些特殊字符,則字符串首尾需要加上單引號(hào)或雙引號(hào)。例如:
special_characters: "[ John ] & { Jane } - <Doe>"
? ? ? ? 對(duì)于多行字符串可以用”|“或”>>“符號(hào)表示,例如:
literal_block: |
This entire block of text will be the value of the 'literal_block' key,
with line breaks being preserved.
folded_style: >
This entire block of text will be the value of 'folded_style', but this
time, all newlines will be replaced with a single space.
? ? ? ? 這兩個(gè)符號(hào)不同之處在于:”|“這個(gè)符號(hào)會(huì)把字符串中的換行符轉(zhuǎn)換為‘\n’字符。而”>>“符號(hào)會(huì)把字符串中的換行符直接丟掉。
? ? ? ? yaml語言中數(shù)組表示方法如下所示:?
a_sequence:
- Item 1
- Item 2
- 0.5 # sequences can contain disparate types.
- Item 4
- key: value
another_key: another_value
- - This is a sequence
- inside another sequence
- - - Nested sequence indicators
- can be collapsed
其中‘-’符號(hào)用于顯示說明縮進(jìn)量,縮進(jìn)量相同的項(xiàng)屬于同一個(gè)數(shù)組,縮進(jìn)量更大的項(xiàng)數(shù)據(jù)屬于子數(shù)組。數(shù)組中的項(xiàng)數(shù)據(jù)類型可以不同。
以上就是yaml的一些基本知識(shí),也是pipeLine中會(huì)用到的內(nèi)容。更詳細(xì)的內(nèi)容可以參考以下鏈接:
Learn yaml in Y Minutes (learnxinyminutes.com)
二、pipeLine基本知識(shí)
? ? ? ? 說到pipeLine基礎(chǔ)概念,需要展示如下圖片:
??? ? ?
?????????一個(gè)pipeline由stage組成,stage由job組成,job由step組成。step有兩種類型:一個(gè)是task,另一個(gè)是script。
? ? ? ? stage是一個(gè)比較大的邏輯單元, 每個(gè)pipeline必須有一個(gè)stage。是否需要多個(gè)stage可以根據(jù)具體情況來確定,通常是考慮如下因素:
? ? ? ? 1、pipeline中是否有多個(gè)比較大塊的邏輯單元,比如說存在創(chuàng)建,測(cè)試,部署這種功能分類。如果有可以考慮將他們劃分為不同的stage
? ? ? ? 2、pipeline中是否需要驗(yàn)證許可(approval),如果需要驗(yàn)證,那么可以按照許可需要驗(yàn)證的job集合,將job劃分為不同的stage。
? ? ? ? 3、如果有些job運(yùn)行時(shí)間很長(zhǎng),那么可以將他們劃為獨(dú)立的stage
? ? ? ? 在pipeline中job是一個(gè)在代理中獨(dú)立運(yùn)行的單元(agent)。這里需要解釋一下什么是代理。代理是服務(wù)器提供的一個(gè)運(yùn)行環(huán)境(可以是虛擬機(jī)或是容器),在這個(gè)環(huán)境中預(yù)裝了一些應(yīng)用程序,比如編譯器,操作系統(tǒng),cmd等。pipeline運(yùn)行的時(shí)候會(huì)為每一個(gè)job選擇一個(gè)滿足它要求的代理,并依次執(zhí)行它的steps。代理在執(zhí)行job的時(shí)候被創(chuàng)建,執(zhí)行之后被銷毀。因此每次代理運(yùn)行的時(shí)候都是全新的。如果需要多個(gè)job并行運(yùn)行,需要將每個(gè)job放入不同的代理中進(jìn)行同時(shí)處理。
? ? ? ? step是最小的執(zhí)行單元,它分為task和script。其中script包含的就是命令行字符串。task則是各種預(yù)定義的任務(wù)。這些任務(wù)類型很廣泛,其中包括各種編譯任務(wù),對(duì)文件的復(fù)制、刪除任務(wù),編譯結(jié)果上傳、下載任務(wù),文件打包任務(wù)等。使用這些task,僅需要輸入一些參數(shù),就可以定制自己需要的操作。yaml編輯器,提供了很方便的ui界面,可以方便大家對(duì)task進(jìn)行篩選以及指定參數(shù)。具體界面如下:
? 三、pipeline中的表達(dá)式
? ? ? ? pipeline使用的是yaml語言,但是它對(duì)表達(dá)式及變量的語法有特殊要求。這里需要進(jìn)行說明:
? ? ? ? pipeline中表達(dá)式可以用于表示條件(條件后面會(huì)詳細(xì)說明)或者給變量賦值。表達(dá)式可以指定在編譯時(shí)求值或者在運(yùn)行時(shí)求值。以下是指定方式:
? ? ? ? 1、(${{ <expression> }}
)這種形式表示表達(dá)式在編譯時(shí)求值。這種表達(dá)式在開始編譯時(shí)對(duì)這些表達(dá)式進(jìn)行求值,并且將表達(dá)式直接替換為結(jié)果。因此,這種表達(dá)式的值在運(yùn)行時(shí)不會(huì)改變。
? ? ? ? 2、($[ <expression> ]
)這種形式表示表達(dá)式在運(yùn)行時(shí)求值,也就是在每個(gè)step執(zhí)行中被求值
? ? ? ? 3、$(<expression>
)這種形式表示表達(dá)式在step執(zhí)行前被求值,在step運(yùn)行過程中,表達(dá)式的值不會(huì)改變。每個(gè)step開始前,step中對(duì)應(yīng)的表達(dá)式會(huì)被替換為表達(dá)式的值。
四、變量
? ? ? ? 變量定義的方式如下:? ? ??
variables:
- name: projectName
value: contoso
- name: fileName
value: output
? ? ? ? pipeline中變量可以在多種位置進(jìn)行定義。在不同位置定義的變量具有不同的作用域,具體如下:
? ? ? ? 1、在yaml文件最外層定義的變量具有全局作用域,所有job都可以訪問這些變量
? ? ? ? 2、在stage中定義的變量只有屬于這個(gè)stage的job可以訪問
? ? ? ? 3、在job中定義的變量只有屬于這個(gè)job的step能夠訪問
? ? ? ? 如果出現(xiàn)同名的變量,那么內(nèi)層定義的變量會(huì)覆蓋外層定義的變量? ?
變量可以按照三種方式求值(對(duì)應(yīng)于三種表達(dá)式求值方式):
? ? ? ? 1、模板表達(dá)式求值方式:${{ variables.var }},這種形式的變量求值發(fā)生在編譯階段。
? ? ? ? 2、宏語法求值方式:$(var),這種形式的變量求值發(fā)生在每個(gè)step開始之前。
? ? ? ? 3、運(yùn)行時(shí)表達(dá)式求值方式:$[variables.var],這種方式的變量求值發(fā)生在step運(yùn)行過程中。
變量引用方式:
? ? ? ? 1、索引形式:variables['MyVar']
? ? ? ? 2、解引用形式:variables.MyVar
變量修改方式:
? ? ? ? 1、可以在yaml文檔中對(duì)已定義的變量進(jìn)行賦值,如下圖所示:
variables:
configuration: debug
platform: x64
? ? ? ? 2、還可以在命令行中修改變量的值,如下圖所示:
steps:
# Create a variable
- bash: |
echo "##vso[task.setvariable variable=sauce]crushed tomatoes" # remember to use double quotes
# Use the variable
# "$(sauce)" is replaced by the contents of the `sauce` variable by Azure Pipelines
# before handing the body of the script to the shell.
- bash: |
echo my pipeline variable is $(sauce)
? ? ? ? ?在這種方式中,用到了logging命令,它用于在step和代理之間傳遞信息。在這里,step調(diào)用了task.setvariable命令用于修改變量值或是創(chuàng)建變量。通過這種方式創(chuàng)建的變量可以被后續(xù)step進(jìn)行訪問。? ?
? ? ? ? pipeline中還有一些預(yù)定義的變量,這些變量在運(yùn)行時(shí),會(huì)被代理自動(dòng)賦值。其中比較常用的是build.SourcesDirectory變量,他表示了庫文件所在的根目錄,其他預(yù)定義變量可參考如下鏈接:Predefined variables - Azure Pipelines | Microsoft Learn
? ? ? ? 在這里需要說明的是,pipeline中的變量只能存儲(chǔ)字符串類型的值。
五、參數(shù)
? ? ? ? 可以在yaml文檔中指定參數(shù)(parameters)。參數(shù)不同于變量,他可以存儲(chǔ)各種類型的值。但是他僅能采用模板表達(dá)式方式進(jìn)行求值(${{parameter}})。以下是一個(gè)參數(shù)定義示例:? ??
parameters:
- name: image
displayName: Pool Image
type: string
default: ubuntu-latest
values:
- windows-latest
- ubuntu-latest
- macOS-latest
????????定義參數(shù)的時(shí)候必須指定name字段及type字段,其他字段是可選的。
????????以下是一個(gè)使用參數(shù)的例子:
parameters:
- name: image
displayName: Pool Image
type: string
default: ubuntu-latest
values:
- windows-latest
- ubuntu-latest
- macOS-latest
trigger: none
jobs:
- job: build
displayName: build
pool:
vmImage: ${{ parameters.image }}
steps:
- script: echo building $(Build.BuildNumber) with ${{ parameters.image }}
? ? ? ? 當(dāng)在yaml文檔中定義了參數(shù)之后,在運(yùn)行管道的ui界面中可以對(duì)這些參數(shù)進(jìn)行賦值。如下圖所示:
????????在這個(gè)例子中,在運(yùn)行管道的ui界面中可以選擇要使用的代理池。之后pipeline會(huì)按照用戶指定的選項(xiàng)運(yùn)行pipeline。?
五、condition
? ? ? ? 默認(rèn)情況下,stage、job只有當(dāng)它們沒有依賴項(xiàng)或者它們依賴的項(xiàng)都執(zhí)行成功它們才會(huì)被執(zhí)行。默認(rèn)情況下,當(dāng)step所在的job沒有其他step執(zhí)行失敗,且它前面的一個(gè)step執(zhí)行成功后他才會(huì)被執(zhí)行。通過condition可以修改這種默認(rèn)行為,如下所示:
jobs:
- job: Foo
steps:
- script: echo Hello!
condition: always() # this step will always run, even if the pipeline is canceled
- job: Bar
dependsOn: Foo
condition: failed() # this job will only run if Foo fails
? ?在這個(gè)例子中,采用了job狀態(tài)函數(shù)表達(dá)式來指定運(yùn)行條件。(在pipeline中包含了一些預(yù)定義函數(shù)。這些函數(shù)可以作為表達(dá)式進(jìn)行求值。預(yù)定義函數(shù)可參考鏈接:Expressions - Azure Pipelines | Microsoft Learn)。
還可以在條件中根據(jù)變量值決定任務(wù)是否執(zhí)行
variables:
isMain: $[eq(variables['Build.SourceBranch'], 'refs/heads/main')]
stages:
- stage: A
jobs:
- job: A1
steps:
- script: echo Hello Stage A!
- stage: B
condition: and(succeeded(), eq(variables.isMain, 'true'))
jobs:
- job: B1
steps:
- script: echo Hello Stage B!
- script: echo $(isMain)
六、代理
? ? ? ? 在這里再啰嗦的說一些有關(guān)代理的內(nèi)容,之前提到過,代理是job運(yùn)行的一個(gè)環(huán)境(可以是虛擬機(jī)或是容器),在這個(gè)環(huán)境中安裝了job運(yùn)行所需的編譯器,操作系統(tǒng),以及其他一些程序。微軟為用戶提供了多種代理。具體資料可以參考如下鏈接:Microsoft-hosted agents for Azure Pipelines - Azure Pipelines | Microsoft Learn
? ? ? ? 此外用戶還可以自己創(chuàng)建代理,這方面的知識(shí)目前還沒有太深入的學(xué)習(xí)。
用戶可以在yaml文件中顯示指定代理需要滿足的各種需求。比如:
?在這兩個(gè)例子中,用戶指定了滿足要求的代理需要安裝的特定程序以及所需要的代理版本編號(hào)。
所有代理是通過代理池進(jìn)行管理的。編寫yaml文件時(shí),指定的是代理池,而不是具體的代理。運(yùn)行時(shí)pipeline會(huì)從指定的代理池中選取滿足要求的代理運(yùn)行job。
六、觸發(fā)器
可以通過觸發(fā)器指定pipeline自動(dòng)執(zhí)行的條件。默認(rèn)情況下對(duì)于所有分支,如果有新的提交那么pipeline就會(huì)被自動(dòng)執(zhí)行??梢酝ㄟ^如下方式,指定僅某些分支有新的提交才觸發(fā)pipeline:
? ??
?在這個(gè)例子中,僅master分支以及名字以release/開頭的分支有新的提交時(shí)pipeline才被自動(dòng)觸發(fā)。
也可以通過以下方式,指定僅能通過手動(dòng)方式進(jìn)行觸發(fā)
七、pipeline執(zhí)行順序
? ? ? ? pipeline按照如下順序運(yùn)行:
? ? ? ? 1、對(duì)模板及模板表達(dá)式進(jìn)行展開
? ? ? ? 2、計(jì)算每個(gè)stage的依賴關(guān)系,并選出第一個(gè)被運(yùn)行的stage
? ? ? ? 3、對(duì)于每一個(gè)將要被運(yùn)行的stage,需要執(zhí)行如下操作
? ? ? ? ? ? ? ? (1)收集jobs所需的所有資源,并驗(yàn)證所有job授權(quán)是否有效
? ? ? ? ? ? ? ? (2)計(jì)算jobs的依賴關(guān)系,并選出第一個(gè)被運(yùn)行的job
? ? ? ? 4、對(duì)于每一個(gè)將被運(yùn)行的job,對(duì)他的condition進(jìn)行求值,判斷這個(gè)job是否被運(yùn)行。
? ? ? ? 5、為符合運(yùn)行條件的job請(qǐng)求一個(gè)代理
? ? ? ? 當(dāng)一個(gè)job運(yùn)行完畢,pipeline會(huì)查找是否還有滿足運(yùn)行條件的job,如果有則重復(fù)4、5步驟。同樣的,如果一個(gè)stage執(zhí)行完畢,會(huì)對(duì)下一個(gè)stage執(zhí)行2-5步驟。
? ? ? ? 以上運(yùn)行順序也解釋了為什么模板表達(dá)式的值不會(huì)在job運(yùn)行時(shí)改變,因外在pipeline開始執(zhí)行的之前,模板表達(dá)式就被求值,并且把文檔中模板表達(dá)式出現(xiàn)的位置替換為所求得的值。因此在job運(yùn)行的時(shí)候模板表達(dá)式已經(jīng)不存在了。
七、實(shí)例
? ? ? ? 以上講了關(guān)于pipeline的一些基礎(chǔ)知識(shí)以及個(gè)人的一些理解。接下來想給大家展示一個(gè)應(yīng)用pipeline的例子。
? ? ? ? 首先需要?jiǎng)?chuàng)建一個(gè)庫? ?,這個(gè)庫中的程序比較簡(jiǎn)單,只是在命令行中輸出hello world而已。這里僅僅為了演示pipeline所以程序復(fù)雜與否并不重要。
? ? ? ? 之后進(jìn)到pipeline tab頁中,點(diǎn)擊new pipeline按鈕
?因?yàn)槲业倪@個(gè)庫是一個(gè)Azure Repos,所以選擇第一個(gè)選項(xiàng)
?在界面中選擇pipeline要關(guān)聯(lián)的庫
?在這個(gè)界面中我選擇了最小pipeline選項(xiàng)
?執(zhí)行完以上操作后,pipeline會(huì)為我們生成一份yaml文檔。在這份初始文檔中,僅僅是描述了兩個(gè)script,這些script只是在控制臺(tái)中輸出一些字符串而已。(這里需要提醒大家的是,需要點(diǎn)擊保存,否則之前的操作就白做了)
?以下是我自己寫的一份yaml文檔。其中使用了MSBuild任務(wù)、Publish Pipeline Artifacts任務(wù)以及Download Pipeline Artifacts任務(wù)。這個(gè)pipeline做的事情很簡(jiǎn)單,首先是對(duì)程序進(jìn)行編譯,之后在代理中運(yùn)行編譯好的exe程序,在控制臺(tái)中輸出hello world,其后是是將編譯結(jié)果上傳到pipeLine公共區(qū)域,最后將編譯結(jié)果在下載回代理指定目錄中,并在下載目錄中執(zhí)行程序。
trigger:
- main
pool:
vmImage: windows-latest
steps:
- task: VSBuild@1
inputs:
solution: 'testPipeLine\testPipeLine.sln'
platform: 'x64'
configuration: 'debug'
msbuildArchitecture: 'x64'
displayName: 編譯程序
- script: |
cd $(Build.SourcesDirectory)\testPipeLine\x64\Debug
testPipeLine.exe
displayName: 在生成目錄中運(yùn)行程序
- publish: $(Build.SourcesDirectory)\testPipeLine\x64\Debug\
artifact: WebApp
displayName: 將生成的程序上傳至公共區(qū)
- task: DownloadPipelineArtifact@2
inputs:
buildType: 'current'
artifactName: 'WebApp'
targetPath: 'D:\學(xué)習(xí)\代碼\testPipeLine\testPipeLine'
displayName: 將生成的程序下載到指定目錄下
- script: |
cd D:\學(xué)習(xí)\代碼\testPipeLine\testPipeLine
testPipeLine.exe
displayName: 在下載目錄中運(yùn)行程序
執(zhí)行結(jié)果如下:
?這個(gè)管道觸發(fā)器指定的是當(dāng)main分支有提交時(shí)被觸發(fā)。
?八、總結(jié)
? ? ? ? 以上就是我這段時(shí)間學(xué)習(xí)的一些總結(jié),內(nèi)容比較簡(jiǎn)單,沒有設(shè)計(jì)太多關(guān)于部署的內(nèi)容。對(duì)更復(fù)雜的pipeline yaml語言特性也沒有涉及。但是他已經(jīng)可以滿足我目前工作中的需求。其中有不足和錯(cuò)誤的地方還請(qǐng)各位大神指教。文章來源:http://www.zghlxwxcb.cn/news/detail-443325.html
?文章來源地址http://www.zghlxwxcb.cn/news/detail-443325.html
到了這里,關(guān)于Azure Pipeline入門的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!