Linux中國

Kubernetes 網路運維

最近我一直在研究 Kubernetes 網路。我注意到一件事情就是,雖然關於如何設置 Kubernetes 網路的文章很多,也寫得很不錯,但是卻沒有看到關於如何去運維 Kubernetes 網路的文章、以及如何完全確保它不會給你造成生產事故。

在本文中,我將儘力讓你相信三件事情(我覺得這些都很合理 :)):

  • 避免生產系統網路中斷非常重要
  • 運維聯網軟體是很難的
  • 有關你的網路基礎設施的重要變化值得深思熟慮,以及這種變化對可靠性的影響。雖然非常「牛x」的谷歌人常說「這是我們在谷歌正在用的」(谷歌工程師在 Kubernetes 上正做著很重大的工作!但是我認為重要的仍然是研究架構,並確保它對你的組織有意義)。

我肯定不是 Kubernetes 網路方面的專家,但是我在配置 Kubernetes 網路時遇到了一些問題,並且比以前更加了解 Kubernetes 網路了。

運維聯網軟體是很難的

在這裡,我並不討論有關運維物理網路的話題(對於它我不懂),而是討論關於如何讓像 DNS 服務、負載均衡以及代理這樣的軟體正常工作方面的內容。

我在一個負責很多網路基礎設施的團隊工作過一年時間,並且因此學到了一些運維網路基礎設施的知識!(顯然我還有很多的知識需要繼續學習)在我們開始之前有三個整體看法:

  • 聯網軟體經常重度依賴 Linux 內核。因此除了正確配置軟體之外,你還需要確保許多不同的系統控制(sysctl)配置正確,而一個錯誤配置的系統控制就很容易讓你處於「一切都很好」和「到處都出問題」的差別中。
  • 聯網需求會隨時間而發生變化(比如,你的 DNS 查詢或許比上一年多了五倍!或者你的 DNS 伺服器突然開始返回 TCP 協議的 DNS 響應而不是 UDP 的,它們是完全不同的內核負載!)。這意味著之前正常工作的軟體突然開始出現問題。
  • 修復一個生產網路的問題,你必須有足夠的經驗。(例如,看這篇 由 Sophie Haskins 寫的關於 kube-dns 問題調試的文章)我在網路調試方面比以前進步多了,但那也是我花費了大量時間研究 Linux 網路知識之後的事了。

我距離成為一名網路運維專家還差得很遠,但是我認為以下幾點很重要:

  1. 對生產網路的基礎設施做重要的更改是很難得的(因為它會產生巨大的混亂)
  2. 當你對網路基礎設施做重大更改時,真的應該仔細考慮如果新網路基礎設施失敗該如何處理
  3. 是否有很多人都能理解你的網路配置

切換到 Kubernetes 顯然是個非常大的更改!因此,我們來討論一下可能會導致錯誤的地方!

Kubernetes 網路組件

在本文中我們將要討論的 Kubernetes 網路組件有:

  • 覆蓋網路 overlay network 的後端(像 flannel/calico/weave 網路/romana)
  • kube-dns
  • kube-proxy
  • 入站控制器 / 負載均衡器
  • kubelet

如果你打算配置 HTTP 服務,或許這些你都會用到。這些組件中的大部分我都不會用到,但是我儘可能去理解它們,因此,本文將涉及它們有關的內容。

最簡化的方式:為所有容器使用宿主機網路

讓我們從你能做到的最簡單的東西開始。這並不能讓你在 Kubernetes 中運行 HTTP 服務。我認為它是非常安全的,因為在這裡面可以讓你動的東西很少。

如果你為所有容器使用宿主機網路,我認為需要你去做的全部事情僅有:

  1. 配置 kubelet,以便於容器內部正確配置 DNS
  2. 沒了,就這些!

如果你為每個 pod 直接使用宿主機網路,那就不需要 kube-dns 或者 kube-proxy 了。你都不需要一個作為基礎的覆蓋網路。

