1.什么是Service?
在kubernets中,Pod是應用程式的載體,Pod你可以想象成就是容器,為動態的一組Pod提供一個固定的訪問入口,它是以一種叫ClusterIP地址來進行標識,而ClusterIP就位于我們集群網路(Cluster Network)當中,我們可以通過Pod的IP地址來進行訪問,但是會遇到問題:
- 動態Pod的IP地址不是固定的,一旦Pod例外退出、節點故障,則會發生Pod重建,一旦發生重建客戶端則會訪問失敗;
- Pod如果擴容多個,會造成客戶端無法有效使用新增的Pod,如果Pod進行縮容則會造成客戶端訪問錯誤;
- 官方檔案: https://kubernetes.io/zh-cn/docs/concepts/services-networking/service/
1.2 Service能干什么?
-
為了解決這個問題,K8s提供了Service資源,Service為動態的一組Pod提供一個固定的訪問入口;這個固定的訪問入口可以理解為是一組應用的前端的負載均衡器;就像LVS或Nginx為一組ReadyServer做負載均衡器是一樣的,你是看不見的,可以理解為Service就是負載均衡器,但是這種負載均衡器比傳統的負載均衡器要強大;Service資源通過"標簽選擇器Label Selector"把篩選出來的符合條件的一組Pod物件定義成一個邏輯集合,而后Service對外提供自己的IP和埠,

