說明
這里先介紹下兩個東西 CI/CD、GitLab Runner,當然在此之前你需要對 git 有所了解,關於 git 這里不做說明,可以自行百度。
首先介紹 CI/CD :隨着我們開發方式的轉變,程序的發布變得非常頻繁,而其這些發布操作都是重復的。CI/CD 就是為了使這些操作能變得自動化,那它是怎么實現自動化的呢?其實它做的就是當我們使用 git push(推送)代碼的時候會執行 任務(task) 而這個 任務 里面其實又包含多個 作業(job),如對代碼進行單元測試、部署項目等等,這些 任務 和 作業 在 gitlab 中其實是以一個 .gitlab-ci.yml 文件存在的,這個文件后面會說明。好了我們知道了 CI/CD 是什么(心虛~,你們可以自行百度查看更詳細的說明。),那么到底是誰在執行這些 任務 和 作業 的呢?這就是下面要介紹的 GitLab Runner。
GitLab Runner:GitLab Runner 就是用來運行我們定義好的 任務 和 作業 也就是 .gitlab-ci.yml 文件。Runner 分為 Shared Runner(共享型) 和 Specific Runner(專有型),Shared Runner 是所有的項目都能用,但只能由管理員創建,而 Specific Runner(專有型)只能為指定的項目服務。Shared Runner 一般是用在有多個項目的服務器上,Specific Runner 則是單個項目的服務器,或者是你自己的電腦上。
下面列出我本次使用的環境:
操作系統:Windows 10
項目版本:.NET Core 2.2
腳本執行環境:PowerShell 5.1.17763.316
Web服務器:IIS 10.0
Gitlab:使用 gitlab.com (*Gitlab 支持私有化部署 )
項目地址:https://gitlab.com/WigorRunnerTest

Gitlab CI/CD
首先你需要在 GitLab 上注冊個賬號,這里需要使用你懂的工具上網,因為它使用了谷歌的 reCAPTCHA,如果你是自己部署的 gitlab 將沒有這個問題。如果大家有需要請留下郵箱。
Gitlab 設置中文界面
Gitlab 默認的界面是英文的,只需要點擊頭像行的 Settings,然后點擊 左側導航欄 的 Preferences,之后在滑到最底部找到 Localization 旁邊的 Language 選擇 簡體中文,最后點擊 Save changes,F5 刷新頁面即可。
設置好后我們可能更方便的操作 gitlab 了,接着我們需要創建一個項目,這里將使用一個 DotNET Core 項目為例。創建好項目后我們需要將它先 clone 到本地。
下載 Gitlab Runner
在我們定義 任務 和 作業 之前我們需要在我們的服務器或者是電腦上安裝好 Gitlab Runner。
官網下載地址:https://docs.gitlab.com/runner/install/
下面是我整理好的下載地址,本次使用的是 Windows amd64:
下載好后,找到你下載的目錄,將軟件重命名為 gitlab-runner.exe。只用使用 cmd 進入到該目錄,需要注意的是你需要以 管理員 的方式運行 cmd,否者后面執行命令的時候會報錯。

注冊 Gitlab Runner
接着在命令行中輸入:
gitlab-runner register
這時會出現提示:Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
它叫你輸入協調器的地址,這個地址是在你 gitlab 項目的 左側導航欄 ,設置 下的 CI/CD 中,找到 Runner 點擊展開,就會看到 專有Runner 和 共享Runner ,這里我們使用 專有Runner 做演示說明。紅色框中的東西是我們后面需要用到的東西。

好了我們有了 coordinator URL 把它復制下了,粘貼到剛剛的命令中回車。
出現了另外一個提示:Please enter the gitlab-ci token for this runner:,需要你輸入 token ,這個 token 就是你剛剛復制 URL 下面的 注冊令牌。接着它要你輸入這個 Runner 的描述,這個根據自己的情況填。
之后又來一個提示:Please enter the gitlab-ci tags for this runner (comma separated):,需要我們輸入 Runner 的標簽,這里我使用 deploy。
最后一個提示:Please enter the executor: docker, virtualbox, shell, ssh, docker+machine, docker-ssh+machine, kubernetes, docker-ssh, parallels:,需要我們填入腳本的執行環境,這里先填 shell,這時你的 gitlab-runner.exe 下會生成一個 config.toml 文件,里面保存着我們剛剛輸入的信息。

