把 k3s 從 Ubuntu 搬到 OpenSUSE MicroOS,順便換上 FluxCD GitOps

把 k3s 從 Ubuntu 搬到 OpenSUSE MicroOS,順便換上 FluxCD GitOps

前言 我的 Homelab 跑著一台 Proxmox VE,底下有一個 Ubuntu Server 24.04 的 VM 負責跑 k3s cluster,這個 cluster 接管了家裡所有的自架服務:從 Vaultwarden 密碼管理、Karakeep 書籤、Filebrowser 文件管理,到 Wakapi 開發時間追蹤,大大小小跑了十幾個服務。 這個架構一直跑得很穩。直到 Linux kernel 7.0 發布,我才開始動搖。 kernel 7.0 的各種新特性讓我心癢,Ubuntu 26.04 LTS 剛好以 kernel 7.0 作為預設核心,理論上從 24.04 升上去就能一步到位。但在一個跑著十幾個服務的生產 VM 上執行 do-release-upgrade,那種心臟發抖的感覺,即便有做好備份,還是讓我遲遲下不了手。 就在猶豫要不要升級的當下,我問了自己一個問題:「我要繼續用 Ubuntu 嗎?」 這個問題打開了一扇門。我的 Linux desktop 是 openSUSE Tumbleweed + KDE Plasma,用了三年、換過兩台裝置(筆電和桌電),沒有遇到太多問題。Tumbleweed 的滾動更新讓我一直跑著最新的 kernel,升級這件事從來不是一個需要另外排行程的壓力事件。 既然 desktop 側已經對 openSUSE 生態有信心,server 側為什麼不試試看? 這讓我開始認真考慮:有沒有一種 OS,讓 server 的升級這件事也變成「預設安全」而不是「需要勇氣」? 為什麼選 OpenSUSE MicroOS OpenSUSE MicroOS 是一個 Immutable OS(不可變作業系統),核心特性有幾個: ...

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」。 ...