你照著 Day 4 裝好了平台,然後在公司環境重做一次——卡在第一步。
ImagePullBackOff。因為 quay.io 連不到。
這不是例外,這是金融業的常態。 而且影響的不只是安裝:
每個 workbench image、每個 ServingRuntime、
pipeline 裡每個 packages_to_install——全部都要有離線的來源。
skopeo(或 oc mirror)這是最多人卡住的地方——他們做了第一件,以為就完成了。
| 做什麼 | 沒做會怎樣 | |
|---|---|---|
| A 搬 image | 複製到內部 registry | image 不存在 |
| B 改路由 | 設 mirror 規則 | image 在,但叢集還是去 quay.io 找 |
| C 給權限 | pull secret + TLS 信任 | 找得到,但拉不動 |
三件事是獨立的,而且錯誤訊息不一樣——步驟五那張表會用到。
skopeo copy --all \
docker://quay.io/opendatahub/odh-workbench-jupyter-datascience-cpu-py312-ubi9@sha256:<digest> \
docker://registry.internal:8088/odh/odh-workbench-jupyter-datascience-cpu-py312-ubi9:3.5
⚠️ 來源用 digest,目的地用 tag。
因為 mirror 規則是按 digest 比對的(下一步會看到),
你搬的必須是規則會去找的那一顆,而 tag 隨時可能指向不同的 image。
驗證這一步:
skopeo inspect docker://registry.internal:8088/odh/<name>:3.5 | jq -r '.Digest'
digest 要跟來源一模一樣。
我 lab 上搬一個 workbench image 花了 17 分 26 秒、1,698 MB。
完整的平台有幾十個——這是排期時要算進去的。
OpenShift 4.x 用 ImageDigestMirrorSet:
apiVersion: config.openshift.io/v1
kind: ImageDigestMirrorSet
metadata:
name: odh-workbench-mirror
spec:
imageDigestMirrors:
- source: quay.io/opendatahub/odh-workbench-jupyter-datascience-cpu-py312-ubi9
mirrors:
- registry.internal:8088/odh/odh-workbench-jupyter-datascience-cpu-py312-ubi9
⚠️ IDMS 只對 digest 形式的參照生效。
YAML 裡寫 image: quay.io/xxx:3.5(tag 形式)不會被改寫——
這是名字裡 Digest 的意思。(tag 需求要用 ImageTagMirrorSet。)
套用後節點會逐台重啟 CRI-O:
oc get imagedigestmirrorset
oc get mcp # 等 UPDATED=True
oc create cm registry-certs -n openshift-config \
--from-file=registry.internal..8088=ca.crt
oc patch image.config.openshift.io/cluster --type=merge \
-p '{"spec":{"additionalTrustedCA":{"name":"registry-certs"}}}'
⚠️ 檔名格式很特別:主機名裡的冒號寫成兩個點(registry.internal..8088)。
lab 可以走捷徑(正式環境不要,它關掉的是 TLS 驗證,
中間人可以換掉你的 image):
oc patch image.config.openshift.io/cluster --type=merge \
-p '{"spec":{"registrySources":{"insecureRegistries":["registry.internal:8088"]}}}'
| 層 | 影響範圍 | 什麼時候用 |
|---|---|---|
叢集全域(openshift-config/pull-secret) |
所有 namespace | 平台自己要拉的 |
| ServiceAccount | 那個 SA 起的所有 pod | 最常用 |
Pod(imagePullSecrets) |
單一 pod | 特例 |
⚠️ 最常見的錯誤:建了 Secret,以為就生效了。
Secret 必須被 SA 連結、或被 pod 明確引用。
oc create secret docker-registry harbor-pull \
--docker-server=registry.internal:8088 \
--docker-username='robot$odh+puller' \
--docker-password='<token>' -n <ns>
oc secrets link default harbor-pull --for=pull -n <ns>
⚠️ Harbor 的 robot 帳號含 $ 和 +,shell 裡一定要單引號,
不然會被展開成空的——而錯誤訊息只會說認證失敗。
而且 OpenShift AI 的 pod 不都用 default SA:
oc get pods -n <ns> -o custom-columns='NAME:.metadata.name,SA:.spec.serviceAccountName'
每一個用到的 SA 都要連。
oc run pulltest --rm -it --restart=Never \
--image=registry.internal:8088/odh/some-image:3.5 -- echo ok
失敗的話,訊息會告訴你是三件事裡的哪一件:
| 訊息 | 是哪一件 | 回去看 |
|---|---|---|
manifest unknown |
A:image 不在那裡 | 步驟二 |
| 還是去 quay.io 拉 | B:mirror 沒生效(多半是用了 tag) | 步驟三 |
x509: certificate signed by unknown authority |
C:不信任 registry | 步驟四 TLS |
unauthorized: authentication required |
C:沒憑證或沒連上 SA | 步驟四 pull secret |
no route to host |
網路/防火牆 | 不是這篇的問題 |
這張表能省下很多亂試的時間——五個症狀對應五個完全不同的原因。
這是離線環境最容易漏的一節。
| 東西 | 離線會怎樣 | 怎麼辦 |
|---|---|---|
pipeline 的 packages_to_install |
❌ pip 連不到 PyPI | 自己 build base image |
workbench 裡 pip install |
❌ 同上 | 內部 PyPI mirror |
| HuggingFace 模型下載 | ❌ 連不到 | 先下載,放 S3 |
| operator 更新 | ❌ OperatorHub 連不到 | 離線 catalog |
最後一列常被忽略,然後半年後要修 CVE 時才發現升不了級。
評估離線可行性時,把「怎麼更新」一起問。
| 檢查 | 怎麼看 | |
|---|---|---|
| 1 | image 在、digest 一致 | skopeo inspect |
| 2 | IDMS 存在、節點更新完 | oc get idms、oc get mcp |
| 3 | Secret 連上了 SA | oc get sa <sa> -o jsonpath='{.imagePullSecrets}' |
| 4 | 真的拉得下來 | 步驟五那個 pod |
| 5 | 權限是最小的 | 用 pull 帳號試推,應該要 401 |
| 6 | ⭐ 斷網再試一次 | 見下 |
第 6 項是唯一真的驗證:
把叢集對外的連線切掉,然後刪掉一個 pod 讓它重拉。
起得來,才代表你真的離線可用。
沒做這件事,你不知道有多少東西是靠著「其實還連得到」在跑。
Q:oc mirror 跟 skopeo 選哪個?
A:oc mirror 能整批處理 operator catalog,適合初次建置;skopeo 精準,適合補漏和日常維護。兩個都會用到。
Q:要 mirror 多少個 image?
A:沒有人能事先列全。 先在能連外網的環境裝一次,然後:
oc get pods -A -o json | jq -r '.items[].spec.containers[].image' | sort -u
這份清單就是你的搬運清單。
Q:pull 和 push 可以用同一個帳號嗎?
A:不要。給推送權限的憑證如果被用在每個拉取的 pod 上,
任何能進那個 pod 的人都能覆蓋你的 image。
Q:robot 帳號會過期嗎?
A:Harbor 的 robot 可以設有效期,預設有。
症狀是「昨天還好好的,今天全部拉不到」——把到期日記進行事曆。
Q:這些設定能寫進 GitOps 嗎?
A:IDMS 和 image config 是 cluster-scoped 的 CR,可以,而且建議一定要——
這是重建叢集時最容易漏的一塊。Day 25 會談。
opendatahub-operator.v3.5.0(即 RHOAI 3.x 的上游開源版)、cert-manager-operator.v1.20.0(3.x 的必要相依,2.x 不需要)kserve、aipipelines、dashboard、workbenches、modelregistry
⚠️ ODH ≠ RHOAI:元件同源,但 namespace 與部分名稱不同
(這裡是 opendatahub,商用版是 redhat-ods-*)。指令邏輯可照用,字串要自己對一次。
你們的叢集連得到外網嗎?如果不能,image 現在怎麼進來的? 留言或到原文留言都可以,我會回。