Z.S.K.'s Records

Kubernetes学习(排查访问service时提示Connection refused)

今天排查一个在kubernetes集群中访问svc时出现的Connection refused的问题,比较奇怪

现象

背景是: 由于项目关系,需要从一个k8s环境中把yaml文件导入到一个全新的k8s环境, 导入之后发现有些service在应用间访问不通

1
2
3
telnet mongodb-mst.external 27017
Trying 10.97.135.242...
telnet: Unable to connect to remote host: Connection refused

排查

首先排除了域名、端口的配置问题。

可以确定的是集群内的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
2
3
Trying 10.105.116.92...
Connected to mongodb-mst.external.svc.cluster.local.
Escape character is '^]'.

访问也是没问题,

结果

那么结果很明显了:

在service中指定了port name时, 也需要在ep中指定同样的port name

这是为什么呢?

查看文档

1
2
# ServicePort v1 core
The name of this port within the service. This must be a DNS_LABEL. All ports within a ServiceSpec must have unique names. This maps to the 'Name' field in EndpointPort objects. Optional if only one ServicePort is defined on this service

提到了在不止一个端口时, svc的port name 需要与endpointport name保持一致.

源码里也会对比端口名字.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
func (cache *EndpointSliceCache) endpointInfoByServicePort(serviceNN types.NamespacedName, sliceInfoByName endpointSliceInfoByName) spToEndpointMap {
endpointInfoBySP := spToEndpointMap{}

for _, sliceInfo := range sliceInfoByName {
for _, port := range sliceInfo.Ports {
if port.Name == nil {
klog.Warningf("ignoring port with nil name %v", port)
continue
}
// TODO: handle nil ports to mean "all"
if port.Port == nil || *port.Port == int32(0) {
klog.Warningf("ignoring invalid endpoint port %s", *port.Name)
continue
}

svcPortName := ServicePortName{
NamespacedName: serviceNN,
Port: *port.Name,
Protocol: *port.Protocol,
}

endpointInfoBySP[svcPortName] = cache.addEndpointsByIP(serviceNN, int(*port.Port), endpointInfoBySP[svcPortName], sliceInfo.Endpoints)
}
}

return endpointInfoBySP
}

主要是这个端口的名称平时也不怎么在意, 没想到有坑

参考文章:

转载请注明原作者: 周淑科(https://izsk.me)

 wechat
Scan Me To Read on Phone
I know you won't do this,but what if you did?