GitLab CI 從小白到入門
Tags: gitlab, ci
Published: 2021-11-29 16:26:49

GitLab CI 是 GitLab 的 CI 服務，本文分享 GitLab CI 的用法，以及配置文件 .gitlab-ci.yml 的寫法。

CI 是 continuous integration 的縮寫，華文叫持續整合或持續集成，通常還會與 continuous delivery、continuous deployment 摻在一起，有人把這些叫成 DevOps，儘管這些工程師黑話各有各的面向，但他們之間涵義上的重疊率真的太高，並且竊以為不斷發明新名詞、新詮釋對理解這些事物沒有幫助，所以我們反璞歸真，就稱之為 CI，因為它的發音比 DevOps 簡單，也不像那兩位 CD 同學會與生活中的 CD 撞名，所以就叫 CI 吧！

## 持續整合…什麼？

CI 是什麼，個人試著用一句話解釋－「**提交程式碼後的自動化作業**」。

自動化作業通常包括三大環節－建置、測試、佈署，具體要怎麼做這三項工作，以 GitLab 來說是由 .gitlab-ci.yml 內的敘述所定義。

以上是極簡 CI 解釋。

### 為什麼做 CI？

因為資訊界目前主流的開發思想是**持續改善**，意即小步伐、快速迭代發佈新版本，目的是縮短 time to market 時間，然而帶來的副作用是每次的小變更都需要耗費大量的人力做建置、測試、佈署的工作，於是我們開始設法讓這三項工作能夠自動化作業。

