k3s Ingress Controller 從 Nginx 遷移到 Traefik 同時整合 CrowdSec

k3s Ingress Controller 從 Nginx 遷移到 Traefik 同時整合 CrowdSec

TL;DR 馬上就看到有小王八蛋想壞壞 前言 2025 年 11 月,Kubernetes SIG Network 發布了一篇公告:ingress-nginx 將正式退役。 這個消息讓不少人震驚,但嚴格來說有個細節需要釐清。目前市場上有兩個長得很像的 nginx ingress controller: kubernetes/ingress-nginx:由 Kubernetes SIG Network 維護,這次宣布 EOL 的就是它。 nginx/kubernetes-ingress(又稱 NKS):由 F5 / NGINX Inc. 維護,目前仍持續開發中。 我的 homelab k3s cluster 一直以來用的是 F5 維護的版本,嚴格來說不在這次 EOL 的範圍內。但這個公告還是給了我一個動力,與其繼續追蹤兩個版本之間的差異、擔心哪天又有什麼變化,不如趁這個機會把遷移一次做完。 遷移目標選定 Traefik v3,原因有兩個: k3s 內建 Traefik 作為預設 Ingress Controller,1.32 版本後升級為 Traefik v3,搭配 HelmChartConfig 管理,和 cluster 的整合度最高。 順手引入 CrowdSec 主動防護——長期以來我的服務靠著 Cloudflare proxy 當唯一守門人,但我一直想要在 Ingress 層就能即時判斷並封鎖攻擊者 IP,而不只是依賴前端的 CDN 過濾。 為什麼不選 Cilium Gateway API 在決定遷移到 Traefik 之前,我也閱讀了 Gene 的告別 ingress-nginx:Cilium Gateway API 遷移筆記,評估過 Cilium Gateway API 方案。Cilium 在 CNI 層整合了 Gateway API,理論上能提供更底層、效能更好的流量控制,且完全符合 Kubernetes Gateway API 的標準規範。 ...

Helm Smart Resource:讓你的 Chart 學會與既有資源和平共處

前言 在 Kubernetes 的世界裡,Helm 無疑是管理應用程式部署的霸主。它標準化了資源的定義,讓我們可以用宣告式的方式管理整套系統。然而,在真實世界的維運場景中,事情往往沒那麼單純。 我們常遇到一種尷尬的情況:某些資源(例如 Database 的 Secret、外部系統的 ConfigMap)可能在 Helm Chart 安裝之前就已經由維運人員手動建立,或是由另一個流程(如 Terraform)預先準備好了。 這時候,如果直接執行 helm install,往往會收到 “resource already exists” 的錯誤;如果使用 helm upgrade --install,又擔心 Helm 會覆蓋掉這些既有設定。 這篇文章將分享一種「Smart Resource」的設計模式,透過 Helm 的 lookup 函數與樣板邏輯,讓你的 Chart 能夠聰明地判斷:「這東西是我管的嗎?如果是,我才動它;如果不是,我就尊重現狀。」 核心難題:Ownership 在 Kubernetes 中,資源的「所有權」觀念至關重要。Helm 預設認為它 release 中的所有資源都應該由它全權管理。但當我們需要與外部資源協作時,我們需要更細緻的控制。 我們的目標很明確: 若資源不存在:建立它,並標記為 Helm 管理。 若資源已存在且由 Helm 管理:更新它(Patch/Merge)。 若資源已存在但由外部管理:保持原狀,不進行覆蓋或刪除。 為了達成這個目標,我們需要一個輔助函數來判斷資源的歸屬權。 實作細節 1. 定義所有權檢查 首先,我們在 _helpers.tpl 中定義一個檢查函數。Helm 會在它建立的資源上打上特定的 Annotations(meta.helm.sh/release-name 和 meta.helm.sh/release-namespace)。我們可以利用這一點來判斷資源是否屬於當前的 Release。 {{/* Check if a resource is owned by this Helm release Returns "true" or "false" as string for stable piping */}} {{- define "visionone-filesecurity.isOwnedByRelease" -}} {{- $resource := .resource -}} {{- $releaseName := .releaseName -}} {{- $releaseNamespace := .releaseNamespace -}} {{- $owned := and $resource (hasKey $resource.metadata "annotations") (eq (get $resource.metadata.annotations "meta.helm.sh/release-name") $releaseName) (eq (get $resource.metadata.annotations "meta.helm.sh/release-namespace") $releaseNamespace) -}} {{ printf "%t" $owned }} {{- end -}} 這段程式碼邏輯很簡單:只有當資源存在,且其 Annotations 中的 Release Name 與 Namespace 都與當前 Release 相符時,才視為「Owned」。 ...