今天我們要用昨天開的 EC2 instance 來架設 Gitlab Runner,然後跑第一個 pipeline say hello!跟著實作比較有 fu~可以到 https://gitlab.com 申請一個免費帳號、開 project 來練習跟放這 30 天用到的程式碼。(本日程式碼)
Gitlab CI/CD 是做 CI/CD 的工具,最上層的 component 是 pipeline——把軟體整個 build、test 到 deploy 過程看成有一個個階段的流水線就是 pipeline。
pipeline 主要由 stage 跟 job 組成。job 是「要做的事」,通常是一堆指令。stage 則是「什麼時候(階段)做」,像 build job 必須在 deploy job 前做,build job 就必須在 deploy job 的 stage 前。
這張圖是 Gitlab 內一個 pipeline 可能會長的樣子 (source)
Gitlab Runner 是執行 pipeline job 的程式,它會跟 Gitlab 溝通、取得需要執行的 job 來執行,一個 job 是否會給某個 runner 執行是依據 runner 以及 job 的 tag。
Executor 是 Runner 執行 job 的工作環境——Runner 收到 job 後會到什麼環境執行 job?直接在 Runner 本身用 shell?用 ssh 連到某台機器上?還是使用 docker 建立一個 container 後在裡面執行 job?
Executor 有以下幾種:
shell:直接在 runner 本機執行 job。
ssh:runner 會用 ssh 連上某台機器,在那台機器上跑 job。
virtualbox:用 virtualbox 開一台乾淨的 VM(所以 runner 上要有安裝 virtualbox),在該 VM 裡執行 job。
parallels:用 parallels 開一台乾淨的 VM,在該 VM 上執行 job。
docker:在 runner 上開一個乾淨的 container,在 container 中執行 job。
docker+machine:延續 docker executor,但它會做 auto scaling,當有大量 job 出現的時候可以用更多的 runner 去把 job 做完。
kubernetes:延續 docker+machine,它用 k8s 做 auto scaling。
custom:自己設定的 executor。
我們這 30 天會用 docker~
接下來實際操作吧!
先啟動昨天建立的 EC2 instance、用 ssh 連進去(public IP 可能會變!),我們要在這台 EC2 instance 上安裝 Gitlab Runner。依照 Gitlab 官方的 Install GitLab Runner using the official GitLab repositories 文件 在 EC2 instance 上安裝 Gitlab runner,指令總結如下:
$ curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash
$ sudo apt-get install gitlab-runner
接下來依照 文件 register runner 到 gitlab project,總結一行指令如下:
$ sudo gitlab-runner register \
--non-interactive \
--url "https://gitlab.com/" \
--token "$RUNNER_TOKEN" \
--executor "docker" \
--docker-image alpine:latest \
--description "docker-runner" \
--docker-volumes /var/run/docker.sock:/var/run/docker.sock
其中 $RUNNER_TOKEN
要在 Gitlab project 的 Settings ⇒ CI/CD ⇒ Runner ⇒ Project runners ⇒ New project runner 建立新的 project runner 後取得。建立 project runner 時 Run untagged jobs
先打勾,表示這台 runner 可以接受沒有上 tag 的 job。
這個 register 指令是向 https://gitlab.com/
這個 Gitlab Server 註冊 runner,並以 token 來知道是對哪個 project 註冊。指定 executor 為 docker,也就是對於每個要執行的 job,runner 都會建立一個 container 來執行其中的指令,預設用 alpine:latest
這個 image 來建立執行 job 指令的 container。--docker-volumes
則跟在 container 內使用 docker
指令有關,之後再說明~
如果成功 register,會在 Gitlab 看到:
EC2 Instance 要裝 docker,runner 才能用 docker 啟動 container 來執行 job,參考 Docker 官方文件 安裝指令如下:
$ sudo apt-get update
$ sudo apt-get install ca-certificates curl gnupg
$ sudo install -m 0755 -d /etc/apt/keyrings
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
$ sudo chmod a+r /etc/apt/keyrings/docker.gpg
$ echo \
"deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
有 runner 之後我們就來跑個 pipeline 打聲招呼吧~~~(對,又是 hello world)~~
Gitlab Pipeline 是用 project 根目錄下的 .gitlab-ci.yml
定義的,我們會定義 stage、job 的指令等等,來一個最簡單的 pipeline:
stages:
- deploy
deploy:
stage: deploy
script:
- echo "Hello World!"
這個 pipeline 有個 stage 叫做 deploy
(第 1~2 行)。還有一個 job 叫做 deploy
(第 4 行),它屬於 deploy
stage(第 5 行),並且執行 echo "Hello World!"
這行指令。
把 .gitlab-ci.yml
加入 repository、推上 gitlab 後,可以在 project 的 Build ⇒ Pipelines 頁面看到執行的 pipeline:
點進 pipeline 有 job 們及其狀態:
點進 job 可以看到各 job 的執行輸出跟結果,我們打招呼的 job 成功執行~耶!
現在我們的 job 會在每次 push code 到 Gitlab 時執行,如果希望 job 只在排定的時間執行,例如 build 相關的 job 只要每天跑一次,可以用 Pipeline schedules 功能來排程。
首先在 job 加上 rules
keyword,並且用 $CI_PIPELINE_SOURCE
這個 Gitlab 預先定義好的變數來判斷是否要執行這個 job:
job:
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
接著到左邊選單 Build 底下的 Pipeline schedules,建立一個新的 pipeline schedule:
用 cron syntax 指定要什麼時候執行 job 並且設定 cron 的時區。選擇要跑的 branch 或 tag,由 schedule 啟動的 pipeline 就會用那個 branch 最新的 code 或者 tag 的 code 來執行。
建好後可以看到 pipeline schedule 清單,除了排定的時間會執行外,也可以手動戳右邊的 play 按鈕來啟動 pipeline(方便測試也可以當作類似手動 trigger 的功能):
最後另外介紹兩個常用的 job keyword:tags
跟 artifacts
。
tag 用來讓 job 選擇使用的 runner。
register runner 的時候可以指定 tag 給 runner,job 用 tags
這個 keyword 指定 tag 們。runner 必須要有 job 擁有的所有 tag 才能跑這個 job,例如有個 job 有 php8.2
跟 dev
兩個 tag,runner 必須同時擁有這兩個 tag 才能執行這個 job。
artifacts 是 job 身上的檔案,通常是這個 job 的產出物,像是 build 出來的 binary 檔案、測試的結果報告等等,用 paths
指定哪些檔案要變成 artifacts:
job:
artifacts:
paths:
- builds/
- tests/output.html
有 artifacts 的 job 可以從 job 頁面右側按鈕瀏覽及下載 artifact,也可以讓後面 stage 的 job 使用前面 job 產生的 artifact。另外,如果 artifacts 不需要留太久,想在一段時間後就刪掉的話,可以用 expire_in
指定它 expire 並且被刪除的時間:
job:
artifacts:
expire_in: 3 days
expire_in
詳細可以使用的值可以參考文件。