天天看點

Kubernetes 網絡實作——外網通訊

引言

本文介紹 Kubernetes 網絡中外網通訊、LoadBalance 以及 Ingress 部分的實作方案,更多關于 Kubernetes 的介紹均收錄于

<Kubernetes系列文章>

中。

與外網通訊

到目前為止,我們已經清楚了 Kubernetes 叢集内部的網絡通訊原理,但是我們還沒有講清楚外部世界的網絡怎麼和我們的 Kubernetes service 互動。這包含兩個部分,叢集内的資料包怎麼發送到外部網絡,以及外部網絡的資料包怎麼流入 pod。

以我現在使用的内部雲服務為例,我的 Kubernetes 叢集實際上運作在一個虛拟機上,這些虛拟機都被指定了一個内部 ip,也就是 eth0 的 ip 位址,這個内部位址在我們的 Kubernetes 叢集中能夠直接通路。為了讓我們的資料包能夠觸及外部世界的網絡,雲服務商會給我們的虛拟機挂載一個網關,這個網關有兩個作用:其一是為我們的虛拟機提供一個路由表的 target,通過這個 target 虛拟機的資料包可以發送給網關繼而由網關轉發到外部網絡。其二是做一個網絡位址轉換(NAT),給每一個資料包指定到一個公網 ip。由于這個網關的存在,我們的虛拟機才得以通路到公網。但是有一個小問題,因為我們的 pod 有自己的網絡域,它是和虛拟機上的 eth0 網絡域是獨立的。而網關隻能負責虛拟機 eth0 網絡域的 ip,因為它根本不知道虛拟機上還有 pod subnet。那麼 Kubernetes 是怎麼解決這個問題的呢?

Kubernetes 網絡實作——外網通訊

在上圖中,資料包由 pod 的網絡空間發出,經由 veth 對,連接配接到主控端的網絡空間 root。當資料包到達,root 網絡空間後,會從網橋流向預設網絡裝置 eth0,因為資料包的目标 ip 沒有命中主控端的任意網絡裝置。在流到 eth0 之前,别忘了它還會經過 iptables 的處理。iptables 發現這個資料包由 pod 網絡中發出,如果它保持這個源 ip 不變,網關 NAT 會無法識别這個網絡域,資料包就發不出去,是以在這裡 iptables 扮演着一個 NAT 的角色,它将源 ip 從 pod ip 改為 eth0 的 ip。這樣這個資料包才能從虛拟機中經由網關傳送到公網。在網關中,它還會再次進行一次 NAT,将虛拟機的内網位址,轉換成公網位址。而從公網中傳回的資料包也是經曆了相同的路線,NAT 将目标位址外網 ip 轉為虛拟機的内網 ip,然後虛拟機将内網 ip 轉為 pod 的 ip。

還記得我們在試玩環節解決的外網通路 service 的實驗麼,當時我們使用了雲服務中的 LoadBalancer,實際上在 Kubernetes 中有兩種方式可以解決外網通路我們 service 的問題,一個就是前面說的 LoadBalancer,另一個 Kubernetes 的 Ingress Controller。

LoadBalancer,又稱 Layer 4 (傳輸層)入口。當我們建立好 service 後,可以通過雲服務商的 API 來建立 LB,這個 LB 對應了一個外網的 ip 位址,外網的使用者可以通過這個 LB public ip 通路到我們的服務。前面的試玩中,因為我使用的雲服務沒有提供 Kubernetes 對接,是以我 Service type 選為 NodePort,并将L4 LB 綁定到 service 的 node port 上,當 Service type 選為 node port 後,會由 kube-proxy 程序在主控端上占用一個端口 Service Port,保證該端口不會被其他程序使用,然後修改 iptables 将發送到 Service Port 的包轉發到随機 pod 中,這是 kube-proxy 的預設工作模式,該模式的優點是代理過程全部經由核心态完成,而且在第四層就能完成轉發工作。

讓我們看一看 LB 是怎麼工作起來的。首先,我們部署了自己的服務 kubia,然後建立了 LB,外網的資料包到達 LB 後會分發到任意一個 Kubernetes 叢集節點,經由該虛拟機節點的 iptables,它會再次進行一個負載均衡,分發到任意一個 service 的 pod 中,當該 pod 傳回資料包時,必然是用的 pod 的 ip 位址,這怎麼行呢,外網的服務通路者肯定希望傳回的資料包 ip 是 LB 的 ip,這樣才能對的上啊。是以,當資料包從 pod 中傳回時,iptables 和 conntrack 齊心協力地重寫了 ip 位址,虛拟機将 ip 改為自己的 eth0 ip 并傳回給 LB,LB 再将虛拟機的 ip 改為自己的外網 ip。下面這張圖就展示了,這裡所說的流程。

Kubernetes 網絡實作——外網通訊

除了,LB 之外,另一種方案是 Layer 7(應用層)入口。一般來說 Layer 7 入口面向的是 HTTP/HTTPS 協定棧。我們需要将 Service 類型置為 NodePort,這樣 Kubernetes 會選擇一個端口作為服務的名義端口,然後每個節點上的 kube-proxy 都會占用該名義端口,防止其他程序也使用相同端口(會發生傳輸沖突),然後每個節點都會修改自己的 iptables,将流入該名義端口的包根據負載均衡規則轉發到對應的 pod 中。

