Service
Pod的IP是在docker0網(wǎng)段動態(tài)分配的,當發(fā)生重啟,擴容等操作時,IP地址會隨之變化。當某個Pod(frontend)需要去訪問其依賴的另外一組Pod(backend)時,如果backend的IP發(fā)生變化時,如何保證fronted到backend的正常通信變的非常重要。由此,引出了Service的概念。
這里docker0是一個網(wǎng)橋,docker daemon啟動container時會根據(jù)docker0的網(wǎng)段來劃粉container的IP地址Docker網(wǎng)絡
在實際生產(chǎn)環(huán)境中,對Service的訪問可能會有兩種來源:Kubernetes集群內(nèi)部的程序(Pod)和Kubernetes集群外部,為了滿足上述的場景,Kubernetes service有以下三種類型:
- ClusterIP:提供一個集群內(nèi)部的虛擬IP以供Pod訪問。
- NodePort:在每個Node上打開一個端口以供外部訪問。
- LoadBalancer:通過外部的負載均衡器來訪問。
ClusterIP && NodePort && LoadBalancer
1. ClusterIP
此模式會提供一個集群內(nèi)部的虛擬IP(與Pod不在同一網(wǎng)段),以供集群內(nèi)部的pod之間通信使用。
ClusterIP也是Kubernetes service的默認類型。