需要注意的是這個標簽就是我們后面編寫
.gitlab-ci.yml里的 job 會用到,它根據 tags 來指派哪些 Runner 會執行該任務和作業。
之后我們回到 gitlab 可以看到這里已經有個激活的運行器了,這里的圖標也變成了綠色。如果你這里顯示的不是綠色,那么你刷新下頁面看看,還不行的話那么你需要運行 gitlab-runner restart 命令來重啟 Runner,接着可以使用 gitlab-runner status 查看 Runner 的運行狀態。出現 gitlab-runner: Service is running! 那么表示你的服務已經運行成功了。 再次強調你的命令需要使用 管理員 身份運行。

將 Shell 改成 PowerShell
上面選擇腳本執行環境的時候我們選了 shell,但是本次我是在 Windows 環境下運行,所以需要將它改為 PowerShell,打開 config.toml 文件,在 [[runners]] 下加入 shell = "powershell" ,然后保存文件即可。

.gitlab-ci.yml 簡單說明
上面已經提過 .gitlab-ci.yml 使用來干什么的了,.gitlab-ci.yml 其實是本次自動化發布的核心,它是放在你 gitlab 上項目的根目錄下。這里將對 .gitlab-ci.yml 該怎么配做一個簡單說明,我只會介紹我用的東西更多的東西你可以查看我下面的「相關文檔」。
首先在項目根目錄下建立一個 .gitlab-ci.yml 文件,代碼如下:
before_script:
- cd src
stages:
- test
# job
test:
stage: test
# 將會執行的腳本
script:
- dotnet restore
- dotnet build
# 哪個分支會執行
only:
- master
#runner 注冊時的 tag,這里指會觸發的 runner
tags:
- deploy
我們來一個個說明這些東西的作用:
before_script 在整個項目 clone 到 Runner 所處的服務器時會先執行這個里面的腳本,這里我是進入到了 src 目錄,你還可以在這里面做一些包還原的操作。
stages 里放的是將會執行的 job。
test 是做作業(job),這個命名你可以根據自己的情況來。test 就是上面 stages 會執行的 job 的真正配置處。
-
stage對應stages中的項,如果一個 job 沒有指定 stage,那么這個任務會分配到test stage。 -
script就是執行的腳本,構建自動化的核心也就是在此處。作為簡單的演示,我就還原了包和生成項目。 -
only是值該 job 會在被哪些分支 push 觸發。 -
tags上面在我們注冊時有提到過,這個tags對應的是我們注冊gitlab runner時所填的tages,表示的是該 job 會觸發哪些 Runner。
OK,我們此時已經將一個最簡單的 .gitlab-ci.yml 構建好了,在項目根目錄下執行 git commit -am "[init] .gitlab-ci.yml",git push,將配置好的文件 push(推送)到遠端。回到 gitlab 中,我們點擊 CI/CD 可以看到有一個流水線在運行。

點進去可以看到運行的日志,可以看到我們 before_script、script 中的命令在一條條的執行,當然如果你的腳本出現了錯誤,狀態會是 失敗,你需要檢查你的腳本是否有誤。如果你的狀態一直處於 等待中 那么需要檢查你的 gitlab runner 是否允許正常,以及上面提到的 設置 中的 Runner 是否處於激活狀態(綠色圖標)。

輸出亂碼問題解決
你可能發現了這里怎么有一些奇怪的字符,這是因為我的操作系統是中文,亂碼了解決辦法是在 before_script 加入 - chcp 65001 腳本。
再次提交代碼,ok 這次的中文信息顯示正確了。

