iT邦幫忙

2026 iThome 鐵人賽

DAY 2
0
Kubernetes

防範軟體供應鏈攻擊:從零打造具備硬性阻擋能力的雲原生 CI/CD 流水線系列 第 2

Day 2:在 Windows 11 建立單機類生產環境:CRC (OpenShift Local) 安裝與資源配置心法

  • 分享至 

  • xImage
  •  

今日目的:先算清楚終局的資源需求,再決定 disk-size——因為這是唯一一項事後改不掉的設定。本篇會用這台機器的實測數字,示範沒算清楚的代價。

先備知識:本篇銜接 Day 1〈主題宣告〉,讀過該篇即可上手。

一個不可逆的決定

CRC(Red Hat OpenShift Local,前身 CodeReady Containers)的安裝流程官網已寫得很清楚:下載、crc setupcrc start,這篇不重複。這篇要講的是安裝之前必須想清楚的一件事:disk-size 一旦設定,事後要改就得 crc delete --force 把整台 VM 砍掉重建,先前部署的 namespace、服務與 Tekton 執行紀錄全部歸零。記憶體和 CPU 隨時能用 crc stopcrc start 調整生效,磁碟不行。

這代表這一天的決定會跟著接下來 29 天。而磁碟這項,當初的決定沒做好——本機配置為 60GB,下面會攤開完整的推導過程,包括這個數字實際上是怎麼來的,以及它後來讓這台機器付出了什麼代價。事實上,為了替這篇文章撈即時數據,這台機器在撰寫過程中就當場示範了一次:磁碟用量觸頂、節點被標上 DiskPressure taint、一次正在進行的滾動更新被卡住將近五分鐘。這段完整過程留在後面「磁碟:我配少了」一節,用真實輸出走一遍。

環境需求與下載

  • 作業系統:Windows 11 Pro
  • Hypervisor:Hyper-V(crc setup 會自動檢查並啟用)
  • 下載頁面:Red Hat Hybrid Cloud Console → OpenShift Local

在執行 crc setup 之後,務必在啟動叢集前完成本篇的資源參數規劃。

宿主機規格(供讀者自行評估是否有餘裕比照配置):

項目 規格
CPU Intel Core i9-13900H(14 核/20 邏輯處理器)
記憶體 63.7GB
系統磁碟(C 槽) 總容量 952.8GB,可用 590.5GB
作業系統 Windows 11 Pro

這台機器最後要扛什麼

在決定資源配置之前,要先掌握整個叢集未來會承載的元件全貌——完整的五階段建置順序已於 Day 1 說明。這裡直接給答案:常駐服務會持續累加(Gitea、Nexus 先上,Tekton 隨後長駐,ArgoCD/Kyverno 最終也是常駐元件),資源配置要以累加後的終局為準,不能只看初期單一元件的需求。

https://ithelp.ithome.com.tw/upload/images/20260801/20183337FPUHdaYZVG.jpg

下面這張表是「累加到終局之後,各元件實際吃多少」的閒置量測結果。量測方式先說明:這台機器上 oc adm top podoc adm top node 一律回傳 error: Metrics API not available——查證後發現 CRC 預設不隨附 openshift-monitoring 底下的 metrics-server(namespace 存在但零 Pod),也就是 Metrics API 從一開始就沒有被啟用,不是叢集異常。改用 oc debug node/crc -- chroot /host crictl stats -a 搭配 crictl ps -a(用 CONTAINER ID 把兩者的輸出接起來,取得每個容器所屬的 namespace)拿到等效數字。