這種配置方式中,你的 pod 們都可以連接到外部網路(同樣的方式,你的宿主機上的任何進程都可以與外部網路對話),但外部網路不能連接到你的 pod 們。

這並不是最重要的(我認為大多數人想在 Kubernetes 中運行 HTTP 服務並與這些服務進行真實的通訊),但我認為有趣的是,從某種程度上來說,網路的複雜性並不是絕對需要的,並且有時候你不用這麼複雜的網路就可以實現你的需要。如果可以的話,儘可能地避免讓網路過於複雜。

運維一個覆蓋網路

我們將要討論的第一個網路組件是有關覆蓋網路的。Kubernetes 假設每個 pod 都有一個 IP 地址,這樣你就可以與那個 pod 中的服務進行通訊了。我在說到「覆蓋網路」這個詞時,指的就是這個意思(「讓你通過它的 IP 地址指向到 pod 的系統)。

所有其它的 Kubernetes 網路的東西都依賴正確工作的覆蓋網路。更多關於它的內容,你可以讀 這裡的 kubernetes 網路模型

Kelsey Hightower 在 kubernetes 艱難之路 中描述的方式看起來似乎很好,但是,事實上它的作法在超過 50 個節點的 AWS 上是行不通的,因此,我不打算討論它了。

有許多覆蓋網路後端(calico、flannel、weaveworks、romana)並且規劃非常混亂。就我的觀點來看,我認為一個覆蓋網路有 2 個職責:

  1. 確保你的 pod 能夠發送網路請求到外部的集群
  2. 保持一個到子網路的穩定的節點映射,並且保持集群中每個節點都可以使用那個映射得以更新。當添加和刪除節點時,能夠做出正確的反應。

Okay! 因此!你的覆蓋網路可能會出現的問題是什麼呢?

  • 覆蓋網路負責設置 iptables 規則(最基本的是 iptables -A -t nat POSTROUTING -s $SUBNET -j MASQUERADE),以確保那個容器能夠向 Kubernetes 之外發出網路請求。如果在這個規則上有錯誤,你的容器就不能連接到外部網路。這並不很難(它只是幾條 iptables 規則而已),但是它非常重要。我發起了一個 拉取請求,因為我想確保它有很好的彈性。
  • 添加或者刪除節點時可能會有錯誤。我們使用 flannel hostgw 後端,我們開始使用它的時候,節點刪除功能 尚未開始工作
  • 你的覆蓋網路或許依賴一個分散式資料庫(etcd)。如果那個資料庫發生什麼問題,這將導致覆蓋網路發生問題。例如,https://github.com/coreos/flannel/issues/610 上說,如果在你的 flannel etcd 集群上丟失了數據,最後的結果將是在容器中網路連接會丟失。(現在這個問題已經被修復了)
  • 你升級 Docker 以及其它東西導致的崩潰
  • 還有更多的其它的可能性!

我在這裡主要討論的是過去發生在 Flannel 中的問題,但是我並不是要承諾不去使用 Flannel —— 事實上我很喜歡 Flannel,因為我覺得它很簡單(比如,類似 vxlan 在後端這一塊的部分 只有 500 行代碼),對我來說,通過代碼來找出問題的根源成為了可能。並且很顯然,它在不斷地改進。他們在審查拉取請求方面做的很好。

到目前為止,我運維覆蓋網路的方法是:

  • 學習它的工作原理的詳細內容以及如何去調試它(比如,Flannel 用於創建路由的 hostgw 網路後端,因此,你只需要使用 sudo ip route list 命令去查看它是否正確即可)
  • 如果需要的話,維護一個內部構建版本,這樣打補丁比較容易
  • 有問題時,向上游貢獻補丁

我認為去遍歷所有已合併的拉取請求以及過去已修復的 bug 清單真的是非常有幫助的 —— 這需要花費一些時間,但這是得到一個其它人遇到的各種問題的清單的好方法。