[持續改善模式的建立源自於二戰時期美國為了滿足當時的軍事需求而誕生的一種快速改進製程的工作模式，並且發揚於戰後的日本](https://en.wikipedia.org/wiki/Kaizen)，在台灣，許多有日系背景的製造業也一直保有持續改善的工作模式。

## GitLab CI

前面提過，GitLab CI 的工作是在 .gitlab-ci.yml 檔案內所定義，而具體執行這些工作的機台稱為 runner，runner 通常都是虛擬機，runner 可以自己搭建也可以用 GitLab.com 提供的 shared runner，在 GitLab 專案的 CI/CD 設定頁內可以看到這些 runner：

![GitLab.com Shared Runners](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8oilgrjodnh390lfs4jf.png)

這些 runner 的代碼或名稱並不重要，重要的是那些藍色的 tag，這些 tag 標註了一個 runner 的特性，例如後面我們會用到 Windows，屆時就會在 .gitlab-ci.yml 內去指定有 `windows` tag 的 runner 來執行 CI 的工作。

### Stage & Job & Pipeline

![GitLab CI Pipeline](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ti956u3m2nxwn7133fwx.png)

前面提過的 CI 三大工作－建置、測試、佈署，在 GitLab CI 的術語稱為 stage，這些 stage 之間有著邏輯上先後次序的關係，建置成功才跑測試，測試成功才做佈署，這樣的先後關係在 GitLab CI 稱之為 pipeline，而上圖就是一個 GitLab 專案內的 pipeline，它會依照專案的 .gitlab-ci.yml 的配置自動產生，並且相當直覺的讓我們能一望即知目前的 CI 狀態。

Stage 是做為 CI 階段的單位，並未定義實際要執行的指令，具體要執行的指令則是定義在稱為 job 的單位內，以上圖來說 build stage 內有個 build-job、test stage 內則有兩個 job，以此類推。

前面提的 runner 就是 job 的執行器，要注意的是每個 job 的 runner 都是獨立的，在沒有特別配置下，彼此間是沒有共用檔案等資源的，並且在一個 job 結束後它的 runner 也隨之消滅，最後留給我們的只有 runner 跑 job 的狀態、log 等資訊，這點在寫 .gitlab-ci.yml 時要特別留意。

### .gitlab-ci.yml

.gitlab-ci.yml 是 GitLab CI 用於定義前面提到過的幾個概念－stage、job 等，是整個 GitLab CI 的靈魂所在，如果曾經寫過 Dockerfile、docker-coompose.yml 或其他 provisioning 配置檔的朋友，看到 .gitlab-ci.yml 應該會冒出熟悉的<del>厭惡</del>感覺。

因為本人此刻剛好要建置一個 Windows 下的小玩具，所在這裡我們示範的也是以 Windows runner 為基礎的配置。

我們用的是 [GitLab Windows shared runner](https://about.gitlab.com/blog/2020/01/21/windows-shared-runner-beta/)，機器裏面已經幫我們[預裝好一些開發工具](https://gitlab.com/gitlab-org/ci-cd/shared-runners/images/gcp/windows-containers/-/blob/main/cookbooks/preinstalled-software/README.md)，常用到的 C++ 編譯工具、.NET Runtime 等都已預裝。

Windows runner 與常用的 Linux runner 有著些許的不同：

- Windows runner 的命令環境是 PowerShell。
- 在 GitLab Windows shared runner 內，預裝之一的工具有 [Chocolatey](https://chocolatey.org/)，它是 Windows 世界的套件管理工具，我們可以用 Chocolatey 幫我們在 CLI 環境下安裝必要的程式。
- Windows runner 並不是 Docker 容器，所以無法在 .gitlab-ci.yml 內指定 `image` 與 `services`。

參考以下範例做為我們 .gitlab-ci.yml 宇宙的起點：

```yml
stages:
  - build
  - test
  - deploy

default:
  tags:
    - windows
  before_script:
    - Set-Variable -Name "time" -Value (date -Format "%H:%m")
    - echo ${time}
    - echo "started by ${GITLAB_USER_NAME}"

build-job:
  stage: build
  script:
    - echo "running scripts in the build job"

test-job1:
  stage: test
  script:
    - echo "running scripts in the test job 1"

test-job2:
  stage: test
  script:
    - echo "running scripts in the test job 2"

deploy-job:
  stage: deploy
  script:
    - echo "running scripts in the deploy job"
```

先從前面已經提過的概念看起，最前面的是 `stages` 區塊，裡面定義了 `build`、`test`、`deploy` 三個 stage，他們的順序也決定了 CI 運作的順序，因此在 pipline 內看到的也會是 build > test > deploy 的順序。

第二大區塊 `default` 定義了後續那些 job 的預設值，首先 `tags` 用於指定 job 的 runner，以此範例來說，runner 必須有 `windows` 的 tag，才可執行 job。

接著我們關注那 `before_script` 區塊，顧名思義，`before_script` 內的命令會在每個 job 自己的命令之前先執行，一般 `before_script` 會用來安裝開發工具等等，例如在 GitLab Windows shared runner 裡面沒有預裝 Python，因此對一個 Python 專案而言，每個 job 都必然要先安裝 Python，像這樣的例子就會把安裝 Python 的命令寫在 `before_script` 區塊內，例如這樣：

```yaml
default:
  tags:
    - windows
  before_script:
    - choco install python --yes --version 3.9.6
    - $env:Path = "C:\Python39\;C:\Python39\Scripts\;" + $env:Path
    - python -m pip install --upgrade pip
```

`default` 內的項目，在 job 內可以把它取代掉，例如在 `build-job` 我想指定用特定版次的 Windows，那我可以在 `build-job` 內另行設定它的 `tags`：

```yaml
build-job:
  stage: build
  tags: windows-1809
  script:
  - echo "running scripts in the build job"
```

後面的四個 job，裡面的 `script` 區塊內則是定義該 job 要執行的命令，這就取決於各專案不同而自行發揮，這會是個充滿 try and error 的過程，祝您好運。

雖然目前這份 .gitlab-ci.yml 內容很陽春，但我們還是可以玩玩看感受一下，把 .gitlab-ci.yml 放到專案的資料夾內，再 commit 再 push 到 GitLab，開瀏覽器進 GitLab 的專案頁，在 CI/CD 的頁面應該就可以看到這些 job 執行的狀態，也可以點進去看 job 的 log，他們正辛勤的為我們工作著呢：

```
Running with gitlab-runner 14.0.0 (3b6f852e)
  on windows-shared-runners-manager 6QgxEPvR
Preparing the "custom" executor
Using Custom executor with driver autoscaler 0.1.0 (495ee7a)...
Creating virtual machine for the job...
```

以上，是 GitLab CI 的基礎使用方法。

## 結語

本文僅介紹了 GitLab CI 最陽春的使用與配置方法，陽春歸陽春，但也能滿足一般人的八成需求，比起看原廠那好幾個單元的文件要容易入門的多，如果對您有幫助，請幫我按讚、訂閱、開啟小鈴鐺。

最後，完整的 .gitlab-ci.yml 語法請參見〈[Keyword reference for the .gitlab-ci.yml file](https://docs.gitlab.com/ee/ci/yaml/)〉。