元件 記憶體(閒置) CPU(閒置,約當 vCPU) 磁碟 何時進場
OpenShift 本體(其餘所有系統 namespace 合計) 11.45 GB ≈0.52 vCPU 主要是容器映像,見下節 Day 2(本篇)
Gitea 606 MB ≈0.15 vCPU* PVC 宣告 64Gi(3×PostgreSQL 10Gi+共用儲存 10Gi+3×Valkey 8Gi) Day 8
Nexus(含 proxy cache) 1,421 MB <0.01 vCPU PVC 宣告 20Gi,實測 blob store 僅 1.7GB Day 10
Tekton controller(openshift-pipelines) 352 MB ≈0.02 vCPU 無獨立 PVC Day 13
ArgoCD(openshift-gitops) 1,196 MB ≈0.02 vCPU 無獨立 PVC Day 28
Kyverno(4 controllers) 304 MB ≈0.05 vCPU 無獨立 PVC Day 29
PipelineRun 尖峰額外佔用 未實測 未實測 未實測 Day 18 起
閒置合計(不含 PipelineRun 尖峰) ≈15.3 GB ≈0.76 vCPU 45.3GB/63.82GB(71%,GC 之後的觀測值,見下節)

* Gitea 的 CPU 數字量測當下叢集才剛啟動十餘分鐘,三節點 PostgreSQL HA 仍在做啟動後同步,數字略高於長時間穩定運行後的真實閒置值;記憶體數字不受此影響,可視為穩定值。

「PipelineRun 尖峰額外佔用」這一行誠實留白:量測當下 ci namespace 裡沒有正在執行的 PipelineRun,閒置記憶體實測為 0;真正的尖峰數字要在觸發一次完整 PipelineRun 的同時另開視窗每 10 秒抓一次上述 crictl 替代法才量得到,這篇先不做,留到 Day 18 起實際跑過 Pipeline 後再回頭補。

合計:閒置狀態下容器層級的記憶體加總約 15.3GB,這台機器配了 24GB,餘裕約 8.7GB 留給 PipelineRun 尖峰與系統緩衝——這句話講完,後面「12/24/60」這組數字才是從實際負載推導出來的,不是憑空宣稱。(crc status 顯示的 RAM Usage 會比這個容器加總數字略高一些,落差來自 VM 本身的系統開銷,屬預期範圍。)

這張表最該注意的不是任何單一元件,是第一行:什麼都還沒裝,OpenShift 本體就吃掉 11.45GB,佔閒置總量的四分之三。 所有之後要裝的東西——Gitea、Nexus、Tekton、ArgoCD、Kyverno 全部加總——不到 4GB(實際 3.88GB)。在單機上評估 CRC 時,這是最容易低估的一項:以為在為自己的服務配資源,實際上絕大部分是在為平台本身付費。

資源配置心法:先看終局,再回推設定

這台機器目前實際跑的配置(crc config view 實測輸出):

- cpus         : 12
- memory       : 24576   # 24GB
- disk-size    : 60      # 60GB
- pull-secret-file : C:\Users\<user>\pull-secret.json

這組數字不是預設值(預設為 4 vCPU / 10752MB / 31GB)。節點實際回報的可分配資源:

資源 Capacity Allocatable 備註
CPU 12 11800m kubelet 保留 200m
記憶體 ~24.03GB ~23.55GB kubelet 保留約 480MB
磁碟(ephemeral-storage) 63.82GB ~57.07GB kubelet 保留約 6.75GB 作為系統與驅逐緩衝

調整記憶體與 CPU 設定:

crc config set memory 24576
crc config set cpus 12

記憶體與 CPU 可透過 crc stop / crc start 重啟生效,但虛擬磁碟空間的變動需要特別處理,見下一節。

磁碟:我配少了

60GB 是哪來的

原本以為 60GB 是宿主機容量限制下的折衷——回頭查了主機的實際狀況才發現這站不住腳:C 槽總容量 952.8GB,可用 590.5GB,當初根本沒有任何容量壓力逼著只能給 60GB。

那 60 是哪來的?誠實的答案是:它就是預設值 31GB 的兩倍左右,一個看起來夠用的整數,沒有經過任何一項元件的實際需求推導就敲定了。這個數字跟了這台機器 30 天,而且改不掉——因為 disk-size 事後調整必須 crc delete --force 整台重建(見下方指令),先前部署的 namespace、服務與 Tekton 執行紀錄會全部歸零。

