--昨夜西风凋碧树,独上高楼,望尽天涯路
-
问题
当通过Kubernetes部署微服务的时候,发现Spring Cloud配置文件中配置的外部数据库链接无法访问(数据库在其他不受k8s控制的服务器,以及配置的ip是内网ip)。通过docker exec进入容器内部访问数据库ip,发现无法访问:
-
原因分析
这是由于部署Kubernetes的时候大多使用flannel或者calico插件带来的解决方案,这种扁平化的解决方案使得所有的pod之间可以相互通信(可以跨主机哦)。每个容器相当于一个endpoint(可以理解为虚拟网卡),这些endpoint向flannel传送包,flannel在做分发和处理。但是当通过容器内部连接其他服务器的内网的时候是不可达的。
我们继续在容器内部ping 数据库的内网,之后新开一个窗口通过tcpdump命令追踪cni0发包(cni0可以理解为类似eth0):
发现根本没有响应。
-
解决方案
基于上述情况,Kubernetes提供了Endpoint方式方式来访问外部服务。大致做法就是定义一对匹配的endpoint和service,Service负责Pod和外部网络的交互,Endpoint连接Service和外部服务,配置如下:
Endpoint:
apiVersion: v1
kind: Endpoints
metadata:
name: mysql-service #必须和对应的Service一样
subsets:
- addresses:
- ip: 10.10.14.21 #数据库内网地址
ports:
- port: 3306 #数据库端口
protocol: TCP
Service:
apiVersion: v1
kind: Service
metadata:
name: mysql-service #service name 必须和endpoint name 一致
spec:
clusterIP: 10.106.106.106 #自定义暴露的Ip 在spring cloud配置文件中填写该ip
ports:
- port: 3306 #service ip
targetPort: 3306 #与endpoint对应的ip
protocol: TCP
Spring Cloud配置如下:
所以大致流程为:加载Spring Cloud配置文件的时候会通过配置的Kubernetes ServiceIP来打通一条网络,之后Kubernetes Service通过与之匹配的Endpoint来访问远程服务