今天排查一个在kubernetes集群中访问svc时出现的Connection refused
的问题,比较奇怪
现象
背景是: 由于项目关系,需要从一个k8s环境中把yaml文件导入到一个全新的k8s环境, 导入之后发现有些service在应用间访问不通
1 | telnet mongodb-mst.external 27017 |
排查
首先排除了域名、端口的配置问题。
可以确定的是集群内的DNS是正常的.
提示连接拒绝那么就是通过clusterIP无法到达realserver. 查看iptables规则
发现提示default has no endpoints --reject-with icmp-port-unreachable
很奇怪, 提示没有endpoints, 但是使用kubectl get ep
又能看到ep存在且配置没有问题
而且这个default是怎么来的.
为了方便部署, 很多配置是从别的环境导出的配置, 有些service访问是没问题的, 只有少部分connection refused
结比一下发现一个很有趣的问题,先来看下不正常的yaml文件:
由于服务在集群外部署的, 因此这里使用了subset方式, 开始怀疑问题在这里, 但是后来知道这个不是重点
乍一看这个配置没什么问题, 部署也很正常, 但是对比正常的yaml文件,发现一个区别:
如果在services中的端口指定了名字, 那么在subsets中的端口也要带名字, 没有带名字的就会出现connection refused
,这个确实之前从来没有关注过, 一个端口的情况下也不会指定名字
而且这面iptalbes中提示的default刚好就是这里的port name,虽然不敢相信,但是也只能试一试这个方法: 在subsets中也加了port name
重新部署一个,再次查看iptalbes规则
iptables-save|grep mongodb-mst
OMG, 居然可行, 再看下telnet的结果:
1 | Trying 10.105.116.92... |
访问也是没问题,
结果
那么结果很明显了:
在service中指定了port name时, 也需要在ep中指定同样的port name
这是为什么呢?
查看文档
1 | # ServicePort v1 core |
提到了在不止一个端口时, svc的port name 需要与endpointport name保持一致.
源码里也会对比端口名字.
1 | func (cache *EndpointSliceCache) endpointInfoByServicePort(serviceNN types.NamespacedName, sliceInfoByName endpointSliceInfoByName) spToEndpointMap { |
主要是这个端口的名称平时也不怎么在意, 没想到有坑