這正好跟後面「CPU/記憶體:我配多了」那節形成對照:CPU 記憶體配錯是可逆的,隨時能調回來,代價只是浪費;磁碟配錯是不可逆的,代價會在最不希望發生的時候討債。同一台機器、同一批決定,一個沒經過推導卻無害,另一個同樣沒經過推導卻要命——差別只在能不能改。

現場示範:DiskPressure 是怎麼發生的

寫這篇文章、回頭替資源表撈即時數據的過程中,這台機器當場示範了一次磁碟配置過緊會發生什麼事,以下是撈資料當下的即時輸出,不是回憶重建的故事。

流程是這樣的:為了取得 oc adm top 失效後的替代數據,連續開了幾個 oc debug node/crc 除錯 Pod 跑 journalctlcrictl statscrictl psdu。這幾個除錯 Pod 本身會拉映像、佔用暫存空間,疊加在原本就已經逼近門檻的磁碟上——事發前的真實用量必然已經超過 54.25GB(85%),因為 imagefs.available<15% 這道硬門檻不到這個水位不會觸發;後文提到的 45.41GB/63.82GB(71%)其實是事件發生「之後」才量到的,不是事發當下的數字。kubelet 的 eviction manager 在 10:19:58 記下「attempting to reclaim resourceName="ephemeral-storage"」,接著在一秒內清掉 30 個沒有 Pod 在用的舊 Operator catalog/release 映像,精確合計 17.8GB,隨即回報「able to reduce resource pressure without evicting pods」——理論上不用犧牲任何 Pod。

DiskPressure 這個節點條件本身,還是在幾秒後的 10:20:03 被記錄下來,節點隨即被打上:

Taints:  node.kubernetes.io/disk-pressure:NoSchedule

oc get events -A 記下兩個除錯 Pod(crc-debug-rvzw6crc-debug-9496h)被判定 Evicted,理由是 The node had condition: [DiskPressure]——映像 GC 保住了正常的工作負載,付出代價的是這幾個除錯 Pod 自己。更值得記錄的是同一時間 ci namespace 裡正在滾動更新的 Tekton EventListener:新版本的 Pod(el-frontend-nx-mono-ci-77689f446-zpm5z)在 10:20:46 就已經被建立,卻一直卡在無法拉取映像的狀態,直到 10:25:09 taint 解除的瞬間才開始 Pulling image——整整卡了 4 分 23 秒;舊版本的 Pod 也因為新 Pod 遲遲無法就緒,跟著多活了將近 5 分鐘才被關閉。這就是磁碟配置過緊最直接的後果:不是變慢,是連正在滾動更新的 CI 元件都會被晾在半空中。

taint 在 10:25:09 自行清除(DiskPressure 條件轉為 Falsereason: KubeletHasNoDiskPressure),前後歷時約 5 分鐘——這不是巧合,這台節點的 eviction-pressure-transition-period 設定就是 5m0s:條件一旦成立,至少要維持滿 5 分鐘的冷卻期才會解除,用意是避免用量在門檻邊緣來回抖動時 taint 跟著頻繁地打上又拿掉。這次事件沒有造成資料損失,但清楚示範了一件事:60GB 的餘裕薄到連一輪除錯/量測作業都能把它推過門檻,而且一旦跨過,接下來 5 分鐘裡任何新排程或滾動更新的工作負載都會被卡住。

叢集沒有另外用 KubeletConfig CR 調整驅逐門檻(oc get kubeletconfig -A 回傳 No resources found),套用的是 OpenShift 內建的 hard eviction 預設值:imagefs.available<15%nodefs.available<10%(外加對應的 inodes 門檻),而不是 /etc/kubernetes/kubelet.conf 這個檔案本身能查到的——那份設定來自 MachineConfig 產生的 KubeletConfiguration,不是命令列 flag,這是排查時容易走錯的一步。這台機器的 nodefsimagefs 也確認是同一顆:df -h 顯示 /sysroot/var/lib/containers/var/lib/kubelet 全部落在同一個 /dev/sda4 分割區上,門檻沒有拆成兩本帳,60GB 就是唯一的預算。

