k8s 網(wǎng)絡(luò)部署匯總——解決集群外部服務(wù)訪問問題

1. Kubernetes 網(wǎng)絡(luò)基礎(chǔ)知識

Kubernetes 網(wǎng)絡(luò)模型定義了一個“平面”網(wǎng)絡(luò),其中:

  • 每個 pod 都有自己的 IP 地址。

  • 任何節(jié)點上的 Pod 都可以在沒有 NAT 的情況下與所有其他節(jié)點上的所有 Pod 通信。

1.1 CNI 插件

CNI(容器網(wǎng)絡(luò)接口)是一個標(biāo)準(zhǔn) API,它允許不同的網(wǎng)絡(luò)實現(xiàn)插入 Kubernetes。每當(dāng)創(chuàng)建或銷毀 pod 時,Kubernetes 都會調(diào)用 API。有兩種類型的 CNI 插件:

  • CNI 網(wǎng)絡(luò)插件:負責(zé)在 Kubernetes pod 網(wǎng)絡(luò)中添加或刪除 pod。這包括創(chuàng)建/刪除每個 pod 的網(wǎng)絡(luò)接口以及將其與其余的網(wǎng)絡(luò)實現(xiàn)連接/斷開。

  • CNI IPAM 插件:負責(zé)在創(chuàng)建或刪除 Pod 時為其分配和釋放 IP 地址。根據(jù)插件的不同,這可能包括為每個節(jié)點分配一個或多個 IP 地址 (CIDR) 范圍,或從底層公共云網(wǎng)絡(luò)獲取 IP 地址以分配給 pod。

1.2 Kubenet

Kubenet 是一個非?;A(chǔ)的網(wǎng)絡(luò)插件,內(nèi)置在 Kubernetes 中。它不實現(xiàn)跨節(jié)點網(wǎng)絡(luò)或網(wǎng)絡(luò)策略。它通常與云提供商集成一起使用,該集成在云提供商網(wǎng)絡(luò)中設(shè)置路由以在節(jié)點之間或在單節(jié)點環(huán)境中進行通信。Kubenet 與 Calico 不兼容。

1.3 覆蓋網(wǎng)絡(luò)(Overlay)

覆蓋網(wǎng)絡(luò)是在另一個網(wǎng)絡(luò)之上的網(wǎng)絡(luò)層。在 Kubernetes 的上下文中,覆蓋網(wǎng)絡(luò)可用于處理底層網(wǎng)絡(luò)之上節(jié)點之間的 pod 到 pod 流量。用于kubernetes覆蓋網(wǎng)絡(luò)的兩種常見網(wǎng)絡(luò)協(xié)議是 VXLAN 和 IP-in-IP。

使用覆蓋網(wǎng)絡(luò)的主要缺點是:

  • 輕微的性能影響。封裝數(shù)據(jù)包的過程占用少量 CPU,數(shù)據(jù)包中用于編碼封裝(VXLAN 或 IP-in-IP 標(biāo)頭)所需的額外字節(jié)減少了可以發(fā)送的內(nèi)部數(shù)據(jù)包的最大大小,進而可以意味著需要為相同數(shù)量的總數(shù)據(jù)發(fā)送更多數(shù)據(jù)包。

  • pod IP 地址不可在集群外路由。

1.4 跨子網(wǎng)覆蓋(Cross-subnet overlays)

除了標(biāo)準(zhǔn)的 VXLAN 或 IP-in-IP 覆蓋外,Calico 還支持 VXLAN 和 IP-in-IP 的“跨子網(wǎng)”模式。在這種模式下,在每個子網(wǎng)中,底層網(wǎng)絡(luò)充當(dāng) L2 網(wǎng)絡(luò)。在單個子網(wǎng)內(nèi)發(fā)送的數(shù)據(jù)包不會被封裝,因此您可以獲得非覆蓋網(wǎng)絡(luò)的性能。

1.5 集群外的 Pod IP 可路由性

不可路由

