怎麼自動截 OpenShift console 和 Grafana 的圖
寫平台文件最花時間的不是文字,是截圖——而且它會過期。 版本升一次,所有截圖作廢。
所以我把它自動化了。19 張圖,一個指令重跑。這篇是做法和四個坑。
為什麼不能用 --screenshot
Chrome 有現成的:
google-chrome --headless --screenshot=out.png https://...
對 SPA 沒用。 OpenShift console、ODH dashboard、Grafana 都是單頁應用,
--screenshot 在 load 事件就截,那時候畫面上只有骨架。
要用 Chrome DevTools Protocol(CDP),才能做「導航 → 等 → 截」。
# 起 Chrome,開 remote debugging
subprocess.Popen(["google-chrome-stable", "--headless=new",
"--ignore-certificate-errors", "--no-sandbox",
"--remote-debugging-port=9333", "--remote-allow-origins=*", # ← 坑 1
"about:blank"])
# 開新分頁(新版 Chrome 的 /json/new 只吃 PUT,不吃 POST)
req = urllib.request.Request("http://127.0.0.1:9333/json/new?about:blank", method="PUT")
ws_url = json.load(urllib.request.urlopen(req))["webSocketDebuggerUrl"]
ws = websocket.create_connection(ws_url)
send("Emulation.setDeviceMetricsOverride", {...}) # ← 坑 2
for c in cookies: send("Network.setCookie", c) # ← 坑 3
send("Page.navigate", {"url": url})
time.sleep(WAIT)
send("Page.captureScreenshot", {"format": "png"})
坑 1:新版 Chrome 擋跨來源 WebSocket
第一次連就被拒:
Handshake status 403 Forbidden
Rejected an incoming WebSocket connection from the http://127.0.0.1:9333 origin.
Use the command line flag --remote-allow-origins=http://127.0.0.1:9333
加 --remote-allow-origins=* 就好。這是為了防止網頁去連你本機的 debug port,
自動化腳本得明確放行。
坑 2:懶載入的面板,captureBeyondViewport 沒有用
CDP 有一個看起來很對的參數:
send("Page.captureScreenshot", {"captureBeyondViewport": True})
我用它截 Grafana,得到的是上面幾格有東西、下面全是空白。
原因:Grafana(和 OCP console 的長表格)只渲染 viewport 內的面板。
captureBeyondViewport 把畫布延長,但捲不到的面板根本沒被畫出來,
延長的部分就是背景色。
正解是把 viewport 直接開到內容的高度:
send("Emulation.setDeviceMetricsOverride",
{"width": 1680, "height": 2600, "deviceScaleFactor": 1, "mobile": False})
我的 Grafana 截圖從 16 KB(空白)變成 158 KB(九個面板都在)。 檔案大小是最快的自我檢查——截到空白的圖,size 會小得很不合理。
坑 3:每個前端有自己的 OAuth,cookie 名字還不一樣
console 和 ODH dashboard 都要登入,而且不能共用 cookie:
| 前端 | OAuth client | session cookie 名字 |
|---|---|---|
| OCP console | console |
openshift-session-token-<pod後綴> ← 名字會變 |
| ODH dashboard | data-science |
_oauth2_proxy ← 是 oauth2,有個 2 |
console 那個特別討厭:cookie 名字帶著 console pod 的後綴
(例如 openshift-session-token-console-65d49ddcc7-xcfqp),
pod 重建就變了,不能寫死。
拿 cookie 的流程用 curl 走完就好:
# 1) GET 登入頁(會種 csrf cookie,並拿到 then / csrf 兩個 hidden 欄位)
curl -sk -c jar -b jar -L -o login.html "$START_URL"
# 2) POST 帳密,一路跟到 callback,session cookie 就種好了
curl -sk -c jar -b jar -L -o /dev/null \
--data-urlencode "then=$THEN" --data-urlencode "csrf=$CSRF" \
--data-urlencode "username=$U" --data-urlencode "password=$P" \
"https://oauth-openshift.apps-.../login"
$START_URL 換成 console 或 ODH 的網址,就分別拿到兩組 cookie。
Harbor 又是另一套:CSRF token 要問兩次——第一次 GET /api/v2.0/systeminfo
只種 _gorilla_csrf cookie,第二次才會在 response header 給你
X-Harbor-CSRF-Token,然後帶著它 POST /c/login。
坑 4:不要猜 SPA 的路徑
我要截 pipeline run 的詳情頁,照舊版的 URL 寫:
/pipelineRun/view/<runId> → We can't find that page
ODH 3.5 改了:
/develop-train/pipelines/runs/<namespace>/runs/<runId>
猜路徑是浪費時間。從列表頁把連結撈出來最快:
[...document.querySelectorAll('a[href]')].map(a => a.getAttribute('href'))
用 Runtime.evaluate 執行它,答案直接出來。
這個坑本身也是一條情報:網路上凡是給 ODH 舊版 URL 的教學,現在全部 404。
額外好處:截圖變成可重跑的資產
自動化之後有一個沒預期到的效果:截圖不再是「當初的樣子」, 而是「現在的樣子」。
版本升級後重跑一次腳本,所有圖同時更新。 更重要的是——如果某張圖跑不出來了,那本身就是一個發現。 我就是這樣抓到 Grafana 面板全壞的:圖截出來是空的, 一路追下去才發現 datasource uid 對不上。
手動截圖的話,我只會覺得「今天沒資料吧」,然後截一張別的。
你們的平台文件截圖是手動的嗎?版本更新後怎麼重截?
🧪 這篇的實驗環境與 lab 檔案(最後更新 2026-08-30)
叢集
- CRC 2.63.0 · OpenShift 4.22.7 · Kubernetes v1.35.6
- 單節點:13 vCPU / 40 GiB RAM / 120 GB disk
- 宿主:Framework Laptop 16(Ryzen AI 7 350 · 8C/16T · 64 GB RAM · 1 TB NVMe · RTX 5070 顯卡模組)
- ⚠️ 叢集內看不到 GPU(CRC 是 VM,RTX 5070 未 passthrough)
Operator
opendatahub-operator.v3.5.0← 即 RHOAI 3.x 的上游開源版cert-manager-operator.v1.20.0(3.x 的必要相依;2.x 不需要)openshift-pipelines-operator-rh.v1.23.2、openshift-gitops-operator.v1.21.3
DataScienceCluster 開啟的元件
kserve、aipipelines、dashboard、workbenches、modelregistry、kueue(Unmanaged)- 其餘(
ray/trustyai/feast/aigateway…)為Removed
叢集外的依賴(跑在宿主的 podman 上,crc start 不會帶起來)
- Harbor v2.15.2(私有 registry)· MinIO(S3)
模型端
- Python 3.12.13 · PyTorch 2.11.0+cu128 · FastAPI + uvicorn · prometheus-client
lab 檔案
- YAML/Containerfile/腳本:github.com/ryanGTR/openshift-ai-30days
(含 Day 對照表;主機名是佔位符,跑
set-lab-host.sh換成你自己的) - 服務的那個模型:llm-from-scratch(從零手刻的小 GPT)
⚠️ ODH ≠ RHOAI:元件同源,但 namespace 與部分名稱不同
(我這裡是 opendatahub,商用版是 redhat-ods-* 那一套)。
指令的邏輯可以照用,字串要自己對一次。
留言與指正
我特別想知道:你們的平台文件截圖是手動的嗎?版本更新後怎麼重截?