這件事的教訓比「60GB 不夠」更值得記下來:磁碟壓力是一個你事後去看就看不到的事件。查完之後 crc status 顯示磁碟用量已經退回 45.44GB/63.82GB(71%),taint 也已經拿掉,看起來一切正常;真正的證據只留在 kubelet 日誌與 oc get events 裡,而 OpenShift 事件的預設保留期通常只有一小時左右,晚一步查就什麼都看不到了。如果這五分鐘裡剛好有 Webhook 進來要觸發 CI,流水線不會失敗、不會告警,它只是卡住排程——事後查看,叢集完全健康。這個模式在後面幾天還會反覆出現:系統事後回報的狀態,跟事發當下的狀態是兩回事。這也代表單看「目前 71%」這個讀數,本身不足以判斷磁碟餘裕還剩多少——真正該盯的是這道 GC 有沒有被反覆觸發。

更準確地說,這台機器很可能長期跑在 85% 門檻邊緣:每次用量逼近門檻,kubelet 就自動清掉一批不在用的映像,把水位壓回 70% 上下,crc status 也就跟著顯示一切正常。不只是「事件過後看不到」,連平常看到的水位讀數本身,都已經是被自動回收機制修飾過的結果,不是原始用量。

這個推測後來多了一筆數據可以對照:為了撰寫 Day 3 又做了一輪完整的 crc stopcrc start——VM 重啟後 OLM 會重新拉取 Catalog Image,理論上正是水位容易被推高的時間點。重啟完成後量到的讀數是 45.75GB/63.82GB(72%),跟這次事件後的基準幾乎持平,這一輪沒有再次觸發 DiskPressure。單一次沒觸發不代表門檻邊緣的推測錯了,反而剛好對上「回收機制把水位穩定壓回 70% 上下」這個說法本身——讀數持平,看不出來的正是它離門檻還有多近。

(順帶一提:crc config 裡設定的 disk-size 60 是宣告值,節點實際回報的 ephemeral-storage 容量是 62,323,692Ki,換算成十進位 GB 正好是 crc status 顯示的 63.82GB——這是正常的單位換算與虛擬磁碟格式開銷,不是設定被打折。)

磁碟實際被誰吃掉

oc get pvc -A 列出的宣告容量加總起來高達 107Gi,遠超過 60GB 物理磁碟:

gitea       data-gitea-postgresql-ha-postgresql-0/1/2   10Gi × 3
gitea       gitea-shared-storage                        10Gi
gitea       valkey-data-gitea-valkey-cluster-0/1/2      8Gi × 3
nexus       data-nexus-nexus3-0                         20Gi
openshift-image-registry  crc-image-registry-storage    20Gi
openshift-pipelines       postgredb-tekton-results-postgres-0  1Gi
ci          pipeline-source-pvc                         2Gi

這組數字之所以能在 60GB 磁碟上跑起來,是因為 CRC 內建的儲存驅動(kubevirt.io.hostpath-provisioner,thin-provisioned)不會預先配置——PVC 的容量宣告只是上限承諾,不是實際佔用。直接在節點上(/var/lib/csi-hostpath-data/)對每個 PVC 的資料夾做 du -sh,11 個綁定中的 PVC 實際落地只有約 4.5GB,其中 Nexus 的 data-nexus-nexus3-0 就佔了 1.7GB(與 blob store 內容一致),Gitea 三個 PostgreSQL 實例加總不到 500MB,真正吃掉磁碟的是容器映像本身:節點上快取的映像檔加總 27.56GB(GC 之後的觀測值;事發前約 45.4GB),是單一最大的磁碟消耗來源——事發當下光容器映像單項就佔掉 45.4GB,接近整顆磁碟的七成(與後文 GC 後的總用量 45.44GB 數值相近,純屬巧合,兩者衡量的不是同一件事)。這個階段的叢集還沒真正跑過幾輪 Pipeline 建置,proxy cache 還沒機會養大,OCP release image、Operator catalog index(redhat-operator-index、community-operator-index 等,單一動輒 1GB 以上)與各元件容器映像才是現階段的大宗。

