Kubernetes的Pods是有生命周期的。他們可以被創建,而且銷毀不會再啟動。如果使用Deployment來運行應用程序,則它可以動態創建和銷毀 Pod。
一個Kubernetes的Service是一種抽象,它定義了一組Pods的邏輯集合和一個用於訪問它們的策略 - 有的時候被稱之為微服務。一個Service的目標Pod集合通常是由Label Selector 來決定的。
舉個例子,想象一個處理圖片的后端運行了三個副本。這些副本都是可以替代的 - 前端不關心它們使用的是哪一個后端。盡管實際組成后端集合的Pod可能會變化,前端的客戶端卻不需要知道這個變化,也不需要自己有一個列表來記錄這些后端服務。Service抽象能達到這種解耦。
不像 Pod 的 IP 地址,它實際路由到一個固定的目的地,Service 的 IP 實際上不能通過單個主機來進行應答。相反,使用 iptables(Linux 中的數據包處理邏輯)來定義一個虛擬IP地址(VIP),它可以根據需要透明地進行重定向。當客戶端連接到 VIP 時,它們的流量會自動地傳輸到一個合適的Endpoint。環境變量和 DNS,實際上會根據 Service 的 VIP 和端口來進行填充。
kube-proxy支持三種代理模式: 用戶空間,iptables和IPVS
-
Userspace代理模式
Client Pod要訪問Server Pod時,它先將請求發給本機內核空間中的service規則,由它再將請求,轉給監聽在指定套接字上的kube-proxy,kube-proxy處理完請求,並分發請求到指定Server Pod后,再將請求遞交給內核空間中的service,由service將請求轉給指定的Server Pod。由於其需要來回在用戶空間和內核空間交互通信,因此效率很差 。
當一個客戶端連接到一個 VIP,iptables 規則開始起作用,它會重定向該數據包到 Service代理 的端口。Service代理 選擇一個 backend,並將客戶端的流量代理到 backend 上。
這意味着 Service 的所有者能夠選擇任何他們想使用的端口,而不存在沖突的風險。客戶端可以簡單地連接到一個 IP 和端口,而不需要知道實際訪問了哪些 Pod。
-
iptables代理模式
當一個客戶端連接到一個 VIP,iptables 規則開始起作用。一個 backend 會被選擇(或者根據會話親和性,或者隨機),數據包被重定向到這個 backend。不像 userspace 代理,數據包從來不拷貝到用戶空間,kube-proxy 不是必須為該 VIP 工作而運行,並且客戶端 IP 是不可更改的。當流量打到 Node 的端口上,或通過負載均衡器,會執行相同的基本流程,但是在那些案例中客戶端 IP 是可以更改的。
-
IPVS代理模式
在大規模集群(例如10,000個服務)中,iptables 操作會顯着降低速度。IPVS 專為負載平衡而設計,並基於內核內哈希表。因此,您可以通過基於 IPVS 的 kube-proxy 在大量服務中實現性能一致性。同時,基於 IPVS 的 kube-proxy 具有更復雜的負載平衡算法(最小連接,局部性,加權,持久性)。
在 Kubernetes 集群中,每個 Node 運行一個 kube-proxy 進程。 kube-proxy 負責為 Service 實現了一種VIP(虛擬 IP)的形式,而不是 ExternalName 的形式。
在 Kubernetes v1.0 版本,代理完全在userspace。在Kubernetes v1.1 版本,新增了 iptables 代理,但並不是默認的運行模式。 從 Kubernetes v1.2 起,默認就是iptables 代理。 在 Kubernetes v1.8.0-beta.0 中,添加了 ipvs 代理在 Kubernetes 1.14 版本開始默認使用 ipvs 代理。在 Kubernetes v1.0 版本, Service 是 “4層”(TCP/UDP over IP)概念。 在Kubernetes v1.1 版本,新增了Ingress API(beta 版),用來表示 “7層”(HTTP)服務 。這種模式,kube-proxy 會監視 Kubernetes Service 對象和 Endpoints ,調用 netlink 接口以相應地創建ipvs 規則並定期與 Kubernetes Service 對象和 Endpoints 對象同步 ipvs 規則,以確保 ipvs 狀態與期望一致。訪問服務時,流量將被重定向到其中一個后端 Pod與 iptables 類似,ipvs 於 netfilter 的 hook 功能,但使用哈希表作為底層數據結構並在內核空間中工作。這意味着 ipvs 可以更快地重定向流量,並且在同步代理規則時具有更好的性能。此外,ipvs 為負載均衡算法提供了更多選項。
Service 在 K8s 中有以下四種類型:
- ClusterIp:默認類型,自動分配一個僅 Cluster 內部可以訪問的虛擬 IP
- NodePort:在 ClusterIP 基礎上為 Service 在每台機器上綁定一個端口,這樣就可以通過 NodePort 來訪問該服務
- LoadBalancer:在 NodePort 的基礎上,借助 cloud provider 創建一個外部負載均衡器,並將請求轉發到NodePort。是付費服務,而且價格不菲
- ExternalName:把集群外部的服務引入到集群內部來,在集群內部直接使用。沒有任何類型代理被創建,這只有 kubernetes 1.7 或更高版本的kube-dns 才支持
ClusterIP
docker pull tomcat:9.0.20-jre8-alpine
clusteripdemo.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: clusteripdemo
labels:
app: clusteripdemo
spec:
replicas: 3
template:
metadata:
name: clusteripdemo
labels:
app: clusteripdemo
spec:
containers:
- name: clusteripdemo
image: tomcat:9.0.20-jre8-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
restartPolicy: Always
selector:
matchLabels:
app: clusteripdemo
---
apiVersion: v1
kind: Service
metadata:
name: clusterip-svc
spec:
selector:
app: clusteripdemo
ports:
- port: 8080
targetPort: 8080
type: ClusterIP
運行服務
kubectl apply -f clusteripdemo.yml
查看服務
kubectl get svc
訪問服務
curl 10.1.15.24:8080
刪除服務
kubectl delete -f clusteripdemo.yml
NodePort
docker pull tomcat:9.0.20-jre8-alpine
nodeportdemo.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: clusteripdemo
labels:
app: clusteripdemo
spec:
replicas: 3
template:
metadata:
name: clusteripdemo
labels:
app: clusteripdemo
spec:
containers:
- name: clusteripdemo
image: tomcat:9.0.20-jre8-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
restartPolicy: Always
selector:
matchLabels:
app: clusteripdemo
---
apiVersion: v1
kind: Service
metadata:
name: clusterip-svc
spec:
selector:
app: clusteripdemo
ports:
- port: 8080
targetPort: 8080
nodePort: 30088
type: NodePort
運行服務
kubectl apply -f nodeportdemo.yml
查看服務
kubectl get svc
訪問服務
curl 10.1.61.126:8080
瀏覽器訪問服務
http://192.168.198.156:30088
刪除服務
kubectl delete -f nodeportdemo.yml