公司導入 GitLab Self-Managed:架構與 CI/CD 流程設計分享
公司導入 GitLab Self-Managed:架構與 CI/CD 流程設計分享
公司原本用 SVN,隨著團隊擴張到 10 個團隊、開發語言從單一 Java 擴散到 .NET / Python,加上未來要拿 ISO 27001,SVN 已經明顯撐不住。於是這次規劃把版本控制平台搬到 GitLab Self-Managed CE,順便把 CI/CD 一起做起來。
這篇分享我們在規劃階段定下來的兩件事:整體系統架構 與 CI/CD 流程設計。不寫 gitlab.rb 設定值,只談架構決策與背後的取捨,給其他在規劃內部 GitLab 的朋友參考。
一、整體系統架構
先上圖。一張圖可以看完:5 台主機 + 1 個 NAS,對外只一條 HTTPS 通道,LDAP / SMTP 沿用既有資源。
部署模式:Self-Managed + Omnibus 單機
我們選了 Self-Managed,自有機房、單機部署,不做 HA。理由很簡單:
- 資料留在公司內部 — 程式碼是公司核心資產,不放雲端是組織共識
- 100 人規模單機足夠 — GitLab Omnibus 在 8 vCPU / 32GB / SSD 的機器上跑 100 人沒壓力
- HA 不是現在的痛點 — 業務還能容忍計畫內維護,真要做 HA 至少要 3 台 + Gitaly Cluster,複雜度是 5 倍以上的跳躍
當然這是取捨 — 主機掛了就全公司停擺。但靠每日完整備份 + 異機保存(寫到 NAS 的 NFS),最壞情況下還原時間可接受。將來業務關鍵性提升,再升級到 HA。
為什麼選 CE 不選 Premium
預算其實不是限制,但盤點商業版差異後發現核心需求 CE 都能滿足:
| 商業版獨有 | 我們怎麼補 |
|---|---|
| LDAP Group Sync | 群組與角色手動維護(訂季度核對 SOP) |
| Required Approvers | 訂 MR 簽核 SOP,以人工流程實施 |
| Audit Events 完整版 | 從 application log + OS log 反查 |
| SAST / DAST | 整合 SonarQube、Trivy 等開源工具 |
這些落差走流程跟外部工具補,不形成技術 lock-in,將來規模或合規要求提高再升級也來得及。
外部依賴(沿用既有,不另建)
- AD / LDAP — 認證來源,GitLab 用一個專屬服務帳號
svc-gitlab-ldap做 read-only bind - SMTP — 寄通知信,同樣用專屬服務帳號
- NAS(NFS) — 備份目標,用 NFS export rules + UID 對映授權,不用額外密碼
小心一個紅線: GitLab 的加密金鑰(
gitlab-secrets.json)跟 DB 備份必須分開存放。同時失守 = 加密形同虛設。我們在備份 SOP 把這個列為硬規。
二、CI/CD 流程設計(以及 Runner Pool 是「共用資源池」的觀念)
接下來這張圖比較精彩。我們在規劃 CI/CD 時遇到一個觀念上的轉換 — Runner Pool 不該被看成 Build 的附屬,而是整條 Pipeline 共用的執行資源池。
Pipeline Stages 的順序:Lint → Build → Test
我們把每個專案的 Pipeline 切成三個 stage:
- Stage 1 — Code Quality / Lint:語法、規範、靜態掃描。最快、最便宜,有錯就直接擋下,不浪費後面資源
- Stage 2 — Build:Java、Python 在 Linux Docker Runner 跑;.NET Framework / IIS 在 Windows Shell Runner 跑
- Stage 3 — Automated Testing:Unit Test、Integration Test。Test 通過才產 artifact,失敗就不污染 Registry
Runner Pool 的設計觀念
Pipeline 上跑的 4 個動作 — Lint / Build / Test / Deploy — 每一個 job 都需要 Runner 才能執行。Runner 不是 Build 專屬的東西,而是整條 Pipeline 共用的「執行容器」。
把這個觀念內化後,圖上的 Runner Pool 就被我們從 Build 旁邊獨立出來,畫成右側的「共用資源池」,讓所有 stage 都用虛線指向它,標示「派 job 借用」。
這個觀念上的修正帶來幾個重要副作用:
| 之前的誤解 | 修正後 |
|---|---|
| Runner 只給 Build 用 → 規劃時容易低估負載 | Lint/Test/Build/Deploy 都在搶 → 規劃 Runner 數量要看所有 stage 併發 |
| Test 卡住跟 Build 卡住是兩件事 | 都是 Runner 卡住 → 監控 Runner 利用率才看得出真因 |
| 加 Runner 只能加速 Build | 加 Runner = 加速整條 pipeline,所有 stage 同步受益 |
Linux Runner × 3 + Windows Runner × 1 的搭配
我們的環境同時有 Java / Python(Linux 友善)跟 .NET Framework / IIS(只能 Windows),所以 Runner Pool 分平台:
- Linux Docker Runner × 3 — 跑 Java、Python、容器化 build。3 台讓多團隊併發不互卡
- Windows Shell Runner × 1 — 跑 .NET Framework、IIS build。先 1 台觀察使用後再擴
兩平台工具鏈無法混用,所以是分開設備,不是「一台 Runner 兩種 OS」。
Deploy 為什麼要 manual + 三條路徑共存
正式環境部署用 when: manual,流程到 Deploy 就停下,等授權人員按按鈕。這是合規與資安要求 — 自動 deploy 到 prod 在內部稽核會被打。結合 Protected Environment 機制,只有特定 role 可以觸發。
部署到正式環境的路徑視目標主機而定,我們有三條共存:
- A. OpenSSH — Linux 目標(如 Tomcat on Linux),Linux Runner 直接 SSH 推送
- B. WinRM — Windows 目標,Linux Runner 跨平台用 MSDeploy / PowerShell Remoting
- C. Windows Runner 直部署 — 同網段 Windows 目標,最直接但要 Runner 跟目標都通
每個專案在落地階段視目標環境選一條,不強制統一。這是正視「組織內就是 Linux + Windows 混合環境」的務實作法。
三、幾個值得分享的取捨
最後快速列幾個我覺得其他公司也會遇到的決策點:
- SVN 歷史不搬,全新起步 — 評估後發現轉換工具與歷史保真度的成本,遠大於從新起步的痛。換到 GitLab 後 SVN repo 凍結唯讀供查詢即可
- 對外只開 HTTPS(443),不開 SSH(22) — 簡化 firewall、減少對外暴露、省掉全公司 SSH key 管理。代價是自動化腳本要改用 Personal Access Token
- 不導入外部 Vault,先用 GitLab 內建加密 — AES-256-GCM 已經符合多數合規要求,Vault 留給未來真有 dynamic secret 需求再評估
- Container Registry 跟 Package Registry 都啟用 — 用統一平台管所有 build 產出,組件可追溯性對 ISO 27001 的「組件版本管理」很重要
- 試點 1~2 個團隊先跑 — 不要一次全公司搬,先讓一兩個團隊跑通再推廣
結語
GitLab Self-Managed 的導入,架構選擇通常比實作細節更重要。我們在規劃階段把「Runner Pool 是共用資源池」這個觀念釐清,直接影響後續 Runner 數量規劃、監控指標設計、容量預測;把「Deploy 三條路徑共存」訂為原則,讓各團隊不必為了統一而扭曲既有環境。