GitLab Runner 建置:為你的 Pipeline 注入生命

「指令我都已經 push 上去了,怎麼一點反應也沒有?」

上次我滿懷雄心地寫好 .gitlab-ci.yml 檔案後 push 上去。「這下部署應該會自動完成了吧?」帶著這樣的期待,我點開了 GitLab 的「CI/CD > Pipelines」選單。

但畫面上出現的並不是綠色的成功標記,而是不停轉動的載入動畫,以及「Pending(待處理)」的狀態訊息。點進去一看,出現了這樣的警告。

This job is stuck because the project doesn't have any runners online assigned to it.

翻譯一下就是:「工作進來了,但是該處理這個工作的工人(Runner)沒有來上班。」糟了,我只丟了工作指令給工廠廠長(GitLab Server),卻沒有實際雇用要在工廠工作的員工(Runner)。

不管設計圖多麼完美,沒有「工人」來組裝的話,工廠根本不會運轉。

GitLab Runner:Pipeline 的手與腳

GitLab 大致可以分成兩個部分。

  1. GitLab Server(總公司/工廠廠長):儲存程式碼、管理 Pipeline 的狀態,並下達指令。
  2. GitLab Runner(分公司/現場人員):安裝在實際的伺服器上,接收總公司的指令後,負責拉取程式碼、進行 build,並執行部署指令。

「不能就讓 GitLab 自己連到我的伺服器幫我部署嗎?」仔細想想,這其實非常危險。如果網路上的網站(GitLab)只要有人按一下按鈕,就能跑進我房間裡的電腦(伺服器)裡隨意執行指令,那跟「駭客入侵」沒兩樣。萬一有人盜走我的 GitLab 帳號,他甚至可以把我的伺服器變成比特幣礦機。

所以 GitLab 不會直接連線到我的伺服器。它會在我的伺服器內部安插一個「身份明確的代理人(Runner)」,並且只透過這個代理人來下達工作指令。我們接下來要做的這套複雜的安裝與註冊流程,正是用來認證這位代理人的「資安程序」。

第 1 步:確認徵才公告(發行 Token)

在安裝 Runner 之前,我們得先去總公司(GitLab)發出「我們專案需要工人」的「徵才公告」並拿到一張「員工證(Token)」。

在最新版的 GitLab 中,為了強化資安,查看 Token 的方式被藏得有點深。

  1. 進入 GitLab 專案
  2. 左側選單:Settings > CI/CD
  3. 點擊 Runners 區塊的 Expand
  4. 點擊 Project runners 區塊右上角的三個點按鈕(⋮)

按下這顆按鈕後會跳出一個彈出選單,我們要找的資訊就在裡面。記得確認並複製 URL 與 Registration token。

(小提醒:你可能會看到一個有點嚇人的警告:「Support for registration tokens is deprecated」。意思是這個方式遲早會被淘汰,但目前為了相容性還是有支援,所以別緊張,照樣複製 Token 即可。)

[Tip] 多個專案的話該怎麼辦?(Group Runner) 如果你跟我一樣,把前端、後端等多個專案綁在同一個 group 下管理,每個專案都個別註冊一個 Runner 實在沒效率。這時候就不要在專案設定裡註冊,改到 群組設定(Group Settings)> CI/CD 選單去註冊 Runner。這樣建立的「Group Runner」可以一肩扛起該群組底下所有專案的工作。(我的專案很多,所以選了這種做法。)

必須打開隱藏選單(⋮)才能看到 Token。這個 Token 是連接 Runner 與伺服器的「秘密鑰匙」,絕對不能外流。

第 2 步:雇用工人(安裝 Runner)

現在來實際在 Linux 伺服器(或自己的電腦)上安裝 Runner 吧。最乾淨俐落的方式,當然就是使用我們最愛的「Docker」。

# 1. 啟動 GitLab Runner 容器
docker run -d --name gitlab-runner --restart always \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v gitlab-runner-config:/etc/gitlab-runner \
  gitlab/gitlab-runner:latest

  • -v /var/run/docker.sock:/var/run/docker.sock:這一行很重要。因為 Runner 還得再啟動另一個 Docker 容器(build 用),所以要把主機的 Docker socket 分享給它。(Docker in Docker 方式)

第 3 步:簽勞動契約(註冊 Runner)

裝好 Runner 還沒結束。這個 Runner 必須向 GitLab 伺服器告知「我是 A 專案的工人」,這道註冊(Register)程序少不了。

我們進到剛才啟動的 Runner 容器裡,執行註冊指令。

# 在 Runner 容器內執行註冊指令
docker exec -it gitlab-runner gitlab-runner register

接著終端機會像「20 個問題」遊戲那樣連續發問。把第 1 步看到的資訊填進去就好。

  1. Enter the GitLab instance URL:
    • https://gitlab.com/(或自架 GitLab 的網址)
  2. Enter the registration token:
    • (貼上剛才複製的 Token)
  3. Enter a description for the runner:
    • my-runner-01(隨便取,好認的名字就行)
  4. Enter tags for the runner:
    • (可以直接按 Enter 略過。只想讓它處理帶有特定標籤的工作時才會用到。)
  5. Enter an executor:
    • docker(我們要在 Docker 上進行 build,所以輸入 docker。)
  6. Enter the default Docker image:
    • docker:latest(預設要使用的 image)

「Runner registered successfully.」當這行訊息出現,雇用程序就完成了!這時重新整理 GitLab 畫面,你會看到亮著綠燈的 Runner 大喊:「準備好了(Online)!」

連線成功後,GitLab 畫面上的 Runner 狀態燈就會變成綠色。

第 4 步:Pipeline 啟動!

Runner 一註冊上去,原本卡在 Pending 的 Pipeline 就會自動開始跑。Running… 過沒多久,Passed!

我什麼都沒做,機器卻自己跑完測試、做完 build、產生 image,再把它推到儲存庫去。打開終端機看 log,發現整個流程比我手動操作還要更快、更精準。

「哇……真的會動耶?」

過去花 10 分鐘的手動部署,現在只要一行 git push 就搞定。我從此可以下指令部署,然後優雅地去喝杯咖啡。

實務小撇步:Docker 權限問題(Permission Denied)

第一次設定 Runner 時,有個 99% 機率會踩到的錯誤。dial unix /var/run/docker.sock: connect: permission denied

這是 Runner 想用 Docker 指令,卻沒有權限造成的問題。這時候要打開 gitlab-runner 的設定檔(config.toml),把 privileged = true 選項打開。

# /etc/gitlab-runner/config.toml(Runner 設定檔)
[[runners]]
  name = "my-runner-01"
  executor = "docker"

[runners.docker]

privileged = true # 這一行要改成 true,Docker-in-Docker 才能正常運作。# …

結語:終於可以下班了

我終於有了自己的「部署機器人」。從現在開始,我只要專心寫 code 就好。那些枯燥又重複的驗證和部署工作,就交給我那忠心耿耿的機器人(Runner)來處理。

不過還差一點點。目前的 Pipeline 只要有人 push 到 master 分支就會無條件執行。「我想讓開發伺服器(dev)自動部署,但正式伺服器(prod)只在我按下『核准按鈕』時才部署,那要怎麼辦?」

下次我們來看看怎麼讓 Pipeline 更聰明,聊聊「分支別部署策略」和「手動核准(Manual)流程」。

發佈留言