對其他人來說,他們的覆蓋網路可能工作的很好,但是我並不能從中得到任何經驗,並且我也曾聽說過其他人報告類似的問題。如果你有一個類似配置的覆蓋網路:a) 在 AWS 上並且 b) 在多於 50-100 節點上運行,我想知道你運維這樣的一個網路有多大的把握。

運維 kube-proxy 和 kube-dns?

現在,我有一些關於運維覆蓋網路的想法,我們來討論一下。

這個標題的最後面有一個問號,那是因為我並沒有真的去運維過。在這裡我還有更多的問題要問答。

這裡的 Kubernetes 服務是如何工作的!一個服務是一群 pod 們,它們中的每個都有自己的 IP 地址(像 10.1.0.3、10.2.3.5、10.3.5.6 這樣)

  1. 每個 Kubernetes 服務有一個 IP 地址(像 10.23.1.2 這樣)
  2. kube-dns 去解析 Kubernetes 服務 DNS 名字為 IP 地址(因此,my-svc.my-namespace.svc.cluster.local 可能映射到 10.23.1.2 上)
  3. kube-proxy 配置 iptables 規則是為了在它們之間隨機進行均衡負載。Kube-proxy 也有一個用戶空間的輪詢負載均衡器,但是在我的印象中,他們並不推薦使用它。

因此,當你發出一個請求到 my-svc.my-namespace.svc.cluster.local 時,它將解析為 10.23.1.2,然後,在你本地主機上的 iptables 規則(由 kube-proxy 生成)將隨機重定向到 10.1.0.3 或者 10.2.3.5 或者 10.3.5.6 中的一個上。

在這個過程中我能想像出的可能出問題的地方:

  • kube-dns 配置錯誤
  • kube-proxy 掛了,以致於你的 iptables 規則沒有得以更新
  • 維護大量的 iptables 規則相關的一些問題

我們來討論一下 iptables 規則,因為創建大量的 iptables 規則是我以前從沒有聽過的事情!

kube-proxy 像如下這樣為每個目標主機創建一個 iptables 規則:這些規則來自 這裡

-A KUBE-SVC-LI77LBOOMGYET5US -m comment --comment "default/showreadiness:showreadiness" -m statistic --mode random --probability 0.20000000019 -j KUBE-SEP-E4QKA7SLJRFZZ2DD[b][c]  
-A KUBE-SVC-LI77LBOOMGYET5US -m comment --comment "default/showreadiness:showreadiness" -m statistic --mode random --probability 0.25000000000 -j KUBE-SEP-LZ7EGMG4DRXMY26H  
-A KUBE-SVC-LI77LBOOMGYET5US -m comment --comment "default/showreadiness:showreadiness" -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-RKIFTWKKG3OHTTMI  
-A KUBE-SVC-LI77LBOOMGYET5US -m comment --comment "default/showreadiness:showreadiness" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-CGDKBCNM24SZWCMS 
-A KUBE-SVC-LI77LBOOMGYET5US -m comment --comment "default/showreadiness:showreadiness" -j KUBE-SEP-RI4SRNQQXWSTGE2Y 

因此,kube-proxy 創建了許多 iptables 規則。它們都是什麼意思?它對我的網路有什麼樣的影響?這裡有一個來自華為的非常好的演講,它叫做 支持 50,000 個服務的可伸縮 Kubernetes,它說如果在你的 Kubernetes 集群中有 5,000 服務,增加一個新規則,將需要 11 分鐘。如果這種事情發生在真實的集群中,我認為這將是一件非常糟糕的事情。

在我的集群中肯定不會有 5,000 個服務,但是 5,000 並不是那麼大的一個數字。為解決這個問題,他們給出的解決方案是 kube-proxy 用 IPVS 來替換這個 iptables 後端,IPVS 是存在於 Linux 內核中的一個負載均衡器。

