同样的镜像 在自己环境可以跑起来,放到朋友rancher搭建的环境里就出现了pod的cluster ip+ port可以访问,但是通过service ip+port就无法访问的情况。 后来通过修改svc 模式 cluster ip 到load balance解决。具体出现这个问题的原因,没有去查证。朋友的环境是一主一从,具体环境已经无法验证了。看到这个issue,现象比较相似 记录一下 方便后续自己出现问题的排查。
Calico CNI
ipvs
具体问题描述就是,当 Pod 通过自身 Service IP 访问的时候,如果 kube-proxy 刚好调度的实例是 Pod 自身的话,这个时候就出现无法访问的问题。
排查过程网上搜索的资料都是指向 kubelet --hairpin-mode
配置(https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/troubleshooting-kubeadm/#pods-are-not-accessible-via-their-service-ip
),确认了一下集群中这块配置使用的是默认的配置,默认配置是 promiscuous-bridge
,如果 kubenet 没有开启的话会自动切换配置为 hairpin-veth
模式。以下是默认配置下,kubelet 的启动日志:
Hairpin mode set to "promiscuous-bridge" but kubenet is not enabled, falling back to "hairpin-veth"
Hairpin mode set to "hairpin-veth"
发现不是 kubenet 之后,切换为 hairpin-veth
。觉得问题还是出在 kube-proxy 这块,当前使用的是 ipvs 模式,查看 kube-proxy 启动日志之后,发现一些错误的日志:
Failed to retrieve node info: nodes "xxxxxxx" not found
server_others.go:189] Using ipvs Proxier.
invalid nodeIP, initializing kube-proxy with 127.0.0.1 as nodeIP
使用默认主机名作为节点,但是并没有找到该节点(集群环境统一使用节点 IP 注册的),然后 kube-proxy 又设置 127.0.0.1 作为 nodeIP。怀疑问题出在这一块,通过 --hostname-overwrite
配置实际节点 IP 之后,发现 Pod 通过 Service IP 访问自身恢复正常了。
实际看代码解读:
nodeIP := net.ParseIP(config.BindAddress)
if nodeIP.IsUnspecified() {
nodeIP = utilnode.GetNodeIP(client, hostname)
if nodeIP == nil {
return nil, fmt.Errorf("unable to get node IP for hostname %s", hostname)
}
}
// IsUnspecified reports whether ip is an unspecified address, either
// the IPv4 address "0.0.0.0" or the IPv6 address "::".
func (ip IP) IsUnspecified() bool {
return ip.Equal(IPv4zero) || ip.Equal(IPv6unspecified)
}
先通过 BindAddress 获取节点 IP,如果是未指定的值 (0.0.0.0 || : 则根据主机名获取节点 IP。
// GetNodeIP returns the ip of node with the provided hostname
// If required, wait for the node to be defined.
func GetNodeIP(client clientset.Interface, hostname string) net.IP {
var nodeIP net.IP
backoff := wait.Backoff{
Steps: 5,
Duration: 1 * time.Second,
Factor: 2.0,
Jitter: 0.2,
}
err := wait.ExponentialBackoff(backoff, func() (bool, error) {
node, err := client.CoreV1().Nodes().Get(hostname, metav1.GetOptions{})
if err != nil {
klog.Errorf("Failed to retrieve node info: %v", err)
return false, nil
}
nodeIP, err = GetNodeHostIP(node)
if err != nil {
klog.Errorf("Failed to retrieve node IP: %v", err)
return false, err
}
return true, nil
})
if err == nil {
klog.Infof("Successfully retrieved node IP: %v", nodeIP)
}
return nodeIP
}
如果还是获取不到,则设置 127.0.0.1 为节点 IP
if nodeIP == nil {
klog.Warning("invalid nodeIP, initializing kube-proxy with 127.0.0.1 as nodeIP")
nodeIP = net.ParseIP("127.0.0.1")
}
因此上文只要设置 --bind-address
项应该也是生效的,实测是正常的。不过当前只是把问题解决了,为何 nodeIP 正确获取之后,之前的问题就解决了?答案是未知的… 类似的问题 kubernetes/kubernetes#57518
https://github.com/opskumu/issues/issues/23#issuecomment-547280434
https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/troubleshooting-kubeadm/#pods-are-not-accessible-via-their-service-ip