在 Kubernetes 中,我們稱這種 Layer 7 的 HTTP LoadBalance 為 Ingress,它同樣需要雲服務商提供 L7 的 http LoadBalance,就像 Layer 4 LoadBalance 一樣,它隻能将請求轉發到虛拟機上,然後虛拟機上的 iptables 再轉發到對應的 pod 中。

下圖展示的就是 Layer 7 應用級 LB 的工作方式,當我們通過 Kubernetes 的 api server 建立 Ingress 對象後,雲服務提供商會感覺到該事件,并建立自己的應用級 LB(ALB),該 ALB 會指向多個節點來保證可用性,同時會根據 Ingress 中定義的規則将請求轉發給對應的節點 NodePort(NP)。

Kubernetes 網絡實作——外網通訊

下圖中描述了資料包的流轉,公網中的資料包發給 Ingress LB 後,它将請求轉發到虛拟機上的 NodePort,然後虛拟機根據 iptables 規則将請求轉發到正确的 pod 中。就像前面所說的一樣,這裡也會使用 conntrack 來将傳回包的源 ip 位址從 pod ip 改為 lb 的 ip。

Kubernetes 網絡實作——外網通訊

LB vs Ingress

我們已經知道了 Kubernetes 中當 service 的類型為 LoadBalance 時,會使用 L4 LB,當使用 Ingress 暴露服務時,會使用 L7 LB,那麼他們有什麼不同呢?

所謂四層負載均衡,也就是主要通過封包中的目标位址和端口,再加上負載均衡裝置設定的伺服器選擇方式,決定最終選擇的内部伺服器。以常見的 TCP 為例,負載均衡裝置在接收到第一個來自用戶端的 SYN 請求時,即通過上述方式選擇一個最佳的伺服器,并對封包中的目标 IP 位址進行修改(改為後端伺服器 IP),直接轉發給該伺服器。TCP 的連接配接建立,即三次握手是用戶端和伺服器直接建立的,負載均衡裝置隻是起到一個類似路由器的轉發動作。在某些部署情況下,為保證伺服器回包可以正确傳回給負載均衡裝置,在轉發封包的同時可能還會對封包原來的源位址進行修改,當然大部分情況下可能不會這麼做,那樣的話伺服器的回包可能就不會經過 LB 裝置。

Kubernetes 網絡實作——外網通訊

所謂七層負載均衡,也稱為“内容交換”,也就是主要通過封包中的真正有意義的應用層内容,再加上負載均衡裝置設定的伺服器選擇方式,決定最終選擇的内部伺服器。以常見的 TCP 為例,負載均衡裝置如果要根據真正的應用層内容再選擇伺服器,隻能先和用戶端建立連接配接(TCP 三次握手)後,才可能接收到用戶端發送的真正應用層内容的封包,然後再根據該封包中的特定字段,再加上負載均衡裝置設定的伺服器選擇方式,決定最終選擇的内部伺服器。負載均衡裝置在這種情況下,更類似于一個代理伺服器。負載均衡和前端的用戶端以及後端的伺服器會分别建立 TCP 連接配接。是以從這個技術原理上來看,七層負載均衡明顯地對負載均衡裝置的要求更高,處理七層的能力也必然會低于四層模式的部署方式。

L7 LB 的優點是它更加靈活,舉個例子:因為它運作在 HTTP 協定棧中,是以它能知道 URL 資訊,是以可以通過 URL 來作為轉發規則,同時我們還可以通過 HTTP 的

X-Forwarded-For

頭來擷取到 HTTP 請求的 client ip。另外一個優點是更加安全,網絡中最常見的 SYN Flood 攻擊,即黑客控制衆多源用戶端,使用虛假 IP 位址對同一目标發送 SYN 攻擊,通常這種攻擊會大量發送 SYN 封包,耗盡伺服器上的相關資源,以達到 Denial of Service(DoS) 的目的。從技術原理上也可以看出,四層模式下這些 SYN 攻擊都會被轉發到後端的伺服器上;而七層模式下這些 SYN 攻擊自然在負載均衡裝置上就截止,不會影響背景伺服器的正常營運。

現在的 7 層負載均衡,主要還是着重于應用廣泛的 HTTP 協定,是以其應用範圍主要是衆多的網站或者内部資訊平台等基于 B/S 開發的系統。4 層負載均衡則對應其他 TCP 應用,例如基于 C/S 開發的系統。

文章說明

更多有價值的文章均收錄于

貝貝貓的文章目錄
Kubernetes 網絡實作——外網通訊

版權聲明: 本部落格所有文章除特别聲明外,均采用 BY-NC-SA 許可協定。轉載請注明出處!

創作聲明: 本文基于下列所有參考内容進行創作,其中可能涉及複制、修改或者轉換,圖檔均來自網絡,如有侵權請聯系我,我會第一時間進行删除。

參考内容

[1]

kubernetes GitHub 倉庫

[2]

Kubernetes 官方首頁

[3]

Kubernetes 官方 Demo

[4] 《Kubernetes in Action》

[5]

了解Kubernetes網絡之Flannel網絡

[6]

Kubernetes Handbook

[7]

iptables概念介紹及相關操作

[8]

iptables超全詳解

[9]

了解Docker容器網絡之Linux Network Namespace

[10]

A Guide to the Kubernetes Networking Model

[11]

Kubernetes with Flannel — Understanding the Networking

[12]

四層、七層負載均衡的差別

繼續閱讀