變量作用的說明
.gitlab-ci.yml 是存放在我們項目的根目錄下的,如果我們項目使開源的,那么我們將會暴露一些私密信息如token,密鑰,項目發布所處服務器的路徑,這些信息公開可能會使我們的項目存在安全隱患。亦或者我們需要部署多個項目但是它們的 .gitlab-ci.yml 文件十分相似那么我們就可以通過變量控制哪些可變的因素。
那么到底怎么使用變量呢?第一步我們需要先聲明變量,在 gitlab 的項目中找到 設置 下的 CI/CD,可以看到 變量 然后展開,這里就是可以聲明我們需要用到的變量。.gitlab-ci.yml 只需要在腳本需要用到變量的方法使用 $env:變量名 的形式使用即可,需要注意的是:不同的系統使用變量的方法也不一樣,這里我使用是 PowerShell。

常用的變量使用方法:
| Shell | 使用方法 |
|---|---|
| bash/sh | $variable |
| windows batch | %variable% |
| PowerShell | $env:variable |
關於變量的更多說明可以參考官方的文檔:https://gitlab.com/help/ci/variables/README#variables
自動化部署到 IIS
前面已經介紹了構建一個自動化的流程,有了前面的基礎其實自動化部署到 IIS 也就是編寫的腳本發生了變化。
再開干之前我們需要把我們的思路捋一捋,核心在於怎么通過命令的形式發布一個站點。
- 首先需要編譯項目,確保代碼沒有問題
- 使用
dotnet publish -c release -r win81-x64獲取我們需要發布站點的部署文件 - IIS 停止運行需要發布的站點
- IIS 停止該站點的進程池
- 備份原有項目(不是必須,但是最好不要省去該步驟)
- 刪除 IIS 上需要發布的站點的原有文件
- 復制我們准備好發布的文件(也就是 publish 文件夾)到 IIS 站點下
- IIS 啟動進程池
- IIS 啟動該站點
下面一步一步已腳本的形式來說明:
- 首先確定整體的東西,這里我准備構建兩個 job
test和deploy,第一個 job 用於校驗我們的代碼是否正確,第二個是部署的 job。第一個 job 只有兩行命令,還原和編譯。
before_script:
#中文亂碼問題
- chcp 65001
- cd src
# 執行的 job
stages:
- test
- deploy
# 校驗代碼
test:
stage: test
# 將會執行的腳本
script:
- dotnet restore
- dotnet build
# 哪個分支會執行
only:
- master
#runner 注冊時的 tag,這里指會觸發的 runner
tags:
- deploy
# 部署
deploy:
stage: deploy
# 將會執行的腳本
script:
# 哪個分支會執行
only:
- master
#runner 注冊時的 tag,這里指會觸發的 runner
tags:
- deploy
- 在進行編寫剩下的腳本之前需要定義幾個變量:
ProjectName:項目名稱,用於 publish 用,如 VS 下一個解決方案可能存在多個項目,這時候就需要知道我們 publish 的項目使哪個。
WebSiteName:站點名稱,用戶關閉 IIS 站點和 IIS 對應進程池的,如果你的進程池和站點的名稱不一致請在聲明一個變量。
WebSitePath:站點的路徑,用於備份、刪除原有站點、新的項目復制到該路徑下。

定義好這些變量后接着寫我們 deploy 的腳本:
可以看到這里使用了:$env:ProjectName、$env:WebSitePath、$env:WebSiteName 變量。
# 部署
deploy:
stage: deploy
# 將會執行的腳本
script:
# 聲明一個變量保存當前時間,用作備份數據文件夾名稱
- $datetime=Get-Date -Format 'yyyy-MM-dd-HH-mm'
# 編譯打包項目
- dotnet publish -c release -r win81-x64
# 進入編譯好的項目目錄
- cd $env:ProjectName\bin\Release\netcoreapp2.2\win81-x64\
# 停止 IIS 對應站點
- C:\Windows\System32\inetsrv\appcmd.exe stop site $env:WebSiteName
# 停止進程池
- C:\Windows\System32\inetsrv\appcmd.exe stop apppool /apppool.name:"$env:WebSiteName"
# 備份原有項目文件,項目名_當前時間
- cp "$env:WebSitePath" "$env:WebSitePath$datetime" -Recurse
# 刪除原有站點
- del "$env:WebSitePath" -Recurse
#復制 publish 文件到站點
- cp "publish" "$env:WebSitePath" -Recurse
# 啟動進程池
- C:\Windows\System32\inetsrv\appcmd.exe start apppool /apppool.name:"$env:WebSiteName"
# 啟動 IIS 站點
- C:\Windows\System32\inetsrv\appcmd.exe start site $env:WebSiteName
# 哪個分支會執行
only:
- master
#runner 注冊時的 tag,這里指會觸發的 runner
tags:
- deploy
到這一步整個自動化發布已經完成了,我們只要 push 代碼到遠端就會自動部署我們的項目到 IIS 中,需要注意的是你必須確保你的 IIS 中已經有這個站點了。
回到 gitlab 中查看 CI/CD 可以看到這次我們的階段有兩個,因為我配置了兩個 作業(job),一個 test一個 deploy。

