因为Pod的IP是不固定的,所以Kubernetes需要Service,除此之外它还可以在多个Pod间负载均衡
Service的访问入口,其实是宿主机的kube-proxy生成的iptables规则 ,及kube-dns生成的DNS记录
Service通过label标签选中Pod,被选中的的Pod称为Service的Endpoints
示例如下
# kubectl get ep hostnames
NAME ENDPOINTS AGE
hostnames 10.244.0.241:9376,10.244.0.242:9376,10.244.0.243:9376 20m
可以看到,当我们访问hostnames这个service时,会被定位到10.244.0.241:9376,10.244.0.242:9376,10.244.0.243:9376
注意:只有处于Running状态,且readlinessProbe检查通过的Pod,才会出现在Endpoints列表里
我们再查看servcie
# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hostnames ClusterIP 10.111.15.33 80/TCP 23m
service列表的VIP(ClusterIP),是设置了一个固定的入口地址,并没有真正的网络设备,ping是没有响应的
通过访问10.111.15.33,就可以访问到它所代理的Pod了
Service的实现原理是由kube-proxy组件,加上iptables来共同实现的,当提交service后,会创建这样一条iptables规则
-A KUBE-SERVICES -d 10.111.15.33/32 -p tcp -m comment --comment "default/hostnames: cluster IP" -m tcp --dport 80 -j KUBE-SVC-NWV5X2332I4OT4T3
iptables规则 的含义是:凡是上的地址是10.111.15.33、目的端口是80的IP包,都会跳转到KUBE-SVC-NWV5X2332I4OT4T3的iptables链处理
KUBE-SVC-NWV5X2332I4OT4T3是一组集合,如下
-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-WNBA2IHDGP2BOBGZ
-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-X3P2623AGDH6CDF3
-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -j KUBE-SEP-57KPRZ3JQVENLNBR
这是一组随机模式的iptables链,这三条链是DNAT规则,三条链指向的最终目的地是Service代理的三个Pod
iptables规则的匹配是从上到下逐条进行的,为了让每条概率都相同,probability分别被设置成了1/3、1/2和1
当访问Service的VIP的IP包经过上述iptables处理后,就变成了访问具体某一个后端Pod的IP包了,这些Endpoints对应的规则,是kube-proxy通过监听Pod的变化事件,在宿主机上生成并的维护
示例yaml
apiVersion: v1
kind: Service
metadata:
name: my-nginx
labels:
run: my-nginx
spec:
type: NodePort
ports:
- nodePort: 8080
targetPort: 80
protocol: TCP
name: http
- nodePort: 443
protocol: TCP
name: https
selector:
run: my-nginx
访问方式: <任何一台宿主机的ip地址> :8080 任何一台宿主机的ip地址>
宿主机上没有任何一个代理的Pod存在,不能直接访问通过IP访问Pod,只能由宿主机转发
示例yaml
kind: Service
apiVersion: v1
metadata:
name: example-service
spec:
ports:
- port: 8765
targetPort: 9376
selector:
app: example
type: LoadBalancer
K8S使用了一个CloudProvier转接层,跟公有云api对拉,当LoadBalancer的Service被提交后,
K8S会在公有云创建一个负载均衡服务,把代理的Pod地址代理给负载均衡后端
示例yaml
kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
type: ExternalName
externalName: my.database.example.com
不需要label选择,相当于在kube-dns里添加了一条CNAME记录
访问my-servcie.default.svc.cluster.locl和访问my.database.example.com一样
另外,还允许配置公有IP地址
kind: Service
apiVersion: v1
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- name: http
protocol: TCP
port: 80
targetPort: 9376
externalIPs:
- 80.11.12.10
在一个 Pod 里执行nslookup排查
$ nslookup kubernetes.default
Server: 10.0.0.10
Address 1: 10.0.0.10 kube-dns.kube-system.svc.cluster.local
Name: kubernetes.default
Address 1: 10.0.0.1 kubernetes.default.svc.cluster.local
检查这个Service的Endpoints
kubectl get endpoints hostnames
NAME ENDPOINTS
hostnames 10.244.0.5:9376,10.244.0.6:9376,10.244.0.7:9376
如果Pod的readniessProbe没通过,不会出现在Endpoints列表
如果Endpoints正常,再确认kube-proxy和宿主机的iptables是否正常