同一次盤點還挖到一個看不見的角落:/var/lib/csi-hostpath-data/ 底下有一個目錄(對應 pvc-d2114ecf-4b31-454e-b1d7-b2c19fb87a79,1.3GB)已經找不到對應的 PV/PVC 物件——oc get pvoc get pvc 都查不到它。原因是這個 StorageClass 的 reclaimPolicyRetain:PVC 被刪除後,Kubernetes 物件消失了,但節點磁碟上的資料夾原封不動留著,而且不會出現在任何 oc get 輸出裡。這 1.3GB 目前只是零頭,但它會隨著 PVC 建立又刪除的次數持續累積,是這套磁碟帳本裡唯一「官方查詢工具完全看不到」的一項。

trivy-db 每日鏡射與 SBOM 產出並沒有各自佔一塊獨立空間:CronJob 是用 oras 把資料推進 Nexus 的 blob store,因此已經算在上面 Nexus 的 1.7GB 裡,不需要另外列一行。

建議值怎麼來的?用這台機器實測到的數字往前推:

項目 現況(實測) 30 天後的合理預期
容器映像(OCP release、Operator catalog、各元件) 27.56GB(GC 後;事發前約 45.4GB) 30–35GB(catalog 會隨 Operator 版本更新持續累積舊版)
PVC 實際落地(不含 Nexus,10 個綁定 PVC,thin-provisioned,非宣告值 107Gi) 2.8GB 6–10GB(Gitea/Tekton Results 的 PostgreSQL 資料隨紀錄增加)
孤兒 PVC 目錄(reclaimPolicy: Retain,刪除後不清理,oc get pvc 看不到) 1.3GB 沒有回收機制就會持續累加,無法預測上限
Nexus blob store(含 trivy-db、SBOM,皆經 oras 推入同一個 blob store) 1.7GB 15–25GB(Day 10 之後才開始密集代理 npm/docker 套件)
kubelet 驅逐保留(SystemReserved,隨磁碟總量等比放大) 6.75GB 隨磁碟總量等比放大
合計 約 40.1GB 約 58–77GB

現況這幾項加總 40.1GB,跟 crc status 實測的 45.44GB 差 5.3GB,落差主要是容器 runtime 本身的中繼資料與未單獨列出的系統 namespace 開銷——量級對得上,這組數字是可以驗算的,不是憑空湊出來的。孤兒 PVC 目錄在兩欄的處理並不對稱:現況欄的 1.3GB 有算進合計,但 30 天欄因為標成「無法預測上限」而沒有數字可加——58–77GB 這個區間因此沒有計入孤兒目錄的持續累積,實際成長只會更高,不會更低。

事發峰值沒辦法直接量到,只能反推,而且反推的基準要落在 crc status 實測的 45.44GB 上,不是元件盤點加總的 40.1GB(兩者本來就有 5.3GB 落差,不能重複疊加)。驅逐門檻 imagefs.available<15% 意味著峰值下限是 54.25GB(85%);若這次回收的 17.8GB 全數來自這一輪 GC,把它加回 45.44GB,峰值會高達約 63.24GB,逼近 63.82GB 的實體上限,佔比達 99%。下限由門檻直接推得是 54.25GB,但下面這條獨立算法會把真實值收斂到高得多的位置——這通常代表 kubelet 的映像 GC 有自己的高低水位(一般預設 high 85%/low 80%),一旦觸發就會超額回收到低水位以下,不是卡在門檻邊緣削一點就停;但除錯 Pod 短時間內能拉下多少映像也有限,85% 到 99% 這段是否全部由這次操作推上去,沒有更細的證據可以確認,留在這裡誠實標註。不管真實值落在哪個位置,60GB 的配置在這次事件裡都已經沒有餘裕可言。往前推 30 天後的用量時,起點該用這個高位,不是 GC 後才量到的低點。