-
當客戶端請求Service的IP和埠時,Service將請求調度給標簽匹配的所有的Pod,Service向客戶端隱藏了真實處理請求的Pod資源,使得客戶端的請求看上去是由Service直接處理并進行回應,
-
Service物件的IP地址(Cluster IP或Service IP)是虛擬IP地址,由kubernetes系統在Service物件創建時在專有網路(Service Network)地址中自動分配或由用戶手動指定,其次Service是基于埠過濾,并根據事先定義好的規則將請求轉發至其后端Pod對應的埠上,因此這種代理機制也稱為"埠代理"或"四層代理"作業在TCP/IP協議堆疊的傳輸層;
1.3 Service的作用?
- 暴露流量,讓用戶可以通過ServiceIP+ServicePort訪問后端的Pod應用;
- 負載均衡: 提供基于4層的TCP/IP負載均衡,并不提供HTTP/HTTPS等負載均衡;
- 服務發現: 當發現新增Pod則自動加入至Service的后端,如發現Pod例外則會踢出Service后端;
1.4 Service的作業邏輯;
- Service持續監視API-Server,監視Service標簽選擇器所匹配的后端的Pod,并實時跟蹤這些Pod物件的變動情況,例如IP地址的變化、Pod物件增加或減少;
- Service并不直接與Pod建立關聯關系,他們之間還有一個中間層Endpoints,Endpoints物件是一個由IP地址和埠組成的串列,這些IP地址和埠來自于Service標簽選擇器所匹配到的Pod,默認情況下,創建Service資源時,關聯的Endpoints物件會被自動創建;
1.5 Endpoint資源
- 創建一個Service的時候會自動創建一個與Service同名的Endpoints,事實上,Service不但能夠把標簽選擇器選中的Pod識別為自己的后端端點,還能夠對后端埠做就緒狀態檢測,如果后端Pod是就緒的就把它加入到后端可用端點串列中,反之踢出;
- 這個功能不是Service來做的,而是Service借助一個中間組件,Endpoints也是kubernetes一個標準的資源型別;
- Service會自動去管理Endpoints,Endpoints真正能發揮作用的是Endpoint控制器,一旦創建一個Service,需要為Service指定的基本屬性是"Label Selector"隨后Service控制器會根據這個標簽選擇器創建一個同名的Endpoints資源,是由Sercice控制器請求創建一個同名的Endpoints資源,隨后Endpoints控制器就會介入,因為有一個自己的資源需要被創建,Endpoints控制器就會使用Endpoints的標簽選擇器與Service一模一樣,繼承Service的,Endpoints控制器會根據"標簽選擇器"去查找多少個符合篩選的Pod,最重要的是還會檢查Pod的就緒狀態,真正去系結的不是由Service做的,而是由Endpoints做的,Service只負責調度,如果關聯到了,Service只是把Endpoint幫查找到的所有處于就緒狀態的后端Pod告訴Service,于是成了Service的后端端點;
1.6 Servcie的實作;
- 在kubernetes中,Service只是一個抽象的概念,真正起作用實作負載均衡規則的其實是kube-proxy這個行程,它在每一個節點都需要運行一個kube-proxy,用來完成負載均衡規則的創建;
1.7 Kube-Proxy代理模式
1.7.1UserSpace
- UserSpace模式下,kube-proxy為ServiceIP創建一個監聽埠,當用戶向ServiceIP發起請求;首先按請求會被Iptables規則攔截,然后重定向到kube-proxy對應的埠上,然后kube-proxy根據調度演算法挑選一個Pod,將請求調度到該Pod上;
- 該模式流量經過內核空間后,會送往用戶空間Kube-Proxy行程,而后又被送回內核空間,發往調度分配的目標后端Pod;效率太差,報文先到內核空間再回到用戶空間,因為報文在用戶空間來回切換兩次以上,
1.7.2iptables - iptables模式下,kube-proxy為Service后端的所有Pod創建對應的iptables規則,當用戶向ServiceIP發起請求;首先iptables會攔截用戶請求,然后直接將請求調度給后端的Pod;問題是一個Service會創建大量的Iptables規則,且不支持更高級的調度演算法;
1.7.3IPVS
ipvs模式和iptables類似,kube-proxy為Service后端所有的Pod創建對應的IPVS規則, 一個Service只生成一條規則,所以規模較大的場景應使用IPVS,其次IPVS支持更多的高級演算法;
2.Service的型別
2.1 Service資源規范
apiVersion: v1 # API的版本
kind: Service # 資源型別定義為Service
metadata:
name: ... # Serivce的名稱
namespace: ... # 默認的default
labels:
key1: value1 # 標簽 key:value格式;
key2: value2
spec:
type <string> # Service型別,默認為ClusterIP;
selector <map[string]string> # 標簽選擇器
ports: # ClusterIP:ServicePort
targetPort: <string> #后端目標行程的埠號或名稱,
nodePort: <integer> # 節點埠號,僅適用于NodePort和loadbalancer型別, "建議動態選擇30000-32767"
clusterIP <string> # Service的集群IP,建議由系統自動分配
externalTrafficPolicy <string> # 外部流量策略處理方式,local表示由當前節點處理,cluster表示向集群范圍調度
loadBalancerIP <string> # 外部負載均衡器使用的IP地址,僅適用于loadbalancer,前提是你的公有云得支持你自己指定;
externalName <string> # 外部服務名稱,該名稱作為Service的DNS CNAME值
2.2 ClusterIP
ClusterIP: 通過集群內部IP暴露服務,選擇ServiceIP只能夠在集群內部訪問,這也是默認的Service型別;該地址僅在集群內部可見、可達,無法被集群外部客戶端訪問;而且是默認型別,創建的任何Service默認就是ClusterIP型別,而且只能接受集群內部客戶端的訪問,
2.2.1 ClusterIP示例;
root@kubernetes-master01:~# cat services-clusterip-nginx.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx-clusterip
namespace: default
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:alpine
imagePullPolicy: IfNotPresent
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
namespace: default
spec:
clusterIP:
selector: # 標簽選擇器
app: nginx
ports:
- name: http # 埠名稱
protocol: TCP # 協議型別,目前支持TCP、UDP、SCTP默認為TCP
port: 80 # Service的埠號
targetPort: 80 # 后端目標行程的埠號
root@kubernetes-master01:~# kubectl apply -f services-clusterip-nginx.yaml
pod/nginx-clusterip created
service/nginx-svc created
2.2.1.1查看Service;
root@kubernetes-master01:~# kubectl get svc
nginx-svc ClusterIP 10.106.70.164 <none> 80/TCP 3m
2.2.1.2 可以看到后端就一個Pod;
root@kubernetes-master01:~# kubectl get pods --show-labels -l app=nginx -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES LABELS
nginx-clusterip 1/1 Running 0 8m58s 10.244.4.49 kubernetes-node01 <none> <none> app=nginx
2.2.1.3查看Endpoint資源,Endpoints可以簡寫為ep;
root@kubernetes-master01:~# kubectl get endpoints
nginx-svc 10.244.4.49:80 10m
2.2.1.4測驗訪問;只能在集群內部訪問,外部無法訪問;
root@kubernetes-master01:~# curl -I 10.106.70.164
HTTP/1.1 200 OK
Server: nginx/1.21.5
Content-Type: text/html
Content-Length: 615
Connection: keep-alive
ETag: "61cb5be0-267"
Accept-Ranges: bytes
2.3 NodePort
NodePort:首先是一種ClusterIP型別,也就是說,NodePort是ClusterIP的擴展型別,NodePort型別的Service不僅僅能夠被集群內部的客戶端可見,還能對外部客戶端可見,怎么可見呢?它會與ClusterIP的功能之外在每個節點上使用一個相同的埠號"注意是在每個節點上使用一個相同的埠號"將外部流量引入到該Service上來,
2.3.1 NodePort示例;
root@kubernetes-master01:~# cat services-nodeport-nginx.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-nodeport-svc
namespace: default
spec:
type: NodePort
clusterIP:
selector:
app: nginx
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80 # 后端Pod監聽什么埠就寫什么埠,要不然到達Service的請求轉發給Pod,Pod沒有那個埠也沒用,一定真正轉發到后端程式監聽的埠,如果沒有特殊情況的話,ServicePort和TargetPort保持一致,NodePort可以不用指定,
nodePort: # 正常情況下應由系統自己分配,默認是3000~32767
root@kubernetes-master01:~# kubectl apply -f services-nodeport-nginx.yaml
service/nginx-nodeport-svc created
2.3.1.1查看Service,意味著訪問宿主機IP+nodeport埠就可以訪問服務;
root@kubernetes-master01:~# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 36d
nginx-nodeport-svc NodePort 10.111.124.121 <none> 80:32049/TCP 5s
nginx-svc ClusterIP 10.106.70.164 <none> 80/TCP 34m
2.3.1.2 測驗,這是windows的命令列,也是沒有問題;
C:\Users\海棠>curl -I 10.0.0.1xx:30824
HTTP/1.1 200 OK
Server: nginx/1.21.5
Content-Type: text/html
Content-Length: 615
Connection: keep-alive
ETag: "61cb5be0-267"
Accept-Ranges: bytes
2.4 LoadBalancer
loadBalancer: 這類Service依賴云廠商,需要通過云廠商呼叫API介面創建軟體負載均衡將服務暴露到集群外部,當創建LoadBalancer型別的Service物件時,它會在集群上自動創建一個NodePort型別的Service,集群外部的請求流量會先路由至該負載均衡,并由該負載均衡調度至各個節點的NodePort;
2.4.1 LoadBalancer示例;
root@kubernetes-master01:~# cat services-loadbalancer-nginx.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-loadbalancer-svc
namespace: default
spec:
type: LoadBalancer
selector:
app: nginx
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
loadBalancerIP: 1.2.3.4
2.4.1.2測驗訪問;
# 我們還是只能是通過NodePort來訪問,因為沒有LoadBalancer的IP;
# LoadBalancer其實就是一個增強的NodePort,而LoadBalancer沒有限制流量調度策略的,外部流量策略對loadbalancer依然使用,因為LoadBalancer首先是一個NodePort的Service,
C:\Users\冷雨夜>curl -I 10.0.0.1XX:31943
HTTP/1.1 200 OK
Server: nginx/1.21.5
Content-Type: text/html
Content-Length: 615
Connection: kep-alive
ETag: "61cb5be0-267"
Accept-Ranges: bytes
2.5 ExternalName
此型別不是用來定義如何訪問集群內服務的,而是把集群外部的某些服務以DNS CANME方式映射到集群內,從而讓集群內的Pod資源能夠訪問外部服務的一種實作方式,
我們一直奔跑在進步的旅途轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/501141.html
標籤:其他
下一篇:Unity實作調色板