看起來,像 kube-proxy 正趨向於使用各種基於 Linux 內核的負載均衡器。我認為這只是一定程度上是這樣,因為他們支持 UDP 負載均衡,而其它類型的負載均衡器(像 HAProxy)並不支持 UDP 負載均衡。

但是,我覺得使用 HAProxy 更舒服!它能夠用於去替換 kube-proxy!我用谷歌搜索了一下,然後發現了這個 thread on kubernetes-sig-network,它說:

kube-proxy 是很難用的,我們在生產系統中使用它近一年了,它在大部分的時間都表現的很好,但是,隨著我們集群中的服務越來越多,我們發現它的排錯和維護工作越來越難。在我們的團隊中沒有 iptables 方面的專家,我們只有 HAProxy & LVS 方面的專家,由於我們已經使用它們好幾年了,因此我們決定使用一個中心化的 HAProxy 去替換分散式的代理。我覺得這可能會對在 Kubernetes 中使用 HAProxy 的其他人有用,因此,我們更新了這個項目,並將它開源:https://github.com/AdoHe/kube2haproxy。如果你發現它有用,你可以去看一看、試一試。

因此,那是一個有趣的選擇!我在這裡確實沒有答案,但是,有一些想法:

  • 負載均衡器是很複雜的
  • DNS 也很複雜
  • 如果你有運維某種類型的負載均衡器(比如 HAProxy)的經驗,與其使用一個全新的負載均衡器(比如 kube-proxy),還不如做一些額外的工作去使用你熟悉的那個來替換,或許更有意義。
  • 我一直在考慮,我們希望在什麼地方能夠完全使用 kube-proxy 或者 kube-dns —— 我認為,最好是只在 Envoy 上投入,並且在負載均衡&服務發現上完全依賴 Envoy 來做。因此,你只需要將 Envoy 運維好就可以了。

正如你所看到的,我在關於如何運維 Kubernetes 中的內部代理方面的思路還是很混亂的,並且我也沒有使用它們的太多經驗。總體上來說,kube-proxy 和 kube-dns 還是很好的,也能夠很好地工作,但是我仍然認為應該去考慮使用它們可能產生的一些問題(例如,」你不能有超出 5000 的 Kubernetes 服務「)。

入口

如果你正在運行著一個 Kubernetes 集群,那麼到目前為止,很有可能的是,你事實上需要 HTTP 請求去進入到你的集群中。這篇博客已經太長了,並且關於入口我知道的也不多,因此,我們將不討論關於入口的內容。

有用的鏈接

幾個有用的鏈接,總結如下:

我認為網路運維很重要

我對 Kubernetes 的所有這些聯網軟體的感覺是,它們都仍然是非常新的,並且我並不能確定我們(作為一個社區)真的知道如何去把它們運維好。這讓我作為一個操作者感到很焦慮,因為我真的想讓我的網路運行的很好!:) 而且我覺得作為一個組織,運行你自己的 Kubernetes 集群需要相當大的投入,以確保你理解所有的代碼片段,這樣當它們出現問題時你可以去修復它們。這不是一件壞事,它只是一個事而已。

我現在的計劃是,繼續不斷地學習關於它們都是如何工作的,以儘可能多地減少對我動過的那些部分的擔憂。

一如繼往,我希望這篇文章對你有幫助,並且如果我在這篇文章中有任何的錯誤,我非常喜歡你告訴我。

via: https://jvns.ca/blog/2017/10/10/operating-a-kubernetes-network/

作者:Julia Evans 譯者:qhwdw 校對:wxy

本文由 LCTT 原創編譯,Linux中國 榮譽推出


本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive

對這篇文章感覺如何?

太棒了
0
不錯
0
愛死了
0
不太好
0
感覺很糟
0
雨落清風。心向陽

    You may also like

    Leave a reply

    您的電子郵箱地址不會被公開。 必填項已用 * 標註

    此站點使用Akismet來減少垃圾評論。了解我們如何處理您的評論數據

    More in:Linux中國