換一條完全不同的算法可以互相佐證:事發前的元件量——容器映像 45.4GB+PVC 2.8GB+孤兒目錄 1.3GB+Nexus 1.7GB+kubelet 保留 6.75GB,加總約 58GB。這是元件盤點單位,要跟門檻比較得先補上前面量到的 5.3GB 落差(容器 runtime 中繼資料與未單獨列出的系統開銷),換算成 crc status 的口徑是 63.3GB。跟直接法算出的 63.24GB 相差不到 0.1GB——兩條完全獨立的路徑收斂到同一個數字,不是同一個區間裡的兩端。事發峰值就在 63.2GB 上下,佔 63.82GB 實體容量的 99.1%,不是「至少超過 85%」,是幾乎打滿。

這顆磁碟的實際容量是 63.82GB,85% 門檻落在 54.25GB。事發峰值不只觸及這條線,兩條獨立算法都收斂在 63.2GB 上下,也就是說 60GB 這個配置從一開始就沒有留下任何緩衝空間。100GB 這個下限不是「乘個安全係數」的空話,而是直接從這道門檻反推:30 天後預期用量 58–77GB,要留在 85% 門檻之內,磁碟總量至少要到 68–90GB——這裡刻意用 disk-size 的宣告值估算,偏保守,因為那才是使用者實際要輸入的數字;實際可用容量還會像 60GB 換算成 63.82GB 一樣略高一點。取整數並留一點餘裕,100GB 是這條算式能推出的下限。這個數字跟開頭那個「31 的兩倍」不同的地方,不在於它比較大,在於它可以被驗算,也可以被推翻。

不過 100GB 在 85% 門檻下,真正能用的也只有 85GB,對上預期用量上緣的 77GB,只剩下 8GB 緩衝——跟這次事件裡 60GB 磁碟只是逼近門檻就被推過去的教訓對照,這個緩衝依然偏薄。宿主機還有 590GB 可用空間、沒有容量壓力的前提下,更務實的起手式是 120GB:85% 門檻下可用 102GB,對上同一組 77GB 的預期上緣,才留得出真正能喘息的餘裕。

邊界條件與擴充機制

crc config set memory 24576   # stop/start 重啟生效
crc config set disk-size 120   # 必須重建虛擬機
crc delete --force             # ⚠️ 清空既有虛擬機資料
crc start

crc config set disk-size 不會直接變更已建立的 VM 虛擬磁碟,其生效機制需透過 crc delete --force 重建 instance,先前部署的 namespace、服務與 Tekton 執行紀錄都會隨之清理。

實測提醒(OpenShift 4.21 / K8s 1.34):早期版本常見的做法是 oc get --raw /api/v1/nodes/crc/proxy/stats/summary 搭配 Python 解析 kubelet 統計來看磁碟容量,但在 4.21(K8s 1.34)此 kubelet stats proxy 端點已被限制存取,直接回傳 NotFound,該寫法在新版叢集上根本跑不通。前面資源表用到的 crictl statscrictl ps 組合,加上下面三條,是實測可行的替代查法:

# 1. 檢查節點是否被標上 disk-pressure taint
oc describe node crc | grep -A 2 "Taints:"

# 2. 查看叢集磁碟實際用量(CRC 直接提供,最快)
crc status

# 3. 從節點物件讀取 ephemeral-storage 容量與 DiskPressure 狀態
oc describe node crc | grep -iE "ephemeral-storage|DiskPressure"

若需要更貼近節點檔案系統的 df 輸出,可用 oc debug node/crc -- chroot /host df -h /sysroot(會啟動一個 debug pod,速度較慢,用完記得清掉;如前面示範,磁碟已經吃緊時,這個指令本身也可能成為壓垮駱駝的那根稻草)。

🪟 Windows/CRC 限定disk-size 變更需 crc delete --force 重建整台 VM,是 CRC 單機模擬叢集的架構限制;雲端受管 K8s 叢集的儲存擴充通常是線上操作,不需要銷毀整個節點重建。

CPU/記憶體:我配多了,而且是因為誤判

CPU 與記憶體的具體數字另有一段配置歷史:CRC 曾出現 CI 異常,當時懷疑是資源不足所致,因而調高了配置;事後排查顯示,異常的實際成因可能與 CNI 狀態或已結束 PipelineRun 遺留的孤兒 Pod 有關(見 Day 17),而非單純的資源不足。配置調高後未再調降。這是一次「先用資源餘裕排除嫌疑,再回頭定位真正根因」的典型除錯順序。