如果 pod IP 地址在集群外部不可路由,那么當(dāng) pod 嘗試建立到集群外部 IP 地址的網(wǎng)絡(luò)連接時,Kubernetes 使用一種稱為 SNAT(源網(wǎng)絡(luò)地址轉(zhuǎn)換)的技術(shù)來更改源 IP從 pod 的 IP 地址到托管 pod 的節(jié)點的 IP 地址。

集群外部的任何東西都不能直接連接到 Pod IP 地址,因為更廣泛的網(wǎng)絡(luò)不知道如何將數(shù)據(jù)包路由到 Pod IP 地址。

可路由

如果 pod IP 地址可在集群外部路由,則 pod 可以在沒有 SNAT 的情況下連接到外部世界,而外部世界可以直接連接到 pod,而無需通過 Kubernetes 服務(wù)或 Kubernetes 入口。

可在集群外路由的 Pod IP 地址的主要缺點是 Pod IP 在更廣泛的網(wǎng)絡(luò)中必須是唯一的。

什么決定了可路由性?

如果您為集群使用覆蓋網(wǎng)絡(luò),則 pod IP 通常無法在集群外部路由。

如果您不使用覆蓋網(wǎng)絡(luò),那么 pod IP 是否可在集群外部路由取決于正在使用的 CNI 插件、云提供商集成或(對于本地)BGP 與物理網(wǎng)絡(luò)對等的組合。

1.6 BGP

BGP(邊界網(wǎng)關(guān)協(xié)議)是一種基于標(biāo)準(zhǔn)的網(wǎng)絡(luò)協(xié)議,用于在網(wǎng)絡(luò)中共享路由。它是互聯(lián)網(wǎng)的基本組成部分之一,具有出色的擴展特性。

1.7 關(guān)于 Calico 網(wǎng)絡(luò)

Calico CNI 網(wǎng)絡(luò)插件

Calico CNI 網(wǎng)絡(luò)插件使用一對虛擬以太網(wǎng)設(shè)備(veth pair)將 pod 連接到主機網(wǎng)絡(luò)命名空間的 L3 路由。這種 L3 架構(gòu)避免了許多其他 Kubernetes 網(wǎng)絡(luò)解決方案中的額外 L2 橋的不必要的復(fù)雜性和性能開銷。

Calico CNI IPAM 插件

Calico CNI IPAM 插件從一個或多個可配置的 IP 地址范圍內(nèi)為 Pod 分配 IP 地址,并根據(jù)需要為每個節(jié)點動態(tài)分配小塊 IP。結(jié)果是與許多其他 CNI IPAM 插件相比,IP 地址空間使用效率更高,包括用于許多網(wǎng)絡(luò)解決方案的主機本地 IPAM 插件。

覆蓋網(wǎng)絡(luò)模式(Overlay )

Calico 可以提供 VXLAN 或 IP-in-IP 覆蓋網(wǎng)絡(luò),包括僅跨子網(wǎng)(cross-subnet only)模式。

非覆蓋網(wǎng)絡(luò)模式(Non-overlay)

Calico 可以提供在任何底層 L2 網(wǎng)絡(luò)或 L3 網(wǎng)絡(luò)之上運行的非覆蓋網(wǎng)絡(luò),該網(wǎng)絡(luò)既可以是具有適當(dāng)云提供商集成的公共云網(wǎng)絡(luò),也可以是支持 BGP 的網(wǎng)絡(luò)(通常是具有標(biāo)準(zhǔn) Top-of 的本地網(wǎng)絡(luò)-機架路由器)。

Calico 內(nèi)置了對 BGP 的支持。在本地部署中,這允許 Calico 與物理網(wǎng)絡(luò)(通常與架頂式路由器)對等以交換路由,從而形成一個非覆蓋網(wǎng)絡(luò),其中 pod IP 地址可在更廣泛的網(wǎng)絡(luò)中路由,就像附加的任何其他工作負載一樣到網(wǎng)絡(luò)。

網(wǎng)絡(luò)策略執(zhí)行

Calico 的網(wǎng)絡(luò)策略執(zhí)行引擎實現(xiàn)了 Kubernetes 網(wǎng)絡(luò)策略的全部功能,以及 Calico 網(wǎng)絡(luò)策略的擴展功能。這與 Calico 的內(nèi)置網(wǎng)絡(luò)模式或任何其他 Calico 兼容的網(wǎng)絡(luò)插件和云提供商集成結(jié)合使用。

