- 一、為什麼需要 Service
- 二、Kubernetes 中的服務發現與負載均衡 -- Service
- 三、用例解讀
- 1、Service 語法
- 2、建立和檢視 Service
- 四、Headless Service
- 五、叢集內訪問 Service
- 六、向叢集外暴露 Service
- 七、操作示例
- 1、獲取叢集狀態資訊
- 2、建立 Service、Deployment
- 3、建立客戶端的測試 Pod
- 4、叢集內訪問 Service 的三種方式
- 4.1、直接透過 Service 的 clusterIP 訪問
- 4.2、直接訪問 Service 名
- 4.3、透過環境變數訪問
- 5、叢集外部訪問服務
- 5.1、NodePort
- 5.1.1、建立 NodePort 型別的 Service(NodePort的埠範圍是 30000-32767)
- 5.1.2、建立 Deployment 模擬後端一組應用 Pod
- 5.1.3、建立並檢視
- 5.1.4、透過節點 IP:port 訪問
- 5.1.5、透過nodename 也可以訪問
- 5.2、LoadBalancer
- 5.2.1、安裝METALLB
- 5.2.2、檢視MetalLB的安裝方式:Installation by manifest
- 5.2.3、建立 MetalLB 的名稱空間
- 5.2.4、下載 MetalLB 的安裝檔案
- 5.2.5、檢視 MetalLB 需要的映象
- 5.2.6、修改 metallb.yaml 檔案
- 5.2.7、worker節點提前下載speaker和controller映象
- 5.2.8、安裝 MetalLB
- 5.2.9、檢視 Pod 驗證安裝情況
- 5.2.10、配置地址池
- 5.2.11、建立地址池
- 5.2.12、建立 LoadBalancer 型別的 SVC
- 5.2.13、透過 svc 的 EXTERNAL-IP 訪問叢集內部的服務
- 5.3、Ingress
- 5.4、HostNetwork
- 5.4.1、給 node 節點新增 role 標籤
- 5.4.2、建立使用 hostnetwork 的 Deployment
- 5.4.3、透過節點 ip 訪問
- 5.5、HostPort
- 5.5.1、給 node 節點新增 role 標籤
- 5.5.2、建立使用 hostport 的deployment
- 5.5.3、透過標籤節點 ip + port / pod ip 訪問
- 5.6、ExternalName
- 5.6.1、建立 ExternalName 型別的 Service
- 5.6.2、啟動臨時 pod 測試 DNS 解析
- 5.6.3、域名解析
- 5.1、NodePort
- 八、架構設計
- 1、Kubernetes 服務發現架構
- 1.1、元件
- 1.2、實際訪問鏈路
- 1、Kubernetes 服務發現架構
一、為什麼需要 Service
在 K8s 叢集裡面會透過 pod 去部署應用,與傳統的應用部署不同,傳統應用部署在給定的機器上面去部署,我們知道怎麼去呼叫別的機器的 IP 地址;但是在 K8s 叢集裡面應用是透過 pod 去部署的, 而 pod 生命週期是短暫的。在 pod 的生命週期過程中,比如它建立或銷燬,它的 IP 地址都會發生變化,這樣就不能使用傳統的部署方式,不能指定 IP 去訪問指定的應用。
另外在 K8s 的應用部署裡,之前雖然學習了 deployment 的應用部署模式,但還是需要建立一個 pod 組,這些 pod 組需要提供一個統一的訪問入口,以及怎麼去控制流量負載均衡到這個組裡面。
比如說測試環境、預發環境和線上環境,其實在部署的過程中需要保持同樣的一個部署模板以及訪問方式。因為這樣就可以用同一套應用的模板在不同的環境中直接釋出。
二、Kubernetes 中的服務發現與負載均衡 -- Service
最後應用服務需要暴露到外部去訪問,需要提供給外部的使用者去呼叫的。我們知道 pod 的網路跟機器不是同一個段的網路,那怎麼讓 pod 網路暴露到去給外部訪問呢?這時就需要服務發現。
在 K8s 裡面,服務發現與負載均衡就是 K8s Service。
上圖就是在 K8s 裡 Service 的架構,K8s Service 向上提供了外部網路以及 pod 網路的訪問,即外部網路可以透過 service 去訪問,pod 網路也可以透過 K8s Service 去訪問。
向下,K8s 對接了另外一組 pod,可以透過 K8s Service 的方式去負載均衡到一組 pod 上面去,這樣相當於解決了前面所說的複發性問題,或者提供了統一的訪問入口去做服務發現,然後又可以給外部網路訪問,解決不同的 pod 之間的訪問,提供統一的訪問地址。
三、用例解讀
1、Service 語法
cat >> my-service.yaml << EOF
apiVersion: v1
kind: Service
metadata:
name: my-service
labels:
app: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
EOF
定義了用於 K8s Service 服務發現的一個協議以及埠。宣告瞭一個名叫 my-service 的一個 K8s Service,它有一個 app:my-service 的 label,它選擇了 app:MyApp 這樣一個 label 的 pod 作為它的後端。
最後是定義的服務發現的協議以及埠,我們定義的是 TCP 協議,埠是 80,目的埠是 9376,效果是訪問到這個 service 80 埠會被路由到後端的 targetPort,就是隻要訪問到這個 service 80 埠的都會負載均衡到後端 app:MyApp 這種 label 的 pod 的 9376 埠。
2、建立和檢視 Service
kubectl apply -f my-service.yaml
kubectl describe svc my-service
service 建立好之後,可以看到它的名字是 my-service。Namespace、Label、Selector 這些都跟我們之前宣告的一樣,這裡宣告完之後會生成一個 IP 地址,這個 IP 地址就是 service 的 IP 地址,它在叢集裡面可以被其它 pod 所訪問,相當於透過這個 IP 地址提供了統一的一個 pod 的訪問入口,以及服務發現。
這裡還有一個 Endpoints 的屬性,就是我們透過 Endpoints 可以看到:透過前面所宣告的 selector 去選擇了哪些 pod?以及這些 pod 都是什麼樣一個狀態?比如說透過 selector,我們看到它選擇了這些 pod 的一個 IP,以及這些 pod 所宣告的 targetPort 的一個埠。
在 service 建立之後,它會在叢集裡面建立一個虛擬的 IP 地址以及埠,在叢集裡,所有的 pod 和 node 都可以透過這樣一個 IP 地址和埠去訪問到這個 service。這個 service 會把它選擇的 pod 及其 IP 地址都掛載到後端,這樣透過 service 的 IP 地址訪問時,就可以負載均衡到後端這些 pod 上面去。
當 pod 的生命週期有變化時,比如說其中一個 pod 銷燬,service 就會自動從後端摘除這個 pod。這樣實現了:就算 pod 的生命週期有變化,它訪問的端點是不會發生變化的。
四、Headless Service
service 建立的時候可以指定 clusterIP:None,告訴 K8s 說我不需要 clusterIP(就是剛才所說的叢集裡面的一個虛擬 IP),然後 K8s 就不會分配給這個 service 一個虛擬 IP 地址,它沒有虛擬 IP 地址怎麼做到負載均衡以及統一的訪問入口呢?
它是這樣來操作的:pod 可以直接透過 service_name 用 DNS 的方式解析到所有後端 pod 的 IP 地址,透過 DNS 的 A 記錄的方式會解析到所有後端的 Pod 的地址,由客戶端選擇一個後端的 IP 地址,這個 A 記錄會隨著 pod 的生命週期變化,返回的 A 記錄列表也發生變化,這樣就要求客戶端應用要從 A 記錄把所有 DNS 返回到 A 記錄的列表裡面 IP 地址中,客戶端自己去選擇一個合適的地址去訪問 pod。
apiVersion: v1
kind: Service
metadata:
name: my-service
labels:
app: my-service
spec:
clusterIP: None
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
可以從看到跟剛才我們宣告的模板的區別,就是在spec下加了一個 clusterIP:None,即表明不需要虛擬 IP。
Headless Service 實際效果就是叢集的 pod 訪問 my-service 時,會直接解析到所有的 service 對應 pod 的 IP 地址,返回給 pod,然後 pod 裡面自己去選擇一個 IP 地址去直接訪問。
五、叢集內訪問 Service
在叢集裡面,其他 pod 要怎麼訪問到我們所建立的這個 service 呢?
有三種方式:
- 首先我們可以透過 service 的虛擬 IP 去訪問,比如說剛建立的 my-service 這個服務,透過 kubectl get svc 或者 kubectl discribe service 都可以看到它的虛擬 IP 地址是 10.96.47.23,埠是 80,然後就可以透過這個虛擬 IP 及埠在 pod 裡面直接訪問到這個 service 的地址;
- 第二種方式直接訪問服務名,依靠 DNS 解析,就是同一個 namespace 裡 pod 可以直接透過 service 的名字去訪問到剛才所宣告的這個 service。不同的 namespace 裡面,我們可以透過 service 名字加“.”,然後加 service 所在的哪個 namespace 去訪問這個 service,例如我們直接用 curl 去訪問,就是 my-service:80 就可以訪問到這個 service;
- 第三種是透過環境變數訪問,在同一個 namespace 裡的 pod 啟動時,K8s 會把 service 的一些 IP 地址、埠,以及一些簡單的配置,透過環境變數的方式放到 K8s 的 pod 裡面。在 K8s pod 的容器啟動之後,透過讀取系統的環境變數比讀取到 namespace 裡面其他 service 配置的一個地址,或者是它的埠號等等。
比如在叢集的某一個 pod 裡面,可以直接透過 curl $ 取到一個環境變數的值,比如取到 MY_SERVICE_SERVICE_HOST 就是它的一個 IP 地址,MY_SERVICE 就是剛才我們宣告的 my-service,SERVICE_PORT 就是它的埠號,這樣也可以請求到叢集裡面的 MY_SERVICE 這個 service。
kubectl get pods -l app=MyApp
kubectl exec -it my-deployment-6866788946-8v9m6 /bin/bash
echo $MY_SERVICE_SERVICE_HOST
echo $MY_SERVICE_SERVICE_PORT
六、向叢集外暴露 Service
前面介紹的都是在叢集裡面 node 或者 pod 去訪問 service,service 怎麼去向外暴露呢?怎麼把應用實際暴露給公網去訪問呢?
NodePort:這種方法會在叢集的所有節點上開放一個埠(稱為 NodePort),外部可以透過任意節點的 IP 地址加上這個埠號來訪問服務。NodePort 的埠範圍預設是 30000-32767。例如,如果你有一個名為 my-service 的服務,Kubernetes 可能會隨機分配一個埠,比如 30001,那麼你可以透過
LoadBalancer:在支援外部負載均衡器的雲服務提供商(如 AWS、Azure、GCP 等)上,你可以建立一個 LoadBalancer 型別的服務。這將自動建立一個外部負載均衡器,並將外部流量轉發到服務。LoadBalancer 型別的服務會在雲提供商的負載均衡器上配置一個公共 IP 地址,你可以透過這個 IP 地址訪問服務 。
ExternalName:這種方式透過 CNAME 記錄將服務對映到一個外部域名。這意味著當請求傳送到 Kubernetes 叢集時,DNS 服務會返回一個 CNAME 記錄,指向你指定的外部域名。這種方法不涉及流量的轉發,而是在 DNS 層面上進行重定向 。
External IP:為服務分配一個或多個外部可訪問的 IP 地址。這些 IP 地址通常由雲服務提供商管理,可以是靜態或動態分配。透過 Service 的 externalIPs 欄位指定外部 IP 地址,外部流量可以透過指定的 IP 地址訪問 Service。
Ingress:Ingress 是 Kubernetes 的一種 API 物件,它管理外部訪問到叢集內服務的 HTTP 流量。透過定義 Ingress 規則,你可以控制如何將外部請求路由到叢集內的服務。Ingress 通常與 Ingress Controller 一起使用,後者負責實現 Ingress 規則並將流量轉發到正確的服務 。
HostPort:在 Pod 級別使用,將 Pod 內的埠對映到宿主機的特定埠。這種方式不是透過 Service 資源實現的,而是在 Pod 定義中使用 hostPort 欄位。
HostNetwork:在 Pod 級別使用,允許 Pod 直接使用宿主機的網路名稱空間。這意味著 Pod 會繞過 Kubernetes 的網路代理,直接在宿主機上監聽網路請求。這種方式不是透過 Service 資源實現的,而是在 Pod 定義中設定 hostNetwork: true。
七、操作示例
1、獲取叢集狀態資訊
kubectl get cs
2、建立 Service、Deployment
cat >> service.yaml << EOF
apiVersion: v1
kind: Service
metadata:
name: nginx-test
labels:
run: nginx
spec:
selector:
run: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
EOF
cat >> server.yaml << EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-test
labels:
run: nginx
spec:
replicas: 2
selector:
matchLabels:
run: nginx
template:
metadata:
labels:
run: nginx
spec:
containers:
- name: nginx
image: nginx:1.16.0
imagePullPolicy: IfNotPresent
EOF
kubectl apply -f service.yaml -f server.yaml
kubectl get pods -o wide -l run=nginx
kubectl describe svc nginx-test
3、建立客戶端的測試 Pod
現在去建立一個客戶端的 pod 實際去感受一下如何去訪問這個 K8s Service
cat >> client-test.yaml << EOF
apiVersion: v1
kind: Pod
metadata:
name: test-client
spec:
containers:
- name: client-test
image: busybox:1.31.0
command:
- sleep
- "3600"
EOF
4、叢集內訪問 Service 的三種方式
4.1、直接透過 Service 的 clusterIP 訪問
kubectl exec -it test-client /bin/sh
wget -qO- 10.96.252.19
4.2、直接訪問 Service 名
wget -qO- nginx-test
不同名稱空間時也可以透過
4.3、透過環境變數訪問
透過執行 env 命令看一下它實際注入的環境變數的情況。看一下 nginx-test 的 service 的各種配置已經註冊進來了。
env
wget -qO- $NGINX_TEST_SERVICE_HOST
5、叢集外部訪問服務
5.1、NodePort
NodePort
型別的 Service
提供了一種將叢集內部的服務暴露給外部客戶端訪問的方式。透過建立一個型別為 NodePort
的 Service
,Kubernetes 控制器會在每個執行中的節點上開啟一個固定的埠(預設範圍是30000-32767,但可以根據需要進行配置)。外部流量可以透過這個節點埠訪問到叢集內的服務。
5.1.1、建立 NodePort 型別的 Service(NodePort的埠範圍是 30000-32767)
cat >> nodeport-svc.yaml << EOF
apiVersion: v1
kind: Service
metadata:
name: nodeport-service
spec:
type: NodePort
ports:
- port: 8080
targetPort: 80
nodePort: 30120
selector:
app: nginx
EOF
5.1.2、建立 Deployment 模擬後端一組應用 Pod
cat >> nodeport-deploy.yaml << EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: nodeport-deploy
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.16.0
ports:
- containerPort: 80
EOF
5.1.3、建立並檢視
kubectl apply -f nodeport-deploy.yaml -f nodeport-svc.yaml
kubectl get pods -l app=nginx
kubectl get svc
kubectl describe svc nodeport-service
5.1.4、透過節點 IP:port 訪問
curl 192.168.112.10:30120
5.1.5、透過nodename 也可以訪問
5.2、LoadBalancer
當建立一個 LoadBalancer
型別的服務時,Kubernetes 會嘗試透過雲提供商或第三方負載均衡解決方案來建立一個負載均衡器。這個負載均衡器會分配一個靜態的外部IP地址(或 DNS 名稱),並會將外部流量路由到叢集內的服務。
5.2.1、安裝METALLB
使用LoadBalancer
的方式進行服務釋出,需要藉助第三方的工具(METALLB)。
每個svc都有一個私有地址,只能在叢集內部訪問,如果我們把svc的型別設定為LoadBalancer
,則svc會獲取到一個外部IP,這個外部IP來自地址池,示例使用METALLB配置地址池。
METALLB官網
5.2.2、檢視MetalLB的安裝方式:Installation by manifest
5.2.3、建立 MetalLB 的名稱空間
kubectl create ns metallb-system
5.2.4、下載 MetalLB 的安裝檔案
wget https://raw.githubusercontent.com/metallb/metallb/v0.11.0/manifests/metallb.yaml
wget https://raw.githubusercontent.com/metallb/metallb/v0.11.0/manifests/namespace.yaml
5.2.5、檢視 MetalLB 需要的映象
grep image metallb.yaml
5.2.6、修改 metallb.yaml 檔案
image同級下新增如下欄位
imagePullPolicy: IfNotPresent
5.2.7、worker節點提前下載speaker和controller映象
所有節點都執行拉取操作
docker pull quay.io/metallb/speaker:v0.11.0
docker pull quay.io/metallb/controller:v0.11.0
5.2.8、安裝 MetalLB
kubectl apply -f namespace.yaml -f metallb.yaml
5.2.9、檢視 Pod 驗證安裝情況
kubectl get pods -n metallb-system
5.2.10、配置地址池
cat >> IPAddressPool.yaml << EOF
apiVersion: v1
kind: ConfigMap
metadata:
namespace: metallb-system
name: config
data:
config: |
address-pools:
- name: default
protocol: layer2
addresses:
- 192.168.112.100-192.168.112.200
EOF
5.2.11、建立地址池
kubectl apply -f IPAddressPool.yaml
5.2.12、建立 LoadBalancer 型別的 SVC
cat << EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: podtest
labels:
app: podtest
spec:
containers:
- name: nginx
image: nginx:1.16.0
ports:
- containerPort: 80
EOF
kubectl expose pod podtest --name=loadbalancer-svc --port=80 --target-port=80 --type=LoadBalancer --selector=app=podtest
檢視svc,EXTERNAL-IP地址是從地址池裡分配的(預設為首個可分配的ip地址)
5.2.13、透過 svc 的 EXTERNAL-IP 訪問叢集內部的服務
瀏覽器訪問
192.168.112.100
curl 192.168.112.100
5.3、Ingress
Ingress
是 Kubernetes 中另一種將叢集內部的服務暴露給外部的方式。不同於 Service
型別(如 NodePort
和 LoadBalancer
),Ingress
提供了一個更高階別的抽象,允許管理員定義更加複雜的路由規則,以便於管理和擴充套件HTTP和HTTPS服務。
TODO
下一篇單獨講講吧
5.4、HostNetwork
hostNetwork
是 Kubernetes 中的一個特性選項,但它並不是直接用於將叢集內部服務暴露給外部訪問的方式,而是指在建立 Pod 時是否使用宿主機的網路棧來進行網路通訊。當在 Pod 的規格中設定了 hostNetwork: true
時,Pod 將直接使用宿主機的網路介面而不是 Kubernetes 的服務網路。
5.4.1、給 node 節點新增 role 標籤
kubectl label nodes k8s-node1 role=node1
kubectl get nodes -L role
5.4.2、建立使用 hostnetwork 的 Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
nodeSelector:
role: node1
hostNetwork: true
containers:
- image: nginx:1.16.0
imagePullPolicy: IfNotPresent
name: nginx
ports:
- containerPort: 8080
5.4.3、透過節點 ip 訪問
在和containers 同級的 hostNetwork: true,表示pod使用宿主機網路,配合 nodeSelector,把pod例項化在固定節點,如上,給node1節點加上標籤role: node1 , 透過nodeSelector,nginx就會例項化在node1節點,這樣就可以透過node1節點的ip就可以訪問這個nginx了。
5.5、HostPort
在 Kubernetes 中,hostPort
是一種配置 Pod 的方式,使得 Pod 內部的應用可以透過特定的埠監聽宿主機的網路介面。當 Pod 的容器配置了 hostPort
,它將能夠接收來自宿主機對應埠的流量。這種方式可以實現外部服務訪問叢集內部服務的需求,但需要注意的是,使用 hostPort
需要注意埠衝突及安全性問題。
5.5.1、給 node 節點新增 role 標籤
kubectl label k8s-node2 role=node2
kubectl get nodes -L role
5.5.2、建立使用 hostport 的deployment
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: hostport-deploy
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
nodeSelector:
role: node2
containers:
- image: nginx:1.16.0
imagePullPolicy: IfNotPresent
name: nginx
ports:
- containerPort: 8080
hostPort: 80
5.5.3、透過標籤節點 ip + port / pod ip 訪問
和hostNetwork相比多了對映能力,可以把容器埠對映為node節點不同埠,hostPort,當然也需要nodeSelector來固定節點,不然每次建立,節點不同,ip也會改變
5.6、ExternalName
ExternalName
型別的 Service
是 Kubernetes 中用於提供從叢集內部訪問外部 DNS 名稱的一種方式。它的主要目的是簡化叢集內部應用訪問外部服務的過程。當你建立一個型別為 ExternalName
的 Service
時,Kubernetes 會為這個 Service
建立一個 DNS 條目,該條目將解析為指定的外部 DNS 名稱。
與 NodePort
或 LoadBalancer
型別的 Service
不同,ExternalName
型別的 Service
不會暴露任何叢集內部的服務到外部網路,而是相反,它讓叢集內部的服務可以訪問外部的服務。
5.6.1、建立 ExternalName 型別的 Service
cat << EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
name: service-externalname
labels:
type: externalname
spec:
type: ExternalName
externalName: www.baidu.com
EOF
kubectl get svc -l type=externalname
5.6.2、啟動臨時 pod 測試 DNS 解析
可以看到叢集內部是可以訪問外部服務www.baidu.com
kubectl run -it --rm --image=alpine:latest dns-test -- sh
5.6.3、域名解析
- 檢視 kube-dns 的 ip 地址
kubectl get svc kube-dns -n kube-system -o custom-columns='ClusterIP:.spec.clusterIP'
- 安裝 dig 命令
yum provides dig
yum install -y bind-utils-9.11.4-26.P2.el7_9.16.x86_64
- 從叢集內部解析
ExternalName
型別的Service
dig @172.16.0.10 service-externalname.default.svc.cluster.local
八、架構設計
1、Kubernetes 服務發現架構
如上圖所示,K8s 服務發現以及 K8s Service 是這樣整體的一個架構。
K8s 分為 master 節點和 worker 節點:
- master 裡面主要是 K8s 管控的內容;
- worker 節點裡面是實際跑使用者應用的一個地方。
在 K8s master 節點裡面有 APIServer,就是統一管理 K8s 所有物件的地方,所有的元件都會註冊到 APIServer 上面去監聽這個物件的變化,比如說我們剛才的元件 pod 生命週期發生變化這些事件。
1.1、元件
這裡面最關鍵的有三個元件:
-
一個是 Cloud Controller Manager,負責去配置 LoadBalancer 的一個負載均衡器給外部去訪問;
-
另外一個就是 Coredns,透過 Coredns 去觀測 APIServer 裡面的 service 後端 pod 的一個變化,去配置 service 的 DNS 解析,實現可以透過 service 的名字直接訪問到 service 的虛擬 IP,或者是 Headless 型別的 Service 中的 IP 列表的解析;
-
在每個 node 裡面會有 kube-proxy 這個元件,它透過監聽 service 以及 pod 變化,然後實際去配置叢集裡面的 node pod 或者是虛擬 IP 地址的一個訪問。
1.2、實際訪問鏈路
比如說從叢集內部的一個 Client Pod3 去訪問 Service:
Client Pod3 首先透過 Coredns 這裡去解析出 ServiceIP,Coredns 會返回給它 ServiceName 所對應的 service IP 是什麼,這個 Client Pod3 就會拿這個 Service IP 去做請求,它的請求到宿主機的網路之後,就會被 kube-proxy 所配置的 iptables 或者 IPVS 去做一層攔截處理,之後去負載均衡到每一個實際的後端 pod 上面去,這樣就實現了一個負載均衡以及服務發現。
對於外部的流量,比如說剛才透過公網訪問的一個請求。它是透過外部的一個負載均衡器 Cloud Controller Manager 去監聽 service 的變化之後,去配置的一個負載均衡器,然後轉發到節點上的一個 NodePort 上面去,NodePort 也會經過 kube-proxy 配置的一個 iptables,把 NodePort 的流量轉換成 ClusterIP,緊接著轉換成後端的一個 pod 的 IP 地址,去做負載均衡以及服務發現。