跟磁碟不同,這個誤判沒有留下長期代價:CPU 與記憶體隨時能用 crc config setcrc stopcrc start 調回合理值,不需要重建整台機器。同一天做的兩個沒有經過推導的決定,一個只是浪費,另一個變成債——差別不在決策品質本身,在於能不能事後修正。

帶著錯誤配置活下去

120GB 才是比較合理的起手式,但這台機器已經跑了 30 天份的紀錄,crc delete --force 會連同 Day 3 到 Day 30 所有實測環境一起銷毀。即使現在主機有 590GB 空間、也已經算出該設多少,這個決定依然動不了——這正是「磁碟配置不可逆」最直接的示範:有能力、有知識、有意願三項都到齊了,實際上還是改不了。

務實的做法是在既有的 60GB 裡把浪費壓下去,而不是等它再撞一次 DiskPressure:

  • 清理已結束的 PipelineRun/TaskRun:前面那次 DiskPressure 事件,實際上是靠 kubelet 自己的映像 GC(image_gc_manager)撐過去的——同一時間 ci namespace 裡的 cleanup-ci-resources 沒有被觸發,代表 Day 17 會提到的這套反應式清理機制,觸發條件比實際需要的更保守,磁碟壓力已經發生才靠 kubelet 內建機制擋下第一波,不能完全指望它。
  • 映像垃圾回收:CRI-O 的 GC 門檻預設偏保守,必要時可手動確認 crictl rmi --prune 是否有東西可清,尤其是被多個 tag 指向、但已經沒有 Pod 在用的舊映像。
  • Nexus proxy cache 容量上限:在 Blob Store 設定裡明確設定容量上限(Soft Quota),避免 npm-proxy/docker-proxy 無上限成長。
  • trivy-db 舊版本清理:每日鏡射會持續產生新的資料庫快照,若沒有輪替機制,舊版本會一直留在 Nexus 裡佔空間。

這幾項不是理論建議——前面那次因為 taint 卡住的 EventListener 滾動更新,最後是靠 kubelet 自己的映像 GC 清出空間、taint 五分鐘後自動解除才恢復;cleanup-ci-resources 沒有介入,下次不見得有這麼幸運的自動復原窗口。

初始化檢查清單

完成 CRC 部署前,建議確認以下關鍵組態:

  • 確認宿主機的實際可用 CPU/記憶體/磁碟餘裕,不要憑印象假設「應該夠用」。
  • disk-size 一次配置足夠容量(建議 120GB,絕對下限 100GB,理由見上)——這是唯一一項事後改不了的設定,其餘都可以事後補救。
  • crc config set memorycpus 依終局的常駐服務加總(見資源表)加上合理尖峰餘裕調整,而不是先猜一個數字再說。
  • 確認 pull-secret 檔案路徑正確,且是透過 crc config set pull-secret-file 寫入(命令列參數帶入的版本在下次啟動後會消失,見 Day 12)。
  • 確認 Hyper-V 已啟用(crc setup 會檢查,但值得手動再確認一次)。
  • 跑完 crc start 後,先照本篇的 crictl 替代法記錄一次基準用量,方便日後比對成長速度——這組數字本篇已經先幫忙量過一次,讀者可以直接拿自己的環境跟這篇對照。

資源配置總結

完成這些基礎組態後,CRC 單機叢集即可具備承載 CI/CD 負載的能力——前提是磁碟這項一次配到位。CPU 與記憶體配錯了還有回頭路,磁碟配錯了就要背著這個決定走完剩下的天數,這也是這篇撞見的 DiskPressure 事件想留下的教訓。隨後便可進入 Windows 環境下的維運維護階段,處理行程控制、CoreDNS 網路解析與 PowerShell 自動化相容性等議題。


上一篇
Day1:從「跑完建構」到「可信供應鏈」
系列文
防範軟體供應鏈攻擊:從零打造具備硬性阻擋能力的雲原生 CI/CD 流水線2
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言