2. Calico 網(wǎng)絡(luò)配置方案

一個比官網(wǎng)講的更系統(tǒng)的介紹:Calico 介紹、原理與使用

如果使用 Calico 官方的本地部署腳本,則部署的技術(shù)結(jié)構(gòu)如下:


Calico on-prem 最常見的網(wǎng)絡(luò)設(shè)置是使用 BGP to peer 與物理網(wǎng)絡(luò)(通常是架頂路由器)的非覆蓋模式,以使 pod IP 可在集群外部路由。(當(dāng)然,如果需要,您可以配置本地網(wǎng)絡(luò)的其余部分以限制集群外部 pod IP 路由的范圍。)此設(shè)置提供了豐富的高級 Calico 功能,包括廣播 Kubernetes 服務(wù) IP 的能力(集群 IP 或外部 IP),以及在 pod、命名空間或節(jié)點級別控制 IP 地址管理的能力,以支持與現(xiàn)有企業(yè)網(wǎng)絡(luò)和安全要求集成的廣泛可能性。

如果無法將 BGP 配對連接到物理網(wǎng)絡(luò),如果集群位于單個 L2 網(wǎng)絡(luò)中,可以在 VXLAN 或 IP-in-IP 覆蓋模式下運行 Calico,并使用跨子網(wǎng)覆蓋模式來優(yōu)化每個 L2 子網(wǎng)內(nèi)的性能。


配置vxlan跨子網(wǎng)的方法

名詞解釋

3. 將服務(wù)暴露到集群外——Ingress 控制器

