Blog:部落格園 個人
參考:Service | Kubernetes、《Kubernetes進階實戰》
有了 Workload,我們可以方便地管理多例項的應用,但是要想能夠方便地訪問應用,我們還需要一個類似於 負載均衡
的資源來分發請求,在 kubernetes 中,有兩個資源負責這個功能,分別是 Service 以及 Ingress。其中 Service 主要負責叢集內部的訪問,而 Ingress 主要負責來自叢集外部的訪問。
Kubernetes Service從邏輯上代表了一組Pod(通常稱為微服務),具體是哪些Pod則是由label來挑選的(selector)。Service有自己的IP,而且這個IP是不變的。客戶端只需要訪問Service的IP,Kubernetes則負責建立和維護Service與Pod的對映關係。無論後端Pod如何變化,對客戶端不會有任何影響,因為Service沒有變。
舉個例子,考慮一個圖片處理後端,它執行了 3 個副本。這些副本是可互換的 —— 前端不需要關心它們呼叫了哪個後端副本。 然而組成這一組後端程式的 Pod 實際上可能會發生變化, 前端客戶端不應該也沒必要知道,而且也不需要跟蹤這一組後端的狀態。
Service 定義的抽象能夠解耦這種關聯。
Service型別
Service有4種型別:
- ClusterIP:通過叢集的內部 IP 暴露服務,選擇該值時服務只能夠在叢集內部訪問。 這也是預設的
ServiceType
。 - NodePort:通過每個節點上的 IP 和靜態埠(
NodePort
)暴露服務。NodePort
服務會路由到自動建立的ClusterIP
服務。 通過請求<節點 IP>:<節點埠>
,你可以從叢集的外部訪問一個NodePort
服務。 - LoadBalancer:使用雲提供商的負載均衡器向外部暴露服務。 外部負載均衡器可以將流量路由到自動建立的
NodePort
服務和ClusterIP
服務上。 - ExternalName:通過返回
CNAME
和對應值,可以將服務對映到externalName
欄位的內容(例如,foo.bar.example.com
)。 無需建立任何型別代理。
總體來說,若需要將Service資源釋出至叢集外部,應該將其配置為NodePort或Load-Balancer型別,而若要把外部的服務釋出於叢集內部供Pod物件使用,則需要定義一個ExternalName型別的Service資源,只是這種型別的實現要依賴於v1.7及更高版本的Kubernetes。
?Tips:Service的預設協議是 TCP。
代理模式(proxy mode)
代理模式分為3種:userspace、iptables和ipvs。
userspace代理模式
此處的userspace是指Linux作業系統的使用者空間。在這種模型中,kube-proxy負責跟蹤API Server上Service和Endpoints物件的變動(建立或移除),並據此調整Service資源的定義。
對於每個Service物件,它會隨機開啟一個本地埠(執行於使用者空間的kube-proxy程式負責監聽),任何到達此代理埠的連線請求都將被代理至當前Service資源後端的各Pod物件,至於哪個Pod物件會被選中則取決於當前Service資源的排程方式,預設排程演算法是輪詢(round-robin)。
另外,此類Service物件還會建立iptables規則以捕獲任何到達ClusterIP和埠的流量。在Kubernetes 1.1版本之前,userspace是預設的代理模型。
iptables代理模式
建立Service物件的操作會觸發叢集中的每個kube-proxy並將其轉換為定義在所屬節點上的iptables規則,用於轉發工作介面接收到的、與此Service資源ClusterIP和埠相關的流量。客戶端發來請求將直接由相關的iptables規則進行目標地址轉換(DNAT)後根據演算法排程並轉發至叢集內的Pod物件之上,而無須再經由kube-proxy程式進行處理,因而稱為iptables代理模式。
使用 iptables 處理流量具有較低的系統開銷,因為流量由 Linux netfilter 處理, 而無需在使用者空間和核心空間之間切換。 這種方法也可能更可靠。但是效能一般,而且受規模影響較大,僅適用於少量Service規模的叢集。
對於每個Endpoints物件,Service資源會為其建立iptables規則並指向其iptables地址和埠,而流量轉發到多個Endpoint物件之上的預設排程機制是隨機演算法。iptables代理模型由Kubernetes v1.1版本引入,並於v1.2版本成為預設的型別。
ipvs代理模式
Kubernetes自v1.9版本起引入ipvs代理模式,且自v1.11版本起成為預設設定。在此種模型中,kube-proxy跟蹤API Server上Service和Endpoints物件的變動,並據此來呼叫netlink介面建立或變更ipvs(NAT)規則。
它與iptables規則的不同之處僅在於客戶端請求流量的排程功能由ipvs實現,餘下的其他功能仍由iptables完成。
ipvs代理模型中Service的服務發現和負載均衡功能均基於核心中的ipvs規則實現。類似於iptables,ipvs也構建於核心中的netfilter之上,但它使用hash表作為底層資料結構且工作於核心空間,因此具有流量轉發速度快、規則同步效能好的特性,適用於存在大量Service資源且對效能要求較高的場景。
支援的排程演算法:
rr
:輪替(Round-Robin)lc
:最少連結(Least Connection),即開啟連結數量最少者優先dh
:目標地址雜湊(Destination Hashing)sh
:源地址雜湊(Source Hashing)sed
:最短預期延遲(Shortest Expected Delay)nq
:從不排隊(Never Queue)
示例
建立一個 Nginx Pod:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
run: my-nginx
replicas: 2
template:
metadata:
labels:
run: my-nginx
spec:
containers:
- name: my-nginx
image: nginx
ports:
- containerPort: 80
然後執行:
kubectl apply -f ./run-nginx.yaml
檢視執行:
[root@master test]# kubectl get pods -l run=my-nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
my-nginx-5b56ccd65f-rnv9b 1/1 Running 0 34s 10.233.112.27 node-1 <none> <none>
my-nginx-5b56ccd65f-rx2mq 1/1 Running 0 34s 10.233.112.26 node-1 <none> <none>
檢查 Pod 的 IP 地址:
[root@master test]# kubectl get pods -l run=my-nginx -o yaml | grep ' podIP:'
podIP: 10.233.112.27
podIP: 10.233.112.26
建立service:
[root@master test]# kubectl expose deployment/my-nginx
service/my-nginx exposed
這等價於使用 kubectl create -f
命令建立,對應如下的 yaml 檔案:
apiVersion: v1
kind: Service
metadata:
name: my-nginx
labels:
run: my-nginx
spec:
ports:
- port: 80
protocol: TCP
selector:
run: my-nginx
檢視 Service 資源:
[root@master test]# kubectl get svc my-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-nginx ClusterIP 10.233.22.145 <none> 80/TCP 79s
一個 Service 由一組 backend Pod 組成。這些 Pod 通過 endpoints
暴露出來。 Service Selector 將持續評估,結果被 POST 到一個名稱為 my-nginx
的 Endpoint 物件上。 當 Pod 終止後,它會自動從 Endpoint 中移除,新的能夠匹配上 Service Selector 的 Pod 將自動地被新增到 Endpoint 中。 檢查該 Endpoint:
[root@master test]# kubectl describe svc my-nginx
Name: my-nginx
Namespace: default
Labels: <none>
Annotations: <none>
Selector: run=my-nginx
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.233.22.145
IPs: 10.233.22.145
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.233.112.26:80,10.233.112.27:80
Session Affinity: None
Events: <none>
檢視endporints:
[root@master test]# kubectl get ep my-nginx
NAME ENDPOINTS AGE
my-nginx 10.233.112.26:80,10.233.112.27:80 3m22s
任意節點測試:
# master節點
[root@master test]# curl 10.233.22.145
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
# worker節點
[root@node-2 ~]# curl 10.233.22.145
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>