點擊每個作業中看看執行的腳本是不是我們定義好的,需要提一下 powershell 腳本如果出錯的話 gitlab-ci 返回的結果還是會顯示成功,錯誤提示還是亂碼的,坑啊。額~目前還找到解決的辦法,如果是 docker 或者 linux 下應該沒有這問題。

再看看 IIS 這邊的效果,文件已經自動備份了,站點也正常運行了,一個自動化部署項目到 IIS 站點已經完成了。


模擬項目發布
下面修改代碼然后 push 上去看看,看看我們的網站沒有沒有更新。

完整的 .gitlab-ci.yml
before_script:
#中文亂碼問題
- chcp 65001
- cd src
# 執行的 job
stages:
- test
- deploy
# 校驗代碼
test:
stage: test
# 將會執行的腳本
script:
- dotnet restore
- dotnet build
# 哪個分支會執行
only:
- master
#runner 注冊時的 tag,這里指會觸發的 runner
tags:
- deploy
# 部署
deploy:
stage: deploy
# 將會執行的腳本
script:
# 聲明一個變量保存當前時間,用作備份數據文件夾名稱
- $datetime=Get-Date -Format 'yyyy-MM-dd-HH-mm'
# 編譯打包項目
- dotnet publish -c release -r win81-x64
# 進入編譯好的項目目錄
- cd $env:ProjectName\bin\Release\netcoreapp2.2\win81-x64\
# 停止 IIS 對應站點
- C:\Windows\System32\inetsrv\appcmd.exe stop site $env:WebSiteName
# 停止進程池
- C:\Windows\System32\inetsrv\appcmd.exe stop apppool /apppool.name:"$env:WebSiteName"
# 備份原有項目文件,項目名_當前時間
- cp "$env:WebSitePath" "$env:WebSitePath$datetime" -Recurse
# 刪除原有站點
- del "$env:WebSitePath" -Recurse
- cp "publish" "$env:WebSitePath" -Recurse
# 啟動進程池
- C:\Windows\System32\inetsrv\appcmd.exe start apppool /apppool.name:"$env:WebSiteName"
# 啟動 IIS 站點
- C:\Windows\System32\inetsrv\appcmd.exe start site $env:WebSiteName
# 哪個分支會執行
only:
- master
#runner 注冊時的 tag,這里指會觸發的 runner
tags:
- deploy
小結
至此已經實現了 push 時項目自動發布到 IIS 。當然在這個過程中踩了 n 多的坑,總結要細心安裝步驟一步一步認真的走。下一步准備對接釘釘的機器人。實現的效果是當我們項目發布時會自動通知,發布成功后也會自動通知。
相關文獻
《什么是 CI/CD?》:https://linux.cn/article-9926-1.html
《GitLab-CI與GitLab-Runner》: http://www.cnblogs.com/cnundefined/p/7095368.html
《IIS 站點和進程池關閉》:https://www.cnblogs.com/jmaly/p/9860606.html
《Gitlab-CI job 配置文件 .gitlab-ci.yml 配置方式(翻譯)》:https://blog.csdn.net/kunyus/article/details/81390330
powershell論壇:https://www.pstips.net
GitLab Runner 官方文檔:https://docs.gitlab.com/ee/ci/runners/README.html
