四層負載均衡?Service
在?kubernetes?中式塌,Pod?是有生命周期的,如果?Pod?重啟它的?IP?很有可能會發(fā)生變化。如果我們的服務都是將?Pod?的?IP?地址寫死,Pod?掛掉或者重啟笋庄,和剛才重啟的?pod?相關聯(lián)的其他服務將會找不 到它所關聯(lián)的?Pod,為了解決這個問題倔监,在?kubernetes?中定義了?service?資源對象直砂,Service?定義了 一個服務訪問的入口,客戶端通過這個入口即可訪問服務背后的應用集群實例浩习,service?是一組?Pod?的 邏輯集合静暂,這一組?Pod?能夠被?Service?訪問到,通常是通過?Label Selector?實現(xiàn)的谱秽。
1洽蛀、pod ip?經(jīng)常變化,service?是?pod?的代理疟赊,我們客戶端訪問郊供,只需要訪問?service,就會把請求 代理到?Pod
2近哟、pod ip?在?k8s?集群之外無法訪問驮审,所以需要創(chuàng)建?service,這個?service?可以在?k8s?集群外訪 問的吉执。
Service?概述
service?是一個固定接入層疯淫,客戶端可以通過訪問?service?的?ip?和端口訪問到?service?關聯(lián)的后端pod,這個?service?工作依賴于在?kubernetes?集群之上部署的一個附件戳玫,就是?kubernetes?的?dns?服 務(不同?kubernetes?版本的?dns?默認使用的也是不一樣的峡竣,1.11?之前的版本使用的是?kubeDNs,較 新的版本使用的是?coredns)量九,service?的名稱解析是依賴于?dns?附件的适掰,因此在部署完?k8s?之后需要再部署?dns?附件,kubernetes?要想給客戶端提供網(wǎng)絡功能荠列,需要依賴第三方的網(wǎng)絡插件(flannel类浪,?calico?等)。每個?K8s?節(jié)點上都有一個組件叫做?kube-proxy肌似,kube-proxy?這個組件將始終監(jiān)視著?apiserver?中有關?service?資源的變動信息费就,需要跟?master?之上的?apiserver?交互,隨時連接到?apiserver?上獲取任何一個與?service?資源相關的資源變動狀態(tài)川队,這種是通過?kubernetes?中固有的一種 請求方法?watch(監(jiān)視)來實現(xiàn)的力细,一旦有?service?資源的內(nèi)容發(fā)生變動(如創(chuàng)建睬澡,刪除),kube- proxy?都會將它轉化成當前節(jié)點之上的能夠實現(xiàn)?service?資源調(diào)度眠蚂,把我們請求調(diào)度到后端特定的?pod?資源之上的規(guī)則煞聪,這個規(guī)則可能是?iptables,也可能是?ipvs逝慧,取決于?service?的實現(xiàn)方式昔脯。
Service?工作原理
k8s?在創(chuàng)建?Service?時,會根據(jù)標簽選擇器?selector(lable selector)來查找?Pod笛臣,據(jù)此創(chuàng)建與
Service?同名的?endpoint?對象云稚,當?Pod?地址發(fā)生變化時,endpoint?也會隨之發(fā)生變化沈堡,service?接 收前端?client?請求的時候静陈,就會通過?endpoint,找到轉發(fā)到哪個?Pod?進行訪問的地址诞丽。(至于轉發(fā)到哪 個節(jié)點的?Pod窿给,由負載均衡?kube-proxy?決定)
kubernetes?集群中有三類?IP?地址
1、Node Network(節(jié)點網(wǎng)絡):物理節(jié)點或者虛擬節(jié)點的網(wǎng)絡率拒,如?ens33?接口上的網(wǎng)路地址?
~]# ip addr
2: ens33:?<BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP
link/ether 00:0c:29:87:60:d5 brd ff:ff:ff:ff:ff:ff
inet 192.168.1.63/24 brd 192.168.1.255 scope global noprefixroute ens33
2崩泡、Pod network(pod?網(wǎng)絡),創(chuàng)建的?Pod?具有的?IP?地址
]# kubectl get pods -o wide
NAME READY STATUS IP NODE
frontend-h78gw 1/1 Running?
10.244.187.76 ? god62
Node Network?和?Pod network?這兩種網(wǎng)絡地址是我們實實在在配置的猬膨,其中節(jié)點網(wǎng)絡地址是配
置在節(jié)點接口之上角撞,而?pod?網(wǎng)絡地址是配置在?pod?資源之上的,因此這些地址都是配置在某些設備之上 的勃痴,這些設備可能是硬件谒所,也可能是軟件模擬的
3、Cluster Network(集群地址沛申,也稱為?service network)劣领,這個地址是虛擬的地址(virtual ip),沒有配置在某個接口上铁材,只是出現(xiàn)在?service?的規(guī)則當中尖淘。
kubectl get svc
NAME? ? ? ? TYPE? ? ? ? CLUSTER-IP? ? ? EXTERNAL-IP? PORT(S)? ? ? ? ? AGE
kubernetes? ClusterIP? 10.96.0.1? ? ? ? <none>? ? ? ? 443/TCP? ? ? ? ? 21d
nginx? ? ? ? NodePort? ? 10.105.245.139? <none>? ? ? ? 3000:31003/TCP? 7d23h
#查看定義?Service?資源需要的字段有哪些?
kubectl explain service
FIELDS:
? apiVersion? <string>. ? ? ? ??#service?資源使用的?api?組
kind <string> ? ? ? ? ? ? ? ? ? ? ??#創(chuàng)建的資源類型
metadata <Object> ? ? ? ? ??#定義元數(shù)據(jù)
spec <Object>
#查看?service?的?spec?字段如何定義?
clusterIP <string>. ? #動態(tài)分配的地址,也可以自己在創(chuàng)建的時候指定著觉,創(chuàng)建之后就改不了了
ports <[]Object>?#定義?service?端口村生,用來和后端?pod?建立聯(lián)系?
publishNotReadyAddresses <boolean>
selector ?#通過標簽選擇器選擇關聯(lián)的?pod?有哪些
sessionAffinity ? ? ? ? ? <string>
sessionAffinityConfig?<Object>
#service?在實現(xiàn)負載均衡的時候還支持?sessionAffinity,sessionAffinity?什么意思?會話聯(lián)系饼丘,默認是?none趁桃,隨機調(diào)度的(基于?iptables?規(guī)則調(diào)度的);如果我們定義sessionAffinity?的?client ip,那就表示把來自同一客戶端的?IP?請求調(diào)度到同一個?pod?上
type ?#定義?service?的類型
Service?的四種類型
kubectl explain service.spec.type
DESCRIPTION:
type determines how the Service is exposed. Defaults to?
ClusterIP. Valid options are?ExternalName,?ClusterIP,?NodePort, and?LoadBalancer.
1、ExternalName:
適用于?k8s?集群內(nèi)部容器訪問外部資源卫病,它沒有?selector油啤,也沒有定義任何的端口和Endpoint。
以下 Service?定義的是將?prod?名稱空間中的?my-service?服務映射到?my.database.example.com
kind: Service?
apiVersion: v1?
metadata:
name: my-service
namespace: prod spec:
type: ExternalName
externalName: my.database.example.com
當查詢主機?my-service.prod.svc.cluster.local?時蟀苛,群集?DNS?將返回值為my.database.example.com?的?CNAME?記錄益咬。
2、ClusterIP:
通過?k8s?集群內(nèi)部?IP?暴露服務屹逛,選擇該值,服務只能夠在集群內(nèi)部訪問汛骂,這也是默認的?ServiceType罕模。
3、NodePort:
通過每個?Node?節(jié)點上的?IP?和靜態(tài)端口暴露?k8s?集群內(nèi)部的服務帘瞭。通過請求?<NodeIP>:<NodePort>可以把請求代理到內(nèi)部的?pod淑掌。Client----->NodeIP:NodePort---- ->Service Ip:ServicePort----->PodIP:ContainerPort。
4蝶念、LoadBalancer:
使用云提供商的負載局衡器抛腕,可以向外部暴露服務。外部的負載均衡器可以路由到?NodePort?服務 和?ClusterIP?服務媒殉。
Service?的端口
kubectl explain service.spec.ports
name ?#定義端口的名字?
nodePort <integer>
|#宿主機上映射的端口担敌,比如一個?Web?應用需要被?k8s?集群之外的其他用戶訪問,那么需要配置?type=NodePort廷蓉,若配置?nodePort=30001全封,那么其他機器就可以通過瀏覽器訪問?scheme://k8s?集 群中的任何一個節(jié)點?ip:30001?即可訪問到該服務,例如?http://192.168.1.63:30001桃犬。如果在?k8s?中 部署?MySQL?數(shù)據(jù)庫刹悴,MySQL?可能不需要被外界訪問,只需被內(nèi)部服務訪問攒暇,那么就不需要設置?NodePort
port -required-?#service?的端口土匀,這個是?k8s?集群內(nèi)部服務可訪問的端口?
protocol ?<string>
targetPort.??<string>
# targetPort?是?pod?上的端口,從?port?和?nodePort?上來的流量形用,經(jīng)過?kube-proxy?流入到后端?pod?的?targetPort?上就轧,最后進入容器。與制作容器時暴露的端口一致(使用?DockerFile?中的?EXPOSE)田度,例如官方的?nginx?暴露?80?端口钓丰。
創(chuàng)建?Service:type?類型是?ClusterIP
docker load -I nginx.tar.gz
cat pod_test.yaml
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:
? ? ? - image: nginx
? ? ? ? name: my-nginx
? ? ? ? ports:
? ? ? ? - containerPort: 80? #pod容器中暴露的端口
kubectl apply -f pod_test.yaml
kubectl get pods -l run=my-nginx -o wide
curl ip 看主頁
Welcome to nginx!
kubectl exec -it my-nginx-5b56ccd65f-cwqbg -- /bin/bash
需要注意的是,pod?雖然定義了容器端口每币,但是不會使用調(diào)度到該節(jié)點上的?80?端口携丁,也不會使用任 何特定的?NAT?規(guī)則去路由流量到?Pod?上。 這意味著可以在同一個節(jié)點上運行多個?Pod,使用相同的容 器端口梦鉴,并且可以從集群中任何其他的?Pod?或節(jié)點上使用?IP?的方式訪問到它們李茫。
誤刪除其中一個?Pod:
kubectl delete pods my-nginx-5b56ccd65f-cwqbg
kubectl get pods -l run=my-nginx -o wide
kubectl get pods -l run=my-nginx -o wide
NAME? ? ? ? ? ? ? ? ? ? ? ? READY? STATUS? ? RESTARTS? AGE? IP? ? ? ? ? ? ? NODE? ? ? NOMINATED NODE? READINESS GATES
my-nginx-5b56ccd65f-d7j7v? 1/1? ? Running? 0? ? ? ? ? 21s? 10.244.187.103 ?god62? <none>? ? ? ? ? <none>
my-nginx-5b56ccd65f-h2kjl? 1/1? ? Running? 0? ? ? ? ? 14m? 10.244.209.135 ?god64? <none>? ? ? ? ? <none>
通過上面可以看到重新生成了一個?pod?:my-nginx-5b56ccd65f-7xzr4,ip?是?10.244.187.102肥橙,在?k8s?中創(chuàng)建?pod魄宏,如果?pod?被刪除了,重新生成的?pod ip?地址會發(fā)生變化存筏,所 以需要在?pod?前端加一個固定接入層宠互。接下來創(chuàng)建?service:
創(chuàng)建?Service
cat service_test.yaml
apiVersion: v1
kind: Service
metadata:
? name: my-nginx
? labels:
? ? run: my-nginx
spec:
? type: ClusterIP
? ports:
? - port: 80 ? ? ? ? ? ??#service?的端口,暴露給?k8s?集群內(nèi)部服務訪問
? ? protocol: TCP ? ? ? #通過ip和端口代理
? ? targetPort: 80 ? ? ?#pod?容器中定義的端口
? selector:
? ? run: my-nginx ? ? ??#選擇擁有?run=my-nginx?標簽的?pod
上述?yaml?文件將創(chuàng)建一個?Service椭坚,具有標簽?run=my-nginx?的?Pod予跌,目標?TCP?端口?80,并 且在一個抽象的?Service?端口(targetPort:容器接收流量的端口;port:抽象的?Service?端口善茎,可 以使任何其它?Pod?訪問該?Service?的端口)上暴露券册。
kubectl apply -f service_test.yaml
kubectl get svc -l run=my-nginx
NAME? ? ? TYPE? ? ? ? CLUSTER-IP? ? ? EXTERNAL-IP? PORT(S)? AGE
my-nginx? ClusterIP? 10.102.215.115? <none>? ? ? ? 80/TCP? ? 3m34s
#在?k8s?控制節(jié)點訪問?service?的?ip:端口就可以把請求代理到后端?pod?
curl 10.102.215.115:80
Welcome to nginx!
#通過上面可以看到請求?service IP:port?跟直接訪問?pod ip:port?看到的結果一樣,這就說明?service?可以把請求代理到它所關聯(lián)的后端?pod
注意:上面的?10.102.215.115:80?地址只能是在?k8s?集群內(nèi)部可以訪問垂涯,在外部無法訪問烁焙,比方說
我們想要通過瀏覽器訪問,那么是訪問不通的耕赘,如果想要在?k8s?集群之外訪問骄蝇,是需要把?service type?類型改成?nodePort?的
#通過上面可以看到請求?service IP:port?跟直接訪問?pod ip:port?看到的結果一樣,這就說明?service?可以把請求代理到它所關聯(lián)的后端?pod
注意:上面的?10.102.215.115:80?地址只能是在?k8s?集群內(nèi)部可以訪問操骡,在外部無法訪問乞榨,比方說
我們想要通過瀏覽器訪問,那么是訪問不通的当娱,如果想要在?k8s?集群之外訪問吃既,是需要把?service type?類型改成?nodePort?的
#查看?service?詳細信息
kubectl describe svc my-nginx
kubectl get ep my-nginx
NAME? ? ? ENDPOINTS? ? ? ? ? ? ? ? ? ? ? ? ? ? AGE
my-nginx? 10.244.187.106:80,10.244.209.138:80? 6m8s
service?可以對外提供統(tǒng)一固定的?ip?地址,并將請求重定向至集群中的?pod跨细。其中“將請求重定向 至集群中的?pod”就是通過?endpoint?與?selector?協(xié)同工作實現(xiàn)鹦倚。selector?是用于選擇?pod,由?selector?選擇出來的?pod?的?ip?地址和端口號冀惭,將會被記錄在?endpoint?中震叙。endpoint?便記錄了所有?pod?的?ip?地址和端口號。當一個請求訪問到?service?的?ip?地址時散休,就會從?endpoint?中選擇出一個?ip地址和端口號媒楼,然后將請求重定向至?pod?中。具體把請求代理到哪個?pod戚丸,需要的就是?kube-proxy?的 輪詢實現(xiàn)的划址。service?不會直接到?pod扔嵌,service?是直接到?endpoint?資源,就是地址加端口夺颤,再由?endpoint?再關聯(lián)到?pod痢缎。
service?只要創(chuàng)建完成,我們就可以直接解析它的服務名世澜,每一個服務創(chuàng)建完成后都會在集群?dns?中 動態(tài)添加一個資源記錄独旷,添加完成后我們就可以解析了,資源記錄格式是:
SVC_NAME.NS_NAME.DOMAIN.LTD.?服務名.命名空間.域名后綴
集群默認的域名后綴是?
svc.cluster.local.
就像我們上面創(chuàng)建的?my-nginx?這個服務寥裂,它的完整名稱解析就是?my-nginx.default.svc.cluster.local
# kubectl exec -it my-nginx-5b56ccd65f-7xzr4 -- /bin/bash?
root@my-nginx-5b56ccd65f-7xzr4:/# curl my-nginx.default.svc.cluster.local
Welcome to nginx!
創(chuàng)建?Service:type?類型是?NodePort
cat pod_nodeport.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
? name: my-nginx-nodeport
spec:
? selector:
? ? matchLabels:
? ? ? run: my-nginx-nodeport
? replicas: 2
? template:
? ? metadata:
? ? ? labels:
? ? ? ? run: my-nginx-nodeport
? ? spec:
? ? ? containers:
? ? ? - name: my-nginx-nodeport-contauber
? ? ? ? image: nginx
? ? ? ? ports:
? ? ? ? - containerPort: 80
kubectl apply -f pod_nodeport.yaml
#查看?pod?是否創(chuàng)建成功
kubectl get pods -l run=my-nginx-nodeport
NAME? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? READY? STATUS? ? RESTARTS? AGE
my-nginx-nodeport-6cb5fff859-9c4lm? 1/1? ? Running? 0? ? ? ? ? 54s
my-nginx-nodeport-6cb5fff859-lqdnc? 1/1? ? Running? 0? ? ? ? ? 54s
創(chuàng)建?service嵌洼,代理?pod
cat service_nodeport.yaml
apiVersion: v1
kind: Service
metadata:
? name: my-nginx-nodeport
? labels:
? ? run: my-nginx-nodeport
spec:
? type: NodePort
? ports:
? - port: 80
? ? protocol: TCP
? ? targetPort: 80
? selector: 30380
? ? run: my-nginx-nodeport
kubectl apply -f service_nodeport.yaml
#查看剛才創(chuàng)建的?service
kubectl get svc -l run=my-nginx-nodeport
NAME? ? ? ? ? ? ? ? TYPE? ? ? CLUSTER-IP? ? ? EXTERNAL-IP? PORT(S)? ? ? ? AGE
my-nginx-nodeport? NodePort? 10.100.132.187? <none>? ? ? ? 80:30380/TCP? 2m36s
curl?10.100.132.187
<!DOCTYPE html>
<h1>Welcome to nginx!</h1> </html>
10.100.132.187是?k8s?集群內(nèi)部的?service ip?地址,只能在?k8s?集群內(nèi)部訪問封恰,在集群外無法訪問麻养。
#在集群外訪問?service
curl 192.168.172.163:30380
過程就是192.168.172.163:30380。--->?10.100.132.187:80(kubectl get svc -l run=my-nginx-nodeport)----> pod ip:container port 隨機生成的如下
創(chuàng)建?Service:type?類型是?ExternalName
應用場景:跨名稱空間訪問
需求:default?名稱空間下的?client?服務想要訪問?nginx-ns?名稱空間下的?nginx-svc?服務
docker load -I busybox.tar.gz. ? 工作節(jié)點
cat client.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
? name: client
spec:
? replicas: 1
? selector:
? ? matchLabels:
? ? ? app: busybox
? template:
? ? metadata:
? ? ? labels:
? ? ? ? app: busybox
? ? spec:
? ? ? containers:
? ? ? - name: busybox
? ? ? ? image: busybox
? ? ? ? command: ["/bin/sh","-c","sleep 36000"]
kubectl apply -f client.yaml
?#. cat client_svc.yaml
apiVersion: v1
kind: Service
metadata:
? name: client-svc
spec:
? type: ExternalName
? externalName: nginx-svc.nginx-ns.svc.cluster.local
? ports:
? - name: http
? ? port: 80
? ? targetPort: 80
#該文件中指定了到?nginx-svc?的軟鏈俭驮,讓使用者感覺就好像調(diào)用自己命名空間的服務一樣回溺。?#查看?pod?是否正常運行
kubectl get pods | grep client-76b6556d97-xqkzk
client-76b6556d97-xqkzk? ? ? ? ? ? ? 1/1? ? Running? ? 0? ? ? ? ? 64m
kubectl apply -f client_svc.yaml
kubectl apply -f client_svc.yaml
#創(chuàng)建名稱空間
kubectl create ns nginx-ns
cat server_nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
? name: nginx
? namespace: nginx-ns
spec:
? replicas: 1
? selector:
? ? matchLabels:
? ? ? app: nginx
? template:
? ? metadata:
? ? ? labels:
? ? ? ? app: nginx
? ? spec:
? ? ? containers:
? ? ? - name: nginx
? ? ? ? image: nginx
? ? ? ? imagePullPolicy: IfNotPresent
kubectl apply -f server_nginx.yaml
#查看?pod?是否創(chuàng)建成功
kubectl get pods -n nginx-ns
NAME? ? ? ? ? ? ? ? ? ? READY? STATUS? ? RESTARTS? AGE
nginx-7cf7d6dbc8-glps2? 1/1? ? Running? 0? ? ? ? ? 79m
cat nginx_svc.yaml
apiVersion: v1
kind: Service
metadata:
? name: nginx-svc
? namespace: nginx-ns
spec:
? selector:
? ? app: nginx
? ports:
? ? - name: http
? ? ? protocol: TCP
? ? ? port: 80
? ? ? targetPort: 80
kubectl apply -f nginx_svc.yaml
#登錄到?client pod
kubectl exec -it client-76b6556d97-xqkzk -- /bin/sh
wget -q -O - client-svc.default.svc.cluster.local
wget -q -O - nginx-svc.nginx-ns.svc.cluster.local
k8s 映射外部服務分享
場景?1:k8s?集群引用外部的?mysql?數(shù)據(jù)庫
在 god62?上安裝?mysql?數(shù)據(jù)庫:
yum install mariadb-server.x86_64 -y
systemctl start mariadb
cat mysql_service.yaml
apiVersion: v1
kind:? Service
metadata:
? name: mysql
pec:kubectl apply -f mysql_service.yaml
? type: ClusterIP
? ports:
? - port: 3306
kubectl apply -f mysql_service.yaml
kubectl get svc | grep mysql
mysql? ? ? ? ? ? ? ClusterIP? ? ? 10.109.176.8? ? <none>? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 3306/TCP? ? ? ? 49s
kubectl describe svc mysql
Name: mysql
Namespace:? ? ? ? default
Labels:? ? ? ? ? ? <none>
Annotations:? ? ? <none>
Selector:? ? ? ? ? <none>
Type:? ? ? ? ? ? ? ClusterIP
IP Families:? ? ? <none>
IP:? ? ? ? ? ? ? ? 10.109.176.8
IPs:? ? ? ? ? ? ? 10.109.176.8
Port:? ? ? ? ? ? ? <unset>? 3306/TCP
TargetPort:? ? ? ? 3306/TCP
Endpoints:? ? ? ? <none> ? ?#還沒有endpoint
Session Affinity:? None
Events:? ? ? ? ? ? <none>
cat mysql_endpoint.yaml
apiVersion: v1
kind: Endpoints
metadata:
? name: mysql
subsets:
- addresses:
? ? - ip: 192.168.172.162
? ports:
? ? - protocol: TCP
? ? ? port: 3306
kubectl describe svc mysql
Name:? ? ? ? ? ? ? mysql
Namespace:? ? ? ? default
Labels:? ? ? ? ? ? <none>
Annotations:? ? ? <none>
Selector:? ? ? ? ? <none>
Type:? ? ? ? ? ? ? ClusterIP
IP Families:? ? ? <none>
IP:? ? ? ? ? ? ? ? 10.109.176.8
IPs:? ? ? ? ? ? ? 10.109.176.8
Port:? ? ? ? ? ? ? <unset>? 3306/TCP
TargetPort:? ? ? ? 3306/TCP
Endpoints:? ? ? ? 192.168.172.162:3306 ? ? #這個 定義的外部數(shù)據(jù)庫煞抬,name與之對應
Session Affinity:? None
Events:? ? ? ? ? ? <none>
上面配置就是將外部?IP?地址和服務引入到?k8s?集群內(nèi)部累贤,由?service?作為一個代理來達到能夠訪問
外部服務的目的妖混。
Service?代理:kube-proxy?組件詳解
Kubernetes service?只是把應用對外提供服務的方式做了抽象,真正的應用跑在?Pod?中的container?里逸嘀,我們的請求轉到?kubernetes nodes?對應的?nodePort?上,那么?nodePort?上的請求是如何進一步轉到提供后臺服務的?Pod?的呢? 就是通過?kube-proxy?實現(xiàn)的:
kube-proxy?部署在?k8s?的每一個?Node?節(jié)點上允粤,是?Kubernetes?的核心組件崭倘,我們創(chuàng)建一個?service?的時候,kube-proxy?會在?iptables?中追加一些規(guī)則类垫,為我們實現(xiàn)路由與負載均衡的功能司光。在?k8s1.8?之前,kube-proxy?默認使用的是?iptables?模式悉患,通過各個?node?節(jié)點上的?iptables?規(guī)則來實 現(xiàn)?service?的負載均衡残家,但是隨著?service?數(shù)量的增大,iptables?模式由于線性查找匹配售躁、全量更新等 特點坞淮,其性能會顯著下降。從?k8s?的?1.8?版本開始陪捷,kube-proxy?引入了?IPVS?模式回窘,IPVS?模式與?iptables?同樣基于?Netfilter,但是采用的?hash?表市袖,因此當?service?數(shù)量達到一定規(guī)模時啡直,hash?查表 的速度優(yōu)勢就會顯現(xiàn)出來,從而提高?service?的服務性能。
service?是一組?pod?的服務抽象付枫,相當于一組?pod?的?LB烹玉,負責將請求分發(fā)給對應的?pod。service?會為這個?LB?提供一個?IP阐滩,一般稱為?cluster IP二打。kube-proxy?的作用主要是負責?service?的實現(xiàn),具體 來說掂榔,就是實現(xiàn)了內(nèi)部從?pod?到?service?和外部的從?node port?向?service?的訪問继效。
1、kube-proxy?其實就是管理?service?的訪問入口装获,包括集群內(nèi)?Pod?到?Service?的訪問和集群外訪問?service瑞信。
2、kube-proxy?管理?sevice?的?Endpoints穴豫,該?service?對外暴露一個?Virtual IP凡简,也可以稱為是?Cluster IP,?集群內(nèi)通過訪問這個?Cluster IP:Port?就能訪問到集群內(nèi)對應的?serivce?下的?Pod。
kube-proxy?三種工作模式?
1精肃、Userspace?方式:
Client Pod?要訪問?Server Pod?時秤涩,它先將請求發(fā)給內(nèi)核空間中的?service iptables?規(guī)則,由它再將請求轉給監(jiān)聽在指定套接字上的?kube-proxy?的端口司抱,kube-proxy?處理完請求筐眷,并分發(fā)請求到指定?Server Pod?后,再將請求轉發(fā)給內(nèi)核空間中的?service ip,由?service iptables?將請求轉給各個節(jié)點中 的?Server Pod习柠。
這個模式有很大的問題匀谣,客戶端請求先進入內(nèi)核空間的,又進去用戶空間訪問?kube-proxy资溃,由?kube-proxy?封裝完成后再進去內(nèi)核空間的?iptables武翎,再根據(jù)?iptables?的規(guī)則分發(fā)給各節(jié)點的用戶空間 的?pod。由于其需要來回在用戶空間和內(nèi)核空間交互通信溶锭,因此效率很差宝恶。在?Kubernetes 1.1?版本之 前,userspace?是默認的代理模型暖途。
2卑惜、iptables?方式:
客戶端?IP?請求時,直接請求本地內(nèi)核?service ip驻售,根據(jù)?iptables?的規(guī)則直接將請求轉發(fā)到到各?pod?上露久,因為使用?iptable NAT?來完成轉發(fā),也存在不可忽視的性能損耗欺栗。另外毫痕,如果集群中存上萬的?Service/Endpoint征峦,那么?Node?上的?iptables rules?將會非常龐大,性能還會再打折
iptables?代理模式由?Kubernetes 1.1?版本引入消请,自?1.2?版本開始成為默認類型栏笆。
3、ipvs?方式:
Kubernetes?自?1.9-alpha?版本引入了?ipvs?代理模式臊泰,自?1.11?版本開始成為默認設置蛉加。客戶端
請求時到達內(nèi)核空間時缸逃,根據(jù)?ipvs?的規(guī)則直接分發(fā)到各?pod?上针饥。kube-proxy?會監(jiān)視?KubernetesService?對象和?Endpoints,調(diào)用?netlink?接口以相應地創(chuàng)建?ipvs?規(guī)則并定期與?KubernetesService?對象和?Endpoints?對象同步?ipvs?規(guī)則需频,以確保?ipvs?狀態(tài)與期望一致丁眼。訪問服務 時,流量將被重定向到其中一個后端?Pod昭殉。與?iptables?類似苞七,ipvs?基于?netfilter?的?hook?功能,但 使用哈希表作為底層數(shù)據(jù)結構并在內(nèi)核空間中工作挪丢。這意味著?ipvs?可以更快地重定向流量蹂风,并且在同步 代理規(guī)則時具有更好的性能。此外吃靠,ipvs?為負載均衡算法提供了更多選項硫眨,例如:
rr:輪詢調(diào)度?
lc:最小連接數(shù)?
dh:目標哈希?
sh:源哈希?
sed:最短期望延遲?
nq:不排隊調(diào)度
如果某個服務后端?pod?發(fā)生變化足淆,標簽選擇器適應的?pod?又多一個巢块,適應的信息會立即反映到?apiserver?上,而?kube-proxy?一定可以?watch?到?etc?中的信息變化,而將它立即轉為?ipvs?或者?iptables?中的規(guī)則巧号,這一切都是動態(tài)和實時的族奢,刪除一個?pod?也是同樣的原理。如圖:
注:
以上不論哪種丹鸿,kube-proxy?都通過?watch?的方式監(jiān)控著?apiserver?寫入?etcd?中關于?Pod?的最 新狀態(tài)信息,它一旦檢查到一個?Pod?資源被刪除了或新建了越走,它將立即將這些變化,反應再?iptables?或?ipvs?規(guī)則中靠欢,以便?iptables?和?ipvs?在調(diào)度?Clinet Pod?請求到?Server Pod?時廊敌,不會出現(xiàn)?Server Pod?不存在的情況。自?k8s1.1?以后,service?默認使用?ipvs?規(guī)則门怪,若?ipvs?沒有被激活骡澈,則降級使用?iptables?規(guī)則.?但在?1.1?以前,service?使用的模式默認為?userspace掷空。Service?是由?kube-proxy?組件肋殴,加上?iptables?來共同實現(xiàn)的囤锉。kube-proxy?通過?iptables?處理?Service?的過程,需要在宿主機上設置相 當多的?iptables?規(guī)則护锤,如果宿主機有大量的?Pod官地,不斷刷新?iptables?規(guī)則,會消耗大量的?CPU?資源烙懦。
kube-proxy?生成的?iptables?規(guī)則分析
在 k8s?創(chuàng)建的?service驱入,雖然有?ip?地址,但是?service?的?ip?是虛擬的氯析,不存在物理機上的沧侥,是在
iptables?或者?ipvs?規(guī)則里的。
]# kubectl get svc | grep my-nginx
my-nginx ClusterIP 10.99.198.177 80/TCP?
10.99.198.177 是?kubernetes?的?service ip魄鸦,這個?ip?我們在物理機上看不到宴杀,它是在?iptables?規(guī)則里。
iptables -t nat -L |grep 10.99.198.177
KUBE-MARK-MASQ?tcp -- !10.244.0.0/16 10.99.198.177 /*
default/my-nginx cluster IP */ tcp dpt:http
KUBE-SVC-L65ENXXZWWSAPRCR?tcp -- anywhere 10.99.198.177 /*?
default/my-nginx cluster IP */ tcp dpt:http
#通過上面可以看到之前創(chuàng)建的?service拾因,會通過?kube-proxy?在?iptables?中生成一個規(guī)則旺罢,來實現(xiàn)流量路由,有一系列目標為?KUBE-SVC-xxx?鏈的規(guī)則绢记,每條規(guī)則都會匹配某個目標?ip?與端口扁达。也 就是說訪問某個?ip:port?的請求會由?KUBE-SVC-xxx?鏈來處理。這個目標?IP?其實就是?service ip蠢熄。
Service?服務發(fā)現(xiàn):coredns?組件詳解
DNS?全稱是?Domain Name System:域名系統(tǒng)跪解,是整個互聯(lián)網(wǎng)的電話簿,它能夠將可被人理解的 域名翻譯成可被機器理解?IP?地址签孔,使得互聯(lián)網(wǎng)的使用者不再需要直接接觸很難閱讀和理解的?IP?地址叉讥。域 名系統(tǒng)在現(xiàn)在的互聯(lián)網(wǎng)中非常重要,因為服務器的?IP?地址可能會經(jīng)常變動饥追,如果沒有了?DNS图仓,那么可 能?IP?地址一旦發(fā)生了更改,當前服務器的客戶端就沒有辦法連接到目標的服務器了但绕,如果我們?yōu)?IP?地 址提供一個『別名』并在其發(fā)生變動時修改別名和?IP?地址的關系救崔,那么我們就可以保證集群對外提供的 服務能夠相對穩(wěn)定地被其他客戶端訪。DNS?其實就是一個分布式的樹狀命名系統(tǒng)捏顺,它就像一個去中心化 的分布式數(shù)據(jù)庫六孵,存儲著從域名到?IP?地址的映射。
CoreDNS?其實就是一個?DNS?服務幅骄,而?DNS?作為一種常見的服務發(fā)現(xiàn)手段劫窒,所以很多開源項目 以及工程師都會使用?CoreDNS?為集群提供服務發(fā)現(xiàn)的功能,Kubernetes?就在集群中使用?CoreDNS?解決服務發(fā)現(xiàn)的問題昌执。 作為一個加入?CNCF(Cloud Native Computing Foundation)的服務烛亦,?CoreDNS?的實現(xiàn)非常簡單诈泼。
驗證?coredns
docker load -I dig.tar.gz ? ? ?工作節(jié)點解壓
cat dig.yaml
apiVersion: v1
kind: Pod
metadata:
? name: dig
? namespace: default
spec:
? containers:
? - name: dig
? ? image: god/xianchao/dig:latest
? ? command:
? ? - sleep
? ? - "3600"
? ? imagePullPolicy: IfNotPresent
? restartPolicy: Always
kubectl apply -f dig.yaml
#查看默認名稱空間的?kubernetes?服務
# kubectl get svc | grep kubernetes
kubectl get svc | grep kubernetes
kubernetes? ? ? ? ? ClusterIP? ? ? 10.96.0.1? ? ? ? <none>? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 443/TCP? ? ? ? ? 23
#解析?dns,如有以下返回說明?dns?安裝成功
kubectl exec -it dig -- nslookup kubernetes
Server: 10.96.0.10
Address: 10.96.0.10#53
Name: kubernetes.default.svc.cluster.local Address: 10.96.0.1
kubernetes.default.svc.cluster.local?
服務名.名稱空間.默認后綴
在?k8s?中創(chuàng)建?service?之后煤禽,service?默認的?FQDN?是<service name>.<namespace>.svc.cluster.local铐达,那么?k8s?集群內(nèi)部的服務就可以通過?FQDN?訪問