一、Service
對(duì)于kubernetes整個(gè)集群來(lái)說(shuō),Pod的地址也可變的,也就是說(shuō)如果一個(gè)Pod因?yàn)槟承┰蛲顺隽耍捎谄湓O(shè)置了副本數(shù)replicas大于1,那么該P(yáng)od就會(huì)在集群的任意節(jié)點(diǎn)重新啟動(dòng),這個(gè)重新啟動(dòng)的Pod的IP地址與原IP地址不同,這對(duì)于業(yè)務(wù)來(lái)說(shuō),就不能根據(jù)Pod的IP作為業(yè)務(wù)調(diào)度。kubernetes就引入了Service的概念,它為Pod提供一個(gè)入口,主要通過(guò)Labels標(biāo)簽來(lái)選擇后端Pod,這時(shí)候不論后端Pod的IP地址如何變更,只要Pod的Labels標(biāo)簽沒(méi)變,那么 業(yè)務(wù)通過(guò)service調(diào)度就不會(huì)存在問(wèn)題。
當(dāng)聲明Service的時(shí)候,會(huì)自動(dòng)生成一個(gè)cluster IP,這個(gè)IP是虛擬IP。我們就可以通過(guò)這個(gè)IP來(lái)訪問(wèn)后端的Pod,當(dāng)然,如果集群配置了DNS服務(wù),比如現(xiàn)在的CoreDNS,那么也可以通過(guò)Service的名字來(lái)訪問(wèn),它會(huì)通過(guò)DNS自動(dòng)解析Service的IP地址。
Service的模式有三種,user space,iptables,ipvs。
Service的類型有三種,Cluster IP,LoadBalance,NodePort,ExternalName。其中Cluster IP是默認(rèn)的類型。
(1)、Cluster IP:通過(guò) 集群內(nèi)部IP暴露服務(wù),默認(rèn)是這個(gè)類型,選擇該值,這個(gè)Service服務(wù)只能通過(guò)集群內(nèi)部訪問(wèn);
(2)、LoadBalance:使用云提供商的負(fù)載均衡器,可以向外部暴露服務(wù),選擇該值,外部的負(fù)載均衡器可以路由到NodePort服務(wù)和Cluster IP服務(wù);
(3)、NodePort:顧名思義是Node基本的Port,如果選擇該值,這個(gè)Service可以通過(guò)NodeIP:NodePort訪問(wèn)這個(gè)Service服務(wù),NodePort會(huì)路由到Cluster IP服務(wù),這個(gè)Cluster IP會(huì)通過(guò)請(qǐng)求自動(dòng)創(chuàng)建;
(4)、ExternalName:通過(guò)返回 CNAME 和它的值,可以將服務(wù)映射到 externalName 字段的內(nèi)容,沒(méi)有任何類型代理被創(chuàng)建,可以用于訪問(wèn)集群內(nèi)其他沒(méi)有Labels的Pod,也可以訪問(wèn)其他NameSpace里的Service。
kubernetes主要通過(guò)kube-proxy創(chuàng)建iptables和ipvs規(guī)則,在每個(gè)Node節(jié)點(diǎn)上都會(huì)創(chuàng)建這些規(guī)則。
1.1、Cluster IP
集群默認(rèn)的Service類型,只能在集群內(nèi)部訪問(wèn),一個(gè)簡(jiǎn)單的Service定義如下:
apiVersion: v1 # API版本
kind: Service # 聲明版本為Service
metadata: # 元數(shù)據(jù)
name: nginx-service # 定義Service的名字
labels: # 定義Service的標(biāo)簽
name: nginx-service
spec:
type: ClusterIP # 定義Service的類型
selector: # 定義標(biāo)簽選擇器,會(huì)代理后端name=nginx-service的Pod
name: nginx-service
ports: # 暴露的端口名
- port: 8000
然后通過(guò)kubectl get svc可以看到Cluster IP
可以通過(guò)容器內(nèi)訪問(wèn):
1.2、NodePort
暴露端口到Node節(jié)點(diǎn),可以通過(guò)Node節(jié)點(diǎn)訪問(wèn)容器。<br />如果設(shè)置 type 的值為 "NodePort",Kubernetes master 將從給定的配置范圍內(nèi)(默認(rèn):30000-32767)分配端口,每個(gè) Node 將從該端口(每個(gè) Node 上的同一端口)代理到 Service。該端口將通過(guò) Service 的 spec.ports[*].nodePort 字段被指定,如果不指定的話會(huì)自動(dòng)生成一個(gè)端口。
需要注意的是,Service 將能夠通過(guò) :spec.ports[].nodePort 和 spec.clusterIp:spec.ports[].port 而對(duì)外可見(jiàn)。
一個(gè)簡(jiǎn)單的Service定義如下:
apiVersion: v1 # API版本
kind: Service # 聲明版本為Service
metadata: # 元數(shù)據(jù)
name: nginx-service # 定義Service的名字
labels: # 定義Service的標(biāo)簽
name: nginx-service
spec:
type: NodePort # 定義Service的類型
selector: # 定義標(biāo)簽選擇器,會(huì)代理后端name=nginx-service的Pod
name: nginx-service
ports: # 暴露的端口名
- port: 8000
然后通過(guò)kubectl get svc可以看到剛才創(chuàng)建的NodePort。
可以通過(guò)容器內(nèi)訪問(wèn):
也可以通過(guò)外部訪問(wèn):
1.3、LoadBalance
需要云提供商支撐。
比如:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
clusterIP: 10.0.171.239
loadBalancerIP: 78.11.24.19
type: LoadBalancer
status:
loadBalancer:
ingress:
- ip: 146.148.47.155
1.4、ExternalName
ExternalName 是 Service 的特例,它沒(méi)有 selector,也沒(méi)有定義任何的端口和 Endpoint。 對(duì)于運(yùn)行在集群外部的服務(wù),它通過(guò)返回該外部服務(wù)的別名這種方式來(lái)提供服務(wù)。
例如:
kind: Service
apiVersion: v1
metadata:
name: my-service
namespace: prod
spec:
type: ExternalName
externalName: my.database.example.com
當(dāng)查詢主機(jī) my-service.prod.svc.cluster.local (后面服務(wù)發(fā)現(xiàn)的時(shí)候我們會(huì)再深入講解)時(shí),集群的 DNS 服務(wù)將返回一個(gè)值為 my.database.example.com 的 CNAME 記錄。 訪問(wèn)這個(gè)服務(wù)的工作方式與其它的相同,唯一不同的是重定向發(fā)生在 DNS 層,而且不會(huì)進(jìn)行代理或轉(zhuǎn)發(fā)。 如果后續(xù)決定要將數(shù)據(jù)庫(kù)遷移到 Kubernetes 集群中,可以啟動(dòng)對(duì)應(yīng)的 Pod,增加合適的 Selector 或 Endpoint,修改 Service 的 type,完全不需要修改調(diào)用的代碼,這樣就完全解耦了。
二、Headless Service
上面的Service都是有IP的,也就是說(shuō)如果在Kubernetes集群中配置了DNS,解析ServeiceName得到的是ClusterIP,那Headless Service是什么呢?顧名思義是無(wú)頭服務(wù),無(wú)頭在這里就是沒(méi)有IP的意思,YAML文件定義也很簡(jiǎn)單,就是ClusterIP設(shè)置為None。
官方信息為:
"None" can be specified for headless services when proxying is not required.
我們來(lái)定義一個(gè)YAML文件:<br />nginx-headless-service.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-headless-service
labels:
name: nginx-headless-service
spec:
clusterIP: None
selector:
name: nginx-service
ports:
- port: 8000
targetPort: 80
然后創(chuàng)建SVC:
# kubectl apply -f nginx-headless-service.yaml
service/nginx-headless-service created
查看SVC:
# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.68.0.1 <none> 443/TCP 4d18h
nginx-headless-service ClusterIP None <none> 8000/TCP 4s
我們可以看到nginx-headless-service中CLUSTER-IP這一列為None,那么現(xiàn)在我們通過(guò)ServiceName解析會(huì)得到什么?<br />我們用dig命令來(lái)解析一下:
[root@master service]# dig -t a nginx-headless-service.default.svc.cluster.local. @10.68.0.2
; <<>> DiG 9.11.4-P2-RedHat-9.11.4-9.P2.el7 <<>> -t a nginx-headless-service.default.svc.cluster.local. @10.68.0.2
;; global options: +cmd
;; Got answer:
;; WARNING: .local is reserved for Multicast DNS
;; You are currently testing what happens when an mDNS query is leaked to DNS
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 15647
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;nginx-headless-service.default.svc.cluster.local. IN A
;; ANSWER SECTION:
nginx-headless-service.default.svc.cluster.local. 5 IN A 172.20.2.84
;; Query time: 1 msec
;; SERVER: 10.68.0.2#53(10.68.0.2)
;; WHEN: Mon Sep 09 12:04:55 CST 2019
;; MSG SIZE rcvd: 141
可以看到解析得地址是Pod得地址,如果沒(méi)有dig命令,可以使用以下命令安裝:
yum install bind-utils -y
所以Headless Service類型得Service解析的Pod的IP地址,常用在statefulSet中。
公眾號(hào):?jiǎn)踢吂适拢↖D:qiaobiangushi)
知乎: 喬邊故事
頭條號(hào):?jiǎn)踢吂适?/p>
只要臉皮夠厚,整個(gè)世界都將被你踩在腳下。
感謝您的閱讀,歡迎轉(zhuǎn)發(fā)!