歡迎光臨
每天分享高質量文章

Kubernetes 網絡運維 | Linux 中國

運維聯網軟體是很難的
— Julia Evans


致謝
編譯自 | 
https://jvns.ca/blog/2017/10/10/operating-a-kubernetes-network/
 
 作者 | Julia Evans
 譯者 | qhwdw ?共計翻譯:145 篇 貢獻時間:309 天

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

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

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

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

運維聯網軟體是很難的

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

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

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

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

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

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

Okay! 因此!你的改寫網絡可能會出現的問題是什麼呢?

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

我在這裡主要討論的是過去發生在 Flannel 中的問題,但是我並不是要承諾不去使用 Flannel —— 事實上我很喜歡 Flannel,因為我覺得它很簡單(比如,類似 vxlan 在後端這一塊的部分[7] 只有 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 規則:這些規則來自 這裡[8]

  1. -A KUBE-SVC-LI77LBOOMGYET5US -m comment --comment "default/showreadiness:showreadiness" -m statistic --mode random --probability 0.20000000019 -j KUBE-SEP-E4QKA7SLJRFZZ2DD[b][c]  

  2. -A KUBE-SVC-LI77LBOOMGYET5US -m comment --comment "default/showreadiness:showreadiness" -m statistic --mode random --probability 0.25000000000 -j KUBE-SEP-LZ7EGMG4DRXMY26H  

  3. -A KUBE-SVC-LI77LBOOMGYET5US -m comment --comment "default/showreadiness:showreadiness" -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-RKIFTWKKG3OHTTMI  

  4. -A KUBE-SVC-LI77LBOOMGYET5US -m comment --comment "default/showreadiness:showreadiness" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-CGDKBCNM24SZWCMS

  5. -A KUBE-SVC-LI77LBOOMGYET5US -m comment --comment "default/showreadiness:showreadiness" -j KUBE-SEP-RI4SRNQQXWSTGE2Y

因此,kube-proxy 創建了許多 iptables 規則。它們都是什麼意思?它對我的網絡有什麼樣的影響?這裡有一個來自華為的非常好的演講,它叫做 支持 50,000 個服務的可伸縮 Kubernetes[9],它說如果在你的 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[10],它說:

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 網絡模型[2]
◈ GKE 網絡是如何工作的:https://www.youtube.com/watch?v=y2bhV81MfKQ
◈ 上述的有關 kube-proxy 上性能的討論:https://www.youtube.com/watch?v=4-pawkiazEg

我認為網絡運維很重要

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

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

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


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

作者:Julia Evans[14] 譯者:qhwdw 校對:wxy

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

赞(0)

分享創造快樂