[kubernetes]-Pod无法通过 Service IP 访问自身

Pod 无法通过 Service IP 访问自身

同样的镜像 在自己环境可以跑起来,放到朋友rancher搭建的环境里就出现了pod的cluster ip+ port可以访问,但是通过service ip+port就无法访问的情况。 后来通过修改svc 模式 cluster ip 到load balance解决。具体出现这个问题的原因,没有去查证。朋友的环境是一主一从,具体环境已经无法验证了。看到这个issue,现象比较相似 记录一下 方便后续自己出现问题的排查。

以下是借鉴的案例

  • 网络环境:Calico CNI
  • kube-proxy 模式: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

你可能感兴趣的:(kubernetes)