- 作者:HoPGoldy
- 链接:https://www.jianshu.com/p/ed1ae8443fff
问题描述
有两个(或多个)运行在不同节点上的pod
,通过一个svc
提供服务,如下:
1 | root@master1:~# kubectl get pod -o wide |
当透过其他pod
访问该svc
时(使用命令kubectl exec kubia-nwjcc -- curl http://10.98.41.49
),出现了只能访问到和自己同处于一个节点的pod
的问题,访问到其他节点上的pod
时会出现command terminated with exit code 7
的问题,如下:
正常访问到相同节点的pod
1 | root@master1:~# kubectl exec kubia-nwjcc -- curl http://10.98.41.49 |
无法访问其他节点的pod
1 | root@master1:~# kubectl exec kubia-nwjcc -- curl http://10.98.41.49 |
本问题随机发生,如下:
1 | root@master1:~# kubectl exec kubia-nwjcc -- curl http://10.98.41.49 |
问题原因
原因是因为,我是用的VirtualBox
虚拟化出了两台 ubuntu 主机搭建的 k8s ,详见 virtualbox 虚拟机组网 。在组网的过程中,我采用了双网卡方案,网卡1使用NAT地址转换用来访问互联网,网卡2使用Host-only
来实现虚拟机互相访问。flannel
默认使用了网卡1的 ip 地址,而网卡1的NAT地址转换是无法访问其他虚拟机的,从而导致的问题的产生。
解决方案
因为是flannel
使用的默认网卡1导致了这个问题的产生,所以我们需要使用--iface
参数手动指定它使用网卡2来进行通信,这就需要修改flannel
的配置文件,执行如下命令即可进行修改:
1 | $ sudo kubectl edit daemonset kube-flannel-ds-amd64 -n kube-system |
如果你执行后出现了Error from server (NotFound): daemonsets.extensions "kube-flannel-ds-amd64" not found
的问题,按照下列步骤找到其配置文件名称:
查找flannel
配置文件名
首先输入kubectl get po -n kube-system
,然后找到正在运行的flannel
pod。
1 | root@master1:~# kubectl get po -n kube-system |
然后使用flannel
的 pod 名来查看其配置yaml
。使用命令kubectl get po -n kube-system kube-flannel-ds-amd64-8c2lc -o yaml
,注意修改其中的 pod 名称。在输出的内容开头可以找到ownerReferences
字段,其下的name
属性就是要找的配置文件名。如下:
1 | root@master1:~# kubectl get po -n kube-system kube-flannel-ds-amd64-8c2lc -o yaml |
将找到的配置文件名填入sudo kubectl edit daemonset <配置文件名> -n kube-system
并执行即可打开配置文件。
修改配置文件,指定目标网卡
在打开的配置文件中找到spec.template.spec.containers[0].args
字段,如下:
1 | ... |
这个字段表示了flannel
启动时都要附加那些参数,我们要手动添加参数--iface=网卡名
来进行指定,如下:
1 | - args: |
这里的enp0s8
是我的网卡名,你可以通过ifconfig
来找到自己的网卡名。
修改完成之后输入:wq
保存退出。命令行会提示:
1 | daemonset.extensions/kube-flannel-ds-amd64 edited |
这就说明保存成功了。然后就要重启所有已经存在的flannel
。使用kubectl delete pod -n kube-system <pod名1> <pod名2> ...
把所有的flannel
删除即可。k8s 会自动按照你修改好的yaml
配置重建flannel
。
1 | root@master1:~# kubectl delete pod -n kube-system \ |
然后再次kubectl get pod -n kube-system | grep flannel
就发现所有flannel
都已经重启成功了:
1 | root@master1:~# kubectl get pod -n kube-system | grep flannel |
然后再随便找个pod
试一下就可以看到问题解决了:
1 | root@master1:~# k exec kubia-d7kjl -- curl -s http://10.103.214.110 |
问题发现
这里记录一下问题的发现经过,希望对大家有所帮助。当我一开始遇到这个问题的时候还以为是svc
的问题,但是在查看了对应svc
的endpoint
之后,并没有发现有什么显式的问题出现,如下,可以看到svc
正确的识别到了已存在的两个pod
:
1 | root@master1:~# kubectl get ep kubia |
什么是
endpoint
?
endpoint
可以简单理解成路由导向的终点,因为 svc 是将许多个动态的 ip 映射成一个静态的 ip。那么就可以把这些动态的 pod ip 称为 svc 的endpoint
。
继续说,因为在测试过程中向 svc 发了很多请求,也可以察觉到其实 svc 已经随机的将你的请求分发到了不同的 pod,只是目标 pod 不在当前节点的时候就会返回exit code 7
。然后尝试一下绕过 svc 直接请求 pod,首先新建出来一个 pod,然后使用kubectl get po -o wide
查看 pod ip。
1 | root@master1:~# kubectl get po -o wide |
可以看到 k8s 把新的 pod 放在了worker1
上,所以我们就拿这个新的 pod 去直接访问其他两个 pod。这里不能在主机上直接 ping
pod ip,因为 pod 都是开放在虚拟网络10.244.x.x
上的,在主机上访问不到:
访问相同节点上的 pod
1 | root@master1:~# k exec -it kubia-d7kjl -- ping 10.244.1.6 |
访问不同节点上的 pod
1 | root@master1:~# k exec -it kubia-d7kjl -- ping 10.244.3.4 |
这么看的话其实问题不在svc
上,而是两个节点之间的网络联通出现了问题。而10.244.x.x
虚拟网段是通过flannel
搭建的,所以问题自然就是出在它上。在翻阅了官方文档后可以发现,官方明确指出了在vagrant
类型的虚拟机上运行时要注意默认网卡的问题,再结合自己的网络情况,问题就已经很明确了了。
参考
- flannel - Troubleshooting
- Kubernetes with Flannel — Understanding the Networking — Part 1 (Setup the demo).
- k8s svc can not find pod in other worker node
---本文结束感谢您的阅读。微信扫描二维码,关注我的公众号---
本文链接: https://www.yp14.cn/2020/03/12/解决k8s无法通过svc访问其他节点pod的问题/
版权声明: 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。转载请注明出处!