為什么我們重寫 k8s ingress controller
大家好,我是來自蘇州思必馳的金衛,今天和大家聊聊 Apache APISIX 與 k8s 集成代替原生 ingress 的話題。
寫這篇文章時,我們已經在生產環境上應用了 Apache APISIX,接管了部分業務的入口流量,同時正逐步把原生 ingress 中流量遷移過來,如下圖所示:
借助 Apache APISIX 動態路由能力做流量分發,同時自定義一些插件,滿足業務需求。
APISIX-ingress-controller 將 pod ip 注冊到 upstream 的,node 中,業務流量可以繞過 kube DNS 直接訪問到 pod。也正是在此基礎上,可以通過插件實現一些特殊負載均衡策略。
從圖上看,好像做了一件與原生 ingress 重復的事情。那這篇文章我們就簡單介紹一下為什么舍棄原生 ingress,用 Apache APISIX 自建一套 ingress controller。
ingress 是什么
簡單講,Ingress 是 Kubernetes 處理邊緣入口流量的一種方式。
ingress 解決什么問題
由于 Kubernetes 集群內的服務都是虛擬網絡,外部流量訪問集群內部,至少需要一個公網ip和端口映射。
Kubernetes 原生 ingress controller 的問題
Nginx ingress controller 幫助我們維護了 Kubernetes 集群與 Nginx 的狀態同步,并且提供了基本的反向代理能力,為什么我們還要自己造個輪子呢? 業務的需求不容忽視,我們對 ingress controller 有更多的期待。
在使用 Kubernetes 原生 ingress controller 之后,我們發現以下幾點比較突出的問題:
reload 問題
Kubernetes 原生 ingress 在設計上,將 YAML 配置文件交由 ingress controller 處理,轉換為 nginx.conf,再觸發 reload nginx.conf 使配置生效。
日常運維免不了偶爾動一動 ingress YAML 配置,每一次配置生效,都會觸發一次 reload,這是不能接受的,尤其在邊緣流量采用?連接時,更容易導致事故。
Apache APISIX 支持熱配置,隨時可以定義和修改路由,而且不會觸發 nginx reload。
在 annotation 中寫腳本、填充參數
原生 ingress controller 支持在 yaml 中 annotation 定義腳本片段,感覺是為了支持高級功能而實現的一個臨時方案,說實話,真不好管理。大量的 annotation 腳本給配置人員帶來困擾。
在 Apache APISIX 中,我們可以通過插件代碼編寫邏輯,暴露出簡單的配置接口,方便配置的維護,避免腳本對配置人員的干擾。
缺少對有狀態負載均衡的支持
動態調整權重
業務服務常常需要按照百分比控制流量,這在 Kubernetes 中卻變成了麻煩。
擴展能力薄弱
Apache APISIX ingress controller
由于 Apache APISIX 強大的路由和擴展能力,將 Apache APISIX 作為 ingress 的一種實現,可以輕松解決以上提到的痛點,也為社區多一種 ingress controller 選擇。
時序圖如下:
想要實現 Apache APISIX ingress controller,需要解決兩類基礎問題,一是解決 kubernetes 集群與 Apache APISIX 狀態的同步; 二是將 Apache APISIX 中的對象在 kubernetes 中定義出來 (CRD)。
為了快速集成 Apache APISIX,發揮出 Apache APISIX 的優勢,我們創建了 Apache APISIX ingress controller 項目(歡迎大家參與),該項目目前初步實現了第一類基礎問題: 同步 Kubernetes pod 信息到 Apache APISIX 中的 upstream,同時實現主備,解決自身的高可用問題。
由于 Kubernetes 采用 YAML 申明式定義集群狀態,我們需要為 Apache APISIX 中的對象(route/service/upstream/plugin) 定義 CRD(Custom Resource Definitions), 以融入 kubernetes。
同時為了方便現有 Kubernetes ingress 使用者的遷移,我們會盡量兼容現有 ingress 的配置項。
這些特性將是我們接下來努力的目標,歡迎大家一起參與。