我的驗收清單自己有三個 bug
我為一個平台導入案寫了一份 42 條的驗收清單:每一條都有「指令/畫面」、 「預期輸出」、「不接受什麼」。全部照官方文件寫的。
然後我在自己的 lab 上把它跑了一遍。
三條有問題。而且如果我沒跑,它們會直接被帶進驗收現場。
Bug 1:一個會吐出 80 行假警報的指令
原本這樣寫:
oc get csv -A | grep -i opendatahub
在我的 lab 上,它吐 82 行。
看起來像裝了 82 套 operator。第一反應是「環境壞了」。
實際上只裝了一套。
原因:operator 用 AllNamespaces 模式安裝時, 它的 CSV(ClusterServiceVersion)會被複製到每一個 namespace。 那 82 行是同一個 CSV 在 82 個 namespace 的副本。
修正:
oc get csv -A -o jsonpath='{range .items[*]}{.metadata.name}{"\n"}{end}' \
| sort -u | grep -i opendatahub
opendatahub-operator.v3.5.0 ← 就一套
⭐ 這條 bug 的危害不是「數字不對」,是它會製造恐慌。 在驗收現場,你拿一個吐 82 行的指令去問廠商, 對方會花半小時解釋一件根本沒發生的事——而你們兩邊都會覺得對方有問題。
教訓:任何會回傳「一堆」的指令,先確認它回的是不同的東西, 還是同一個東西的多份副本。
Bug 2:問錯了問題
原本 L5-2 寫的是:「比對鏡像的 digest 清單 vs 實際拉取的」。
看起來很嚴謹。但實際跑過才發現,那個問題問得太客氣了。
真正該問的是:
「現在正在跑的 pod,有幾顆 image 根本不在你的私有 registry?」
oc get pods -A --field-selector=status.phase=Running \
-o jsonpath='{range .items[*].status.containerStatuses[*]}{.imageID}{"\n"}{end}' \
| sed 's|@.*||' | sort -u | grep -vE '^<你的私有 registry>'
離線環境的正確答案是:空的。
任何一行輸出,都代表那顆 image 是從外網拉的—— 也就是這個環境現在還連得到外網,或者它根本沒有真正離線過。
差別在哪:原本的問法是「你的清單完整嗎」(比對兩份文件)。 新的問法是「這個環境現在有沒有依賴外網」(直接量事實)。
前者可以用一份漂亮的文件回答,後者不行。
我在 lab 上跑這條,結果是 operator 宣告 2 顆、實際 76 顆。
Bug 3:把兩件無關的事寫成同一條
原本的清單把 insecureRegistries 和 IDMS 混在一條裡,
好像設了其中一個就代表「私有 registry 接好了」。
它們完全無關:
| 機制 | 作用 | 沒有它會怎樣 |
|---|---|---|
insecureRegistries/憑證信任 |
叢集敢不敢連你的 registry | TLS 錯誤,連不上 |
| IDMS(ImageDigestMirrorSet) | 把 quay.io/x@sha256:… 改導向私有 registry |
照樣往外網拉 → 離線環境直接失敗 |
我的 lab 一開始只設了 insecureRegistries(讓 CRC 信任 HTTP 的 Harbor),
而 oc get imagedigestmirrorset 是 No resources found。
當時我以為「私有 registry 已經接好了」——因為推得上去、拉得下來。 那只證明「連得到」,不證明「叢集會去那裡拿」。
(現在補上了:odh-workbench-mirror。)
⚠️ 再補一個後來才知道的:IDMS 是用 digest 比對的。 如果你的 pod spec 寫的是 tag 不是 digest,IDMS 不會生效——要用 ITMS。 這又是一個「設了但沒作用」。
三條的共同點
| bug | 錯在哪 | 一句話 |
|---|---|---|
| 1 | 指令回的是副本不是實體 | 數量對不代表意義對 |
| 2 | 問了一個可以用文件回答的問題 | 要量事實,不要比對文件 |
| 3 | 把兩件事寫成一條 | 一條只驗一件事 |
而它們的共同來源只有一個:這份清單是照文件寫的,沒有跑過。
⭐ 所以:清單也是程式,也要測試
我後來把這件事訂成規矩:
任何驗收清單,在拿去用之前,要先在一個你控制得了的環境跑一遍。
理由跟寫程式一樣:
- 你寫的指令可能有 bug(bug 1)
- 你的預期輸出可能是錯的(bug 1 的「預期一行」其實是 82 行)
- 你問的問題可能問錯方向(bug 2)
- 你可能把兩個概念混在一起(bug 3)
而這些只有跑過才會發現。
沒跑過的清單會怎樣
拿一份沒跑過的清單去驗收,最好的情況是浪費時間解釋假警報。
最壞的情況是:對方照著你的清單交付,而你的清單漏掉了真正的問題—— 然後雙方都有一份「全部通過」的紀錄,而系統是壞的。
那份紀錄會在出事時保護不了任何人。
附帶:跑清單的成本比想像低
我在 CRC 上跑完 42 條,花了大約兩天——而且順便發現了平台本身的四個坑。
那兩天的產出不只是「清單修好了」,還有:
- 每一條的實際輸出可以貼進清單當「預期」的範例
- 對方看到範例輸出,就知道你真的跑過——談判位置完全不同
- 你自己在現場看到異常輸出時,認得出來
最後那點最值錢。 驗收現場對方跑一個指令給你看, 你要能在三秒內判斷「這個輸出正不正常」—— 而那個能力只能靠自己先跑過一遍。
你們的驗收清單有沒有實際跑過一遍?還是寫完就直接拿去用?
🧪 這篇的實驗環境與 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-* 那一套)。
指令的邏輯可以照用,字串要自己對一次。
留言與指正
我特別想知道:你們的驗收清單有沒有實際跑過一遍?還是寫完就直接拿去用?