為了實現(xiàn)圖上的功能主要需要以下幾個組件的協(xié)同工作
- apiserver 用戶通過kubectl命令向apiserver發(fā)送創(chuàng)建service的命令,apiserver接收到請求以后將數(shù)據(jù)存儲到etcd中。
- kube-proxy kubernetes的每個節(jié)點中都有一個叫做kube-proxy的進程,這個進程負責感知service,pod的變化,并將變化的信息寫入本地的iptables中。
- iptables 使用NAT等技術將virtualIP的流量轉至endpoint中。
下面我們實際發(fā)布一個Service,能夠更清晰的了解到Service是如何工作的。
1.1 發(fā)布一個rc,并指定replices count為3.
yancey@ yancey-macbook kubernetes-1$kubectl create -f rc_nginx.yaml
yancey@ yancey-macbook kubernetes-1$kubectl get pods
NAME READY STATUS RESTARTS AGE
k8s-master-core-v2-01 4/4 Running 0 8m
k8s-proxy-core-v2-01 1/1 Running 0 8m
nginx-controller-6bovu 1/1 Running 0 4m
nginx-controller-iowux 1/1 Running 0 4m
nginx-controller-o7m6u 1/1 Running 0 4m
yancey@ yancey-macbook kubernetes-1$kubectl describe pod nginx-controller-6bovu
Name: nginx-controller-6bovu
Namespace: default
Node: core-v2-01/172.17.8.101
Start Time: Fri, 17 Jun 2016 15:22:20 +0800
Labels: app=nginx
Status: Running
IP: 10.1.13.3
Controllers: ReplicationController/nginx-controller
1.2. 發(fā)布一個service,并指定步驟1中的label。
yancey@ yancey-macbook kubernetes-1$kubectl create -f service_nginx.yaml
yancey@ yancey-macbook kubernetes-1$kubectl get svc
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes 10.0.0.1 <none> 443/TCP 9m
nginx-service 10.0.0.252 <none> 8000/TCP 4m
kubernetes為nginx-server這個service創(chuàng)建了一個10.0.0.252這個ClusterIP,也可以稱為VirtualIP.
yancey@ yancey-macbook kubernetes-1$kubectl get ep
NAME ENDPOINTS AGE
kubernetes 172.17.8.101:6443 9m
nginx-service 10.1.13.2:80,10.1.13.3:80,10.1.13.4:80 4m
查看endpoint信息,發(fā)現(xiàn)nginx-service一共有三個endpoint地址,分別對應nginx的三個pod。
1.3. 查看iptables,觀察其NAT表中的信息(只截取了部分和這個service有關的信息)
查看iptables中NAT表的命令:iptables -L -v -n -t nat
Chain PREROUTING (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
37 2766 KUBE-SERVICES all -- * * 0.0.0.0/0 0.0.0.0/0 /* kubernetes service portals */
33 2112 DOCKER all -- * * 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
在PREROUTING鏈中會先匹配到KUBE-SERVICES這個Chain。
Chain KUBE-SERVICES (2 references)
pkts bytes target prot opt in out source destination
0 0 KUBE-SVC-GKN7Y2BSGW4NJTYL tcp -- * * 0.0.0.0/0 10.0.0.252 /* default/nginx-service: cluster IP */ tcp dpt:8000
18 1080 KUBE-NODEPORTS all -- * * 0.0.0.0/0 0.0.0.0/0 /* kubernetes service nodeports; NOTE: this must be the last rule in this chain */ ADDRTYPE match dst-type LOCAL
所有destinationIP為10.0.0.252的包都轉到KUBE-SVC-GKN7Y2BSGW4NJTYL這個Chain
Chain KUBE-SVC-GKN7Y2BSGW4NJTYL (1 references)
pkts bytes target prot opt in out source destination
0 0 KUBE-SEP-7ROBBXFV7SD4AIRW all -- * * 0.0.0.0/0 0.0.0.0/0 /* default/nginx-service: */ statistic mode random probability 0.33332999982
0 0 KUBE-SEP-XY3F6VJIZ7ELIF4Z all -- * * 0.0.0.0/0 0.0.0.0/0 /* default/nginx-service: */ statistic mode random probability 0.50000000000
0 0 KUBE-SEP-JIDZHFC4A3T535AK all -- * * 0.0.0.0/0 0.0.0.0/0 /* default/nginx-service: */
這里能看到請求會平均執(zhí)行KUBE-SEP-7ROBBXFV7SD4AIRW,KUBE-SEP-XY3F6VJIZ7ELIF4Z,KUBE-SEP-XY3F6VJIZ7ELIF4Z這三個Chain.最后我們看下KUBE-SEP-7ROBBXFV7SD4AIRW這個Chain做了什么
Chain KUBE-SEP-7ROBBXFV7SD4AIRW (1 references)
pkts bytes target prot opt in out source destination
0 0 KUBE-MARK-MASQ all -- * * 10.1.13.2 0.0.0.0/0 /* default/nginx-service: */
0 0 DNAT tcp -- * * 0.0.0.0/0 0.0.0.0/0 /* default/nginx-service: */ tcp to:10.1.13.2:80
這個Chain使用了DNAT規(guī)則將流量轉發(fā)到10.1.13.2:80這個地址。至此從Pod發(fā)出來的流量通過本地的iptables將流量轉至了service背后的pod上。
2. NodePort
Kubernetes將會在每個Node上打開一個端口并且每個Node的端口都是一樣的,通過<NodeIP>:NodePort的方式Kubernetes集群外部的程序可以訪問Service。
修改kubernetes/service_nginx.yaml,將Service的type改為NodePort類型。
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
type: NodePort
ports:
- port: 8000
targetPort: 80
protocol: TCP
# just like the selector in the replication controller,
# but this time it identifies the set of pods to load balance
# traffic to.
selector:
app: nginx
發(fā)布這個service,可以看到已經(jīng)隨機分配了一個NodePort端口。
yancey@ yancey-macbook kubernetes-1$kubectl get svc nginx-service -o yaml
apiVersion: v1
kind: Service
metadata:
creationTimestamp: 2016-06-18T03:29:42Z
name: nginx-service
namespace: default
resourceVersion: "1405"
selfLink: /api/v1/namespaces/default/services/nginx-service
uid: e50ba23a-3504-11e6-a94f-080027a75e9e
spec:
clusterIP: 10.0.0.229
ports:
- nodePort: 30802
port: 8000
protocol: TCP
targetPort: 80
selector:
app: nginx
sessionAffinity: None
type: NodePort
status:
loadBalancer: {}
觀察Iptables中的變化,KUBE-NODEPORTS這個Chain中增加了如下內(nèi)容
Chain KUBE-NODEPORTS (1 references)
pkts bytes target prot opt in out source destination
0 0 KUBE-MARK-MASQ tcp -- * * 0.0.0.0/0 0.0.0.0/0 /* default/nginx-service: */ tcp dpt:30802
0 0 KUBE-SVC-GKN7Y2BSGW4NJTYL tcp -- * * 0.0.0.0/0 0.0.0.0/0 /* default/nginx-service: */ tcp dpt:30802
可以看到流量會轉至KUBE-SVC-GKN7Y2BSGW4NJTYL這個Chain中處理一次,也就是ClusterIP中提到的通過負載均衡將流量平均分配到3個endpoint上。
3. LoadBalancer
待補充。
服務發(fā)現(xiàn)
當發(fā)布一個服務之后,我們要使用這個服務,第一個問題就是要拿到這些服務的IP和PORT,kubernetes提供兩種方式以便在程序中去動態(tài)的獲取這些信息。
- ENV環(huán)境變量
在Pod其中之后,kubernetes會將現(xiàn)有服務的IP,PORT以環(huán)境變量的方式寫入pod中,程序只要讀取這些環(huán)境變量即可。 - DNS,程序中可以使用server的名稱對服務進行訪問,在程序啟時候,不必預先讀取環(huán)境變量中的內(nèi)容。
這是兩種方式的詳細說明:http://kubernetes.io/docs/user-guide/services/#discovering-services