使用 Gitlab CI/CD 實現自動化釋出站點到 IIS

AMortal發表於2019-05-10

說明

這裡先介紹下兩個東西 CI/CDGitLab 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

Runner

Gitlab CI/CD

首先你需要在 GitLab 上註冊個賬號,這裡需要使用你懂的工具上網,因為它使用了谷歌的 reCAPTCHA,如果你是自己部署的 gitlab 將沒有這個問題。如果大家有需要請留下郵箱。

Gitlab 設定中文介面

Gitlab 預設的介面是英文的,只需要點選頭像行的 Settings,然後點選 左側導航欄Preferences,之後在滑到最底部找到 Localization 旁邊的 Language 選擇 簡體中文,最後點選 Save changesF5 重新整理頁面即可。

檢視設定中文教程

設定好後我們可能更方便的操作 gitlab 了,接著我們需要建立一個專案,這裡將使用一個 DotNET Core 專案為例。建立好專案後我們需要將它先 clone 到本地。

下載 Gitlab Runner

在我們定義 任務作業 之前我們需要在我們的伺服器或者是電腦上安裝好 Gitlab Runner

官網下載地址:https://docs.gitlab.com/runner/install/

下面是我整理好的下載地址,本次使用的是 Windows amd64

Windows: 下載x86下載amd64

下載好後,找到你下載的目錄,將軟體重新命名為 gitlab-runner.exe。只用使用 cmd 進入到該目錄,需要注意的是你需要以 管理員 的方式執行 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

好了我們有了 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" ,然後儲存檔案即可。
將 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 的真正配置處。

  1. stage 對應 stages 中的項,如果一個 job 沒有指定 stage,那麼這個任務會分配到test stage。

  2. script 就是執行的指令碼,構建自動化的核心也就是在此處。作為簡單的演示,我就還原了包和生成專案。

  3. only 是值該 job 會在被哪些分支 push 觸發。

  4. tags 上面在我們註冊時有提到過,這個 tags 對應的是我們註冊 gitlab runner 時所填的 tages,表示的是該 job 會觸發哪些 Runner。

OK,我們此時已經將一個最簡單的 .gitlab-ci.yml 構建好了,在專案根目錄下執行 git commit -am "[init] .gitlab-ci.yml"git push,將配置好的檔案 push(推送)到遠端。回到 gitlab 中,我們點選 CI/CD 可以看到有一個流水線在執行。

job

點進去可以看到執行的日誌,可以看到我們 before_scriptscript 中的命令在一條條的執行,當然如果你的指令碼出現了錯誤,狀態會是 失敗,你需要檢查你的指令碼是否有誤。如果你的狀態一直處於 等待中 那麼需要檢查你的 gitlab runner 是否允許正常,以及上面提到的 設定 中的 Runner 是否處於啟用狀態(綠色圖示)。

joblog

輸出亂碼問題解決

你可能發現了這裡怎麼有一些奇怪的字元,這是因為我的作業系統是中文,亂碼瞭解決辦法是在 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

關於變數的更多說明可以參考官方的文件:http://192.168.20.21/help/ci/variables/README#variables

自動化部署到 IIS

前面已經介紹了構建一個自動化的流程,有了前面的基礎其實自動化部署到 IIS 也就是編寫的指令碼發生了變化。

再開幹之前我們需要把我們的思路捋一捋,核心在於怎麼通過命令的形式釋出一個站點。

  1. 首先需要編譯專案,確保程式碼沒有問題
  2. 使用 dotnet publish -c release -r win81-x64 獲取我們需要釋出站點的部署檔案
  3. IIS 停止執行需要釋出的站點
  4. IIS 停止該站點的程式池
  5. 備份原有專案(不是必須,但是最好不要省去該步驟)
  6. 刪除 IIS 上需要釋出的站點的原有檔案
  7. 複製我們準備好釋出的檔案(也就是 publish 資料夾)到 IIS 站點下
  8. IIS 啟動程式池
  9. IIS 啟動該站點

下面一步一步已指令碼的形式來說明:

  1. 首先確定整體的東西,這裡我準備構建兩個 job testdeploy,第一個 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
  1. 在進行編寫剩下的指令碼之前需要定義幾個變數:
    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 下應該沒有這問題。

log

再看看 IIS 這邊的效果,檔案已經自動備份了,站點也正常執行了,一個自動化部署專案到 IIS 站點已經完成了。
檔案
站點

模擬專案釋出

下面修改程式碼然後 push 上去看看,看看我們的網站沒有沒有更新。
使用 Gitlab CI/CD 實現自動化釋出站點到 IIS

完整的 .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

相關文章