Skip to main content

Kubernetes系列文 - Ingress抽象元件與Networks介紹 (四)

在這篇文章中我們會聊到

  • Ingress 基本介紹
  • Kubernetes Network 原理

Ingress 基本介紹

上一篇我們介紹了三種常用的 Service,其中也包含了可以讓外部流量流進 Cluster 內部的 NodePort 與 LoadBalancer,我們可以想像一下無論是 LoadBalancer 還是 NodePort 都會面臨到一個問題是當 Service 越來越多的時候,Service 曝露出來的 Port 就會越來越多,我們也就需要針對每個 Service 的 Port 進行管理。可想而知我們需要一個元件來替我們解決這個複雜的問題。

我們來複習一下 Service 的架構圖。

Service

從圖中可以看出當 Service 越來越多的時候,我們就必須要管理 Port 的對應關係,這些 Port 的對應關係也都四散在各個 yaml 檔案內,而且 service entrypoint 也非常多。

危險發言

除了內部的 microservice 以外,外部的 HTTP API 我真的沒有看過有人會打 example.com:30001/api/users

接著我們來看一下 Ingress 的架構圖。

Ingress

Ingress 的目的其實非常簡單,從圖中可以看得出來 Node 只需要一個統一的 Port 入口,就可以將流量傳遞到 Ingress 上,接著再根據 Url 的 Path 將流量傳遞到正確的 Service 上,直接解決掉了透過 Port 再決定要傳到哪個 Service 的問題。另外我覺得也可以直接把 Ingress 想像成是一台 nginx 在做 reverse-proxy,這樣理解上就會變得非常簡單。

這邊提供一個 Ingress 的 yaml 檔案

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-exmaple
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- host: example.com
http:
paths:
- path: /users/?(.*)
backend:
serviceName: users-server
servicePort: 80
- path: /auth/?(.*)
backend:
serviceName: auth-server
servicePort: 80
- path: /v2/users?(.*)
backend:
serviceName: users-v2-server
servicePort: 80
Ingress-Controller

如果使用原生的 Kubernetes 的話需要自行安裝 Ingress Controller,簡單來說就是 Ingress 的 Implementation,最常見的就是ingress-nginx。如果是使用 EKS 或 GKE 的話都已經內建安裝好 Ingress Controller 了。

Kubernetes Network 原理

從上一篇到這篇都在討論 Kubernetes 網路怎麼運行,實際上為了理解方便我們省略掉了很多底層的機制,是時候來討論一下 Node 內部與 Node 間的網路底層是如何運作的。

Pod 內部通訊

NetworkingInPod

我們在前幾篇有提到 Pod 內部是共用同一個 Linux Network Namespace,所以在網路資源共通的情況下,我們是可以直接透過 localhost 加上 Port 的形式直接進行溝通,這些流量並不會流出去 Pod 以外的地方。

Node 內部通訊

我們先解釋幾個名詞

  • veth (Virtual Ethernet): 我們已經知道 Linux Network Namespace 可以把 Container 中的網路環境阻隔開來,但網路環境分開後又會面臨到無法直接通訊的問題,所以 Linux 就提供了 veth 讓兩個不同 namespace 的環境可以直接通訊。在 Kubernetes 中 veth 常用於 Node 與 Pod 之間的網路溝通。
  • bridge: Linux bridge 是一個虛擬的網路橋接器,主要目的是讓不同網段的網路能夠直接通訊(例如 10.40.0.2 與 10.40.0.3)。cbr (custom bridge)是 Kubernetes 建立出來的 bridge。

NetworkingInNode

假設 ContainerB 要與 ContainerC 溝通

  • 流量從 ContainerB 透過 veth0 轉到 Node 上 (這邊的 ContainerB 與 Node 的 Network Namespace 不同,所以需要透過 veth0 進行溝通)
  • 接著流量會被傳遞到 cbr0 中
  • cbr0 會發現 10.40.0.3 是在同一個 subnetwork 底下,接著 cbr0 會將流量傳遞到 veth1
  • veth1 再將流量傳遞到 ContainerC 的 Network Namespace 中

透過這些步驟,我們可以發現 Node 內的 Pod 之間在進行網路通訊時,流量是不會流出去 Node 外的。

Node 間通訊 (Route Table)

接著我們要走出 Node 外的世界了,我們來解釋新名詞

  • eth (Ethernet): 實體的網路接口,Node 是一台實體的機器,所有進出 Node 的流量都會通過這個 eth 來完成。
  • Route Table: Route Table 實際上是長在 Router 上的一張表,該表紀錄著要前往某 IP 的話你的下一站是誰,流量只要 Router 根據 route table 規則轉發的話就會到達目的地。

NetworkingBetweenNodes

假設 ContainerB 要與不同 Node 上的 ContainerC 溝通

  • 流量從 ContainerB 透過 NodeA veth0 轉到 NodeA 上
  • 接著流量會被傳遞到 NodeA cbr0 中
  • NodeA cbr0 會發現 10.40.2.2 不是在同一個 subnetwork 底下,接著會將流量傳遞到 NodeA eth0
  • 接著流量會根據 route table 的規則送到目標 NodeB 的 eth0
  • 接著流量會被傳遞到 NodeB cbr0 上
  • NodeB cbr0 在將流量傳遞到 NodeB veth0 上
  • NodeB veth0 再將流量傳遞到 ContainerC 的 Network Namespace 中
My Tip

這邊講的是 Node 之間的通訊,但如果流量是從 ContainerB 送到外部網路其實也是一樣的原理,只是 Route Table 的 next hop 是指到外部的 Router 而已。

結論

這篇主要延續上一篇的 Service,並介紹了更常與 Service 搭配使用的 Ingress,到目前為止 Kubernetes 網路相關的介紹應該已經告一段落了。基本上所有的流量包含內部通訊與外部通訊都介紹了一輪,再 Ingress 的加入後,API 的 Entrypoint 也會更符合真正產品的樣子。另外 Route Table 模式只是 Node 間通訊的其中一種方式,其他通訊方式還有包含 Flannel 和 Weave 等,之後進階篇我們再來一一介紹。