k8s 可以通過服務(wù)(service)將自己的應(yīng)用程序暴露到集群外,服務(wù)的類型有:

  • ClusterIP:通過集群的內(nèi)部 IP 暴露服務(wù),選擇該值時服務(wù)只能夠在集群內(nèi)部訪問。 這也是默認的 ServiceType

  • [NodePort](https://kubernetes.io/zh-cn/docs/concepts/services-networking/service/#type-nodeport):通過每個節(jié)點上的 IP 和靜態(tài)端口(NodePort)暴露服務(wù)。 NodePort 服務(wù)會路由到自動創(chuàng)建的 ClusterIP 服務(wù)。 通過請求 <節(jié)點 IP>:<節(jié)點端口>,你可以從集群的外部訪問一個 NodePort 服務(wù)。

  • [LoadBalancer](https://kubernetes.io/zh-cn/docs/concepts/services-networking/service/#loadbalancer):使用云提供商的負載均衡器向外部暴露服務(wù)。 外部負載均衡器可以將流量路由到自動創(chuàng)建的 NodePort 服務(wù)和 ClusterIP 服務(wù)上。

  • [ExternalName](https://kubernetes.io/zh-cn/docs/concepts/services-networking/service/#externalname):通過返回 CNAME 和對應(yīng)值,可以將服務(wù)映射到 externalName 字段的內(nèi)容(例如,foo.bar.example.com)。 無需創(chuàng)建任何類型代理。

Ingress 是對集群中服務(wù)的外部訪問進行管理的 API 對象,典型的訪問方式是 HTTP。

k8s 使用 Ingress 方式提供服務(wù),需要額外安裝 Ingress 控制器

以 Ingress-nginx 控制器為例,官方的部署指南提供了多種平臺下的部署方式:

Ingress-nginx 控制器在云環(huán)境部署時,默認的 Service 類型為 LoadBalancer, 在裸機(內(nèi)網(wǎng))環(huán)境中,可以參考 Bare-metal 部署方式(控制器 Service 類型為 NodePort

3.1 關(guān)于 Ingress 的外部訪問

3.1.1 存在的問題

云環(huán)境部署 ingress-nginx 時,默認的訪問方式由云服務(wù)商提供的負載均衡器來負責(zé),從而外部客戶端可以訪問集群中的 NGINX ingress


裸機環(huán)境缺乏負載均衡器,無法給外部用戶同樣的訪問

針對這個問題,官方提供了4種外部訪問方法

3.1.2 使用 NodePort 服務(wù)端口

裸機的 ingress-nginx 默認使用 NodePort 服務(wù)的方式安裝部署

在該配置中,nginx 容器與主機網(wǎng)絡(luò)隔離,因此可以安全的綁定任何端口,包括HTTP的標(biāo)準(zhǔn)端口 80和 443 。然而,由于容器命名空間隔離,集群網(wǎng)絡(luò)外部的客戶端無法直接訪問 ingress主機的80和443端口,相反,外部客戶端必須附加分配給 ingress-nginx 服務(wù)的 NodePort 給 HTTP 請求

例如給 ingress-nginx 服務(wù)分配了 NodePort 30100端口

$ kubectl -n ingress-nginx get svc
NAME                   TYPE        CLUSTER-IP     PORT(S)
ingress-nginx          NodePort    10.0.220.217   80:30100/TCP,443:30101/TCP

k8s node 的外部IP地址是203.0.113.2

$ kubectl get node
NAME     STATUS   ROLES    EXTERNAL-IP
host-1   Ready    master   203.0.113.1
host-2   Ready    node     203.0.113.2
host-3   Ready    node     203.0.113.3

客戶端需要用 host: myapp.example.com 訪問一個 Ingress ,需要訪問 http://myapp.example.com:30100,這里 myapp.example.com 子域名解析為 203.0.113.2

3.1.2 使用主機網(wǎng)絡(luò)

當(dāng)沒有外部負載均衡器,使用NodePorts 也不是一個好的選項時,可以通過配置 ingress-nginx Pods 使用其宿主機網(wǎng)絡(luò),而不是專用網(wǎng)絡(luò)命名空間。這種方法的優(yōu)點是 NGINX Ingress 控制器可以直接綁定 80端口和443端口到 k8s 節(jié)點的網(wǎng)絡(luò)接口,不需要由 NodePort 服務(wù)提供的額外的網(wǎng)絡(luò)轉(zhuǎn)換

這種方法不利用任何服務(wù)對象來暴露 NGINX Ingress 控制器,如果 ingress-nginx 服務(wù)存在于目標(biāo)集群,推薦刪除它

通過配置 Pod 的 spec 選項,可以實現(xiàn)

template:
  spec:
    hostNetwork: true

安全考慮:使用這個方法將會暴露每個系統(tǒng)守護進程給 NGINX Ingress 控制器到任何網(wǎng)絡(luò)接口,包括主機的 loopback。使用這個方法需要小心的評估這給系統(tǒng)帶來的安全影響

例:NGINX Pod 繼承主機的IP地址,而不是Pod內(nèi)部IP

$ kubectl -n ingress-nginx get pod -o wide
NAME                                       READY   STATUS    IP            NODE
default-http-backend-7c5bc89cc9-p86md      1/1     Running   172.17.1.1    host-2
ingress-nginx-controller-5b4cf5fc6-7lg6c   1/1     Running   203.0.113.3   host-3
ingress-nginx-controller-5b4cf5fc6-lzrls   1/1     Running   203.0.113.2   host-2

這種部署方法有一個限制,就是每個集群節(jié)點上只能部署一個 NGINX Ingress 控制器 Pod,因為在同一個網(wǎng)絡(luò)接口上多次綁定同一個端口在技術(shù)上是不可能的,確保僅創(chuàng)建可調(diào)度 Pod 的一種方法是將 NGINX Ingress 控制器部署為DaemonSet而不是傳統(tǒng)的 Deployment。

DaemonSet 為每個集群節(jié)點(包括主節(jié)點)準(zhǔn)確調(diào)度一種 Pod,除非節(jié)點配置為排斥這些Pod 。有關(guān)更多信息,請參閱DaemonSet。

跟 NodePorts 方法一樣,這種方法有幾個奇怪的點需要注意:

  • DNS 解析:配置了 hostNetwork: true的Pod 不使用內(nèi)部 DNS 解析器(如 kube-dns 或 CoreDNS),除非其 dnsPolicy spec 字段設(shè)置為 [ClusterFirstWithHostNet](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/#pod-s-dns-policy)。如果希望 NGINX 解析內(nèi)部名字的話,需要使用這個設(shè)置

  • Ingress 狀態(tài):由于使用主機網(wǎng)絡(luò)的配置中,沒有服務(wù)暴露 NGINX Ingress controller ,在標(biāo)準(zhǔn)云設(shè)置中默認的 --publish-service標(biāo)志將不會應(yīng)用,并且所有的 Ingress 對象的狀態(tài)會保持空

    $ kubectl get ingress
    NAME           HOSTS               ADDRESS   PORTS
    test-ingress   myapp.example.com             80
    

    并且由于裸機節(jié)點通常沒有 ExternalIP,節(jié)點需要設(shè)置 [--report-node-internal-ip-address](https://kubernetes.github.io/ingress-nginx/user-guide/cli-arguments/) 標(biāo)志,這會設(shè)置所有 Ingress 對象的狀態(tài)地址為所有運行 NGINX Ingress controller 的節(jié)點IP地址

    $ kubectl -n ingress-nginx get pod -o wide
    NAME                                       READY   STATUS    IP            NODE
    default-http-backend-7c5bc89cc9-p86md      1/1     Running   172.17.1.1    host-2
    ingress-nginx-controller-5b4cf5fc6-7lg6c   1/1     Running   203.0.113.3   host-3
    ingress-nginx-controller-5b4cf5fc6-lzrls   1/1     Running   203.0.113.2   host-2
    $ kubectl get ingress -o wide
    NAME           HOSTS               ADDRESS                   PORTS
    test-ingress   myapp.example.com   203.0.113.2,203.0.113.3   80
    

3.1.4 使用自配置 edge

與云環(huán)境類似,這種方法需要一個邊界網(wǎng)絡(luò)組件(網(wǎng)關(guān)),給 k8s 集群提供公共進入點(entrypoint)。該邊界組件可以是物理的(運營商實現(xiàn))或軟件實現(xiàn)(例如 HAproxy),并且由運營團隊在 k8s 之外管理。

這種方法與 NodePort 服務(wù)方式的重要區(qū)別就是:外部客戶端不直接訪問集群節(jié)點,只有邊界組件訪問。這種方式適合私有 k8s 集群,其中的節(jié)點都沒有公共ip 地址。

在邊界端,需要預(yù)先準(zhǔn)備一個公共地址,用于轉(zhuǎn)發(fā)所有的 HTTP 流量到 k8s 節(jié)點或 master。TCP 80端口和443端口進入的流量轉(zhuǎn)發(fā)到目標(biāo)節(jié)點的相關(guān)的 HTTP 和 HTTPS NodePort ,圖示如下:

[圖片上傳失敗...(image-9e94ca-1668345670017)]

3.1.5 使用 External IP

不建議:這種方法不允許任何方式保留 HTTP 請求的源IP地址,因此盡管簡單,但不建議使用這種方法

externalIPs 選項讓 kube-proxy將發(fā)送到任意IP地址和服務(wù)端口的流量路由到該服務(wù)的端點,這些IP地址必須屬于目標(biāo)節(jié)點

例:

$ kubectl get node
NAME     STATUS   ROLES    EXTERNAL-IP
host-1   Ready    master   203.0.113.1
host-2   Ready    node     203.0.113.2
host-3   Ready    node     203.0.113.3
$ kubectl -n ingress-nginx get svc
NAME                   TYPE        CLUSTER-IP     PORT(S)
ingress-nginx          NodePort    10.0.220.217   80:30100/TCP,443:30101/TCP

配置該服務(wù)的 spec, NodePort 和 服務(wù) port 都可訪問 NGINX

$ kubectl edit svc ingress-nginx-controller -n ingress-nginx
spec:
  externalIPs:
  - 203.0.113.2
  - 203.0.113.3
  
$ curl -D- http://myapp.example.com:30100
HTTP/1.1 200 OK
Server: nginx/1.15.2
$ curl -D- http://myapp.example.com
HTTP/1.1 200 OK
Server: nginx/1.15.2
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容