OpenBMC 自動化建置黑盒子內幕:拆解 CI 隱形工廠
系列:S2 OpenBMC Project|集數:第 13 集
主題:OpenBMC Build Scripts 與 Jenkins CI 全自動化流水線深度剖析
🎯 核心概念
OpenBMC build scripts 是一組以 Apache License 2.0 開源的腳本集合,與 Jenkins CI 系統緊密協作,實現從程式碼提交到韌體產出的全自動化流水線。
角色分工:
角色元件職責工廠總經理(排程大腦)Jenkins事件觸發、資源排程、任務調度精密肌肉與神經網路OpenBMC build scripts(Bash + Python)環境建置、編譯邏輯、測試執行、品質審查
關鍵洞見:
Jenkins 的強項在於「偵測事件 → 喚醒節點」,但它不懂 Yocto / BitBake 等嵌入式建置引擎的領域知識。腳本的存在,正是填補「排程能力」與「領域專業」之間的鴻溝。
🏗️ 第一階段:Docker 容器化 — 無塵室策略
環境一致性問題
CI 系統最痛的痛點:50 台伺服器節點的編譯器版本、環境變數、作業系統可能各不相同,同一份程式碼在不同節點可能編譯成功或直接報錯。
解決方案:絕對隔離的 Docker 容器
支援的基礎映像檔:
映像檔來源Ubuntu(預設)public.ecr.aws/ubuntu(AWS ECR)
Fedora官方映像
兩大工程細節
1. 絕對隔離性
編譯過程產生的暫存檔、設定變更,容器一關閉即灰飛煙滅,絕不污染宿主機。
2. UID / GID 同步機制
容器啟動 → 自動建立與宿主機一致的 UID / GID
→ 編譯產出物的檔案擁有者 = 開發者本人
→ 避免「權限不足」的存取障礙
新手常見大坑:若在容器內以 root 編譯,產出檔案的擁有者為 root,回到宿主機後一般使用者無法移動、刪除或讀取該檔案。
🪆 第二階段:俄羅斯娃娃架構 — 動態藍圖生成
當 Jenkins 觸發 ci-openbmc 任務時,執行流程如下:
Jenkins 觸發任務
└─ 呼叫 build-setup.sh(核心腳本)
├─ 讀取目標機型(TARGET,預設 qemuarm)
├─ 在隨機命名的 WORKSPACE 目錄中動態寫出 Dockerfile
├─ 建置並啟動 Docker 容器
└─ 在容器內部動態生成 build.sh
└─ 執行 BitBake 建置指令 → 完成韌體編譯
自動效能適配
腳本自動讀取系統變數 NUM_CPUS,探測當前機器的核心數量4 核心小虛擬機 → 溫和編譯128 核心怪物伺服器 → 多執行緒全力榨乾算力Jenkins 完全無需介入底層效能調配
🧪 第三階段:單元測試 — 依賴地獄的終結者
觸發機制
編譯完成後,Jenkins 觸發 ci-repository 任務 → 呼叫 run-unit-test-docker.sh → 啟動核心引擎 unit-test.py(高達 1460 行 Python)。
C++ 依賴地獄
風扇轉速套件 → 依賴資料庫套件 → 依賴網路通訊套件 → 依賴底層加密模組
(缺任何一環,單元測試連啟動都無法啟動)
unit-test.py 的解法
步驟機制
1. 解析依賴深入解析 configure.ac / meson.build 設定檔
2. 建構依賴樹使用自訂 DependencyTree 類別,建立完整依賴關係圖
3. 拓撲排序經典演算法,計算出從最底層(不依賴任何人)開始的正確編譯順序
4. 自動拉取原始碼連線 Gerrit 程式碼代管伺服器,依序拉取、編譯、安裝
5. 平行加速透過 Docker 多階段建置 + Python 多執行緒,平行處理笨重的預裝套件(Boost、Google Test、sdbusplus)
測試覆蓋率報告
get-under-test-report.py 透過 GitHub API 遍歷 OpenBMC 組織下所有倉庫,自動過濾歸檔專案,產出覆蓋率報告(標示 YES / NO / SKIP)。
🖥️ 第四階段:QEMU 整合測試 — 虛擬宇宙攻防戰
為何需要虛擬化
實體伺服器主機板昂貴且測試速度慢,解法:在 Docker 容器內虛擬出一塊主機板。
執行流程
Jenkins 觸發 run-ci-in-qemu 任務
└─ 呼叫 run-qemu-robot-test.sh
├─ qemu-build.sh:編譯客製化 QEMU(鎖定 arm-softmmu 架構)
│ └─ 禁用所有圖形功能(SDL / GTK / VNC),全力模擬 CPU 與記憶體
├─ 啟動 QEMU 虛擬機
│ └─ 非同步日誌輪詢:死盯日誌等待「OpenBMC Ready」信號
└─ 就緒後啟動第二個容器(測試武器庫)
├─ Robot Framework 7.2.2(自動化測試框架)
├─ Selenium(網頁界面操作)
└─ Redfish 工具套件(伺服器管理協定)
└─ 透過 SSH / HTTPS 連線 QEMU 內的 OpenBMC
→ 瘋狂點擊界面、呼叫 API、測試極端狀況
多機型支援
支援切換多種虛擬機型:Palmetto、Romulus、VersatilePB(預設)等,全部在 Docker 容器內完成,不依賴實體主機板。
⚡ 第五階段:快取預熱 — 打敗編譯物理學
ci-build-seed 批次任務
項目說明執行時機半夜系統空閒時段執行內容一口氣替 18 種 目標機型完整編譯一次(Romulus、P4BMC、Harma 等)核心目的Yocto SState(Shared State Cache)快取預熱
原理
[半夜] ci-build-seed 完整編譯 → 產生 SState 快取(所有底層元件)
[白天] 開發者推送程式碼 → 系統只編譯被修改的部分 + 快取組裝
→ 從數小時 → 數分鐘
設計哲學:以空間換取時間的極致展現。在無人時段備好所有原料,讓白天的建置速度狂飆。
🔄 第六階段:自我驗證 — CI 測試 CI
ci-openbmc-build-scripts 任務
CI 系統對自身進行測試,展現高度工程成熟度:
檢查所有 Bash / Python 腳本語法測試 Docker 影像檔 是否能順利建置用 sdbusplus 跑一次模擬流程確保整套 CI 邏輯齒輪沒有崩壞
👮 第七階段:品質警察 — format-code.sh
15 種 Linter 總控框架
語言 / 範圍工具功能C / C++clang-tidy深度靜態分析,揪出潛在記憶體洩漏Pythonblack強制統一程式碼排版風格Git 提交訊息commit-spell拼字檢查通用依副檔名自動派發最終以 git diff 確保格式完美
💡 設計哲學總結
開發者按下提交
↓
Jenkins(排程大腦)觸發任務
↓
build-setup.sh → Docker 無塵室 → 俄羅斯娃娃架構 → 韌體編譯
↓
unit-test.py → 依賴樹拓撲排序 → 自動拉取 + 平行編譯 → 單元測試
↓
QEMU 虛擬機 + Robot Framework → 整合測試
↓
ci-build-seed → SState 快取預熱 → 加速後續建置
↓
ci-openbmc-build-scripts → CI 自我驗證
↓
format-code.sh → 15 種 Linter 品質審查
↓
韌體產出 + 測試報告
機制 | 解決的痛點
Docker 容器化 + UID/GID 同步 | 環境不一致、檔案權限錯亂
俄羅斯娃娃動態藍圖 | 開發者與外部系統無感適配硬體環境
DependencyTree + 拓撲排序 | C++ 依賴地獄
QEMU + Robot Framework | 實體主機板昂貴且緩慢
SState 快取預熱 | 全量編譯耗時數小時
CI 自我驗證 | 自動化系統自身的可靠性
15 種 Linter | 多語言多面向的程式碼品質把關
🤔 結語思考題
這套系統使用了 15 種極度嚴格的 Linter 來維持絕對的程式碼秩序,但維護團隊故意沒有鎖定部分 Linter 工具的版本號。
官方理由:鎖定版本會導致工具過時,讓品質標準停滯不前。
矛盾:不鎖定版本 = 每次建置抓取最新檢查標準 → 違背了系統追求的「絕對一致性」。 程式碼昨天檢查通過,今天因為 Linter 升級而莫名報錯,開發者被迫重建所有容器。
「我們是否必須在完美的機器裡,刻意保留一絲不可預測的混亂,以維持系統的新陳代謝與進化?」
Reference
參考資料:OpenBMC build scripts 開源專案(Apache License 2.0)|Jenkins CI 持續整合系統
https://github.com/openbmc/openbmc-build-scripts
--
Hosting provided by SoundOn