問題描述
有兩個(或多個)運行在不同節(jié)點上的pod
基括,通過一個svc
提供服務(wù),如下:
root@master1:~# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
kubia-nwjcc 1/1 Running 0 33m 10.244.1.27 worker1
kubia-zcpbb 1/1 Running 0 33m 10.244.2.11 worker2
root@master1:~# kubectl get svc kubia
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubia ClusterIP 10.98.41.49 <none> 80/TCP 34m
當透過其他pod
訪問該svc
時(使用命令k exec kubia-nwjcc -- curl http://10.98.41.49
)年堆,出現(xiàn)了只能訪問到和自己同處于一個節(jié)點的pod
的問題,訪問到其他節(jié)點上的pod
時會出現(xiàn)command terminated with exit code 7
的問題盏浇,如下:
正常訪問到相同節(jié)點的pod
root@master1:~# kubectl exec kubia-nwjcc -- curl http://10.98.41.49
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 23 0 23 0 0 8543 0 --:--:-- --:--:-- --:--:-- 11500
You've hit kubia-nwjcc
無法訪問其他節(jié)點的pod
root@master1:~# kubectl exec kubia-nwjcc -- curl http://10.98.41.49
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
curl: (7) Failed to connect to 10.98.41.49 port 80: No route to host
command terminated with exit code 7
本問題隨機發(fā)生变丧,如下:
root@master1:~# kubectl exec kubia-nwjcc -- curl http://10.98.41.49
You've hit kubia-nwjcc
root@master1:~# kubectl exec kubia-nwjcc -- curl http://10.98.41.49
command terminated with exit code 7
root@master1:~# kubectl exec kubia-nwjcc -- curl http://10.98.41.49
command terminated with exit code 7
root@master1:~# kubectl exec kubia-nwjcc -- curl http://10.98.41.49
You've hit kubia-nwjcc
問題原因
原因是因為,我是用的VirtualBox
虛擬化出了兩臺 ubuntu 主機搭建的 k8s 绢掰,詳見 virtualbox 虛擬機組網(wǎng) 痒蓬。在組網(wǎng)的過程中,我采用了雙網(wǎng)卡方案滴劲,網(wǎng)卡1使用NAT地址轉(zhuǎn)換用來訪問互聯(lián)網(wǎng)攻晒,網(wǎng)卡2使用Host-only
來實現(xiàn)虛擬機互相訪問。flannel
默認使用了網(wǎng)卡1的 ip 地址哑芹,而網(wǎng)卡1的NAT地址轉(zhuǎn)換是無法訪問其他虛擬機的,從而導(dǎo)致的問題的產(chǎn)生捕透。
解決方案
因為是flannel
使用的默認網(wǎng)卡1導(dǎo)致了這個問題的產(chǎn)生聪姿,所以我們需要使用--iface
參數(shù)手動指定它使用網(wǎng)卡2來進行通信碴萧,這就需要修改flannel
的配置文件,執(zhí)行如下命令即可進行修改:
sudo kubectl edit daemonset kube-flannel-ds-amd64 -n kube-system
如果你執(zhí)行后出現(xiàn)了Error from server (NotFound): daemonsets.extensions "kube-flannel-ds-amd64" not found
的問題末购,按照下列步驟找到其配置文件名稱:
查找flannel
配置文件名
首先輸入kubectl get po -n kube-system
破喻,然后找到正在運行的flannel
pod。
root@master1:~# k get po -n kube-system
NAME READY STATUS RESTARTS AGE
coredns-bccdc95cf-69zrw 1/1 Running 1 2d1h
coredns-bccdc95cf-77bg4 1/1 Running 1 2d1h
etcd-master1 1/1 Running 6 2d1h
kube-apiserver-master1 1/1 Running 6 2d1h
kube-controller-manager-master1 1/1 Running 2 2d1h
# 下面這四個都可以
kube-flannel-ds-amd64-8c2lc 1/1 Running 4 2d1h
kube-flannel-ds-amd64-dflsl 1/1 Running 9 23h
kube-flannel-ds-amd64-hgp55 1/1 Running 1 2d1h
kube-flannel-ds-amd64-jb79v 1/1 Running 33 26h
kube-proxy-2lz7f 1/1 Running 0 23h
kube-proxy-hqsdn 1/1 Running 4 2d1h
kube-proxy-rh92r 1/1 Running 1 2d1h
kube-proxy-tv4mt 1/1 Running 0 26h
kube-scheduler-master1 1/1 Running 2 2d1h
然后使用flannel
的 pod 名來查看其配置yaml
盟榴。使用命令kubectl get po -n kube-system kube-flannel-ds-amd64-8c2lc -o yaml
曹质,注意修改其中的 pod 名稱。在輸出的內(nèi)容開頭可以找到ownerReferences
字段擎场,其下的name
屬性就是要找的配置文件名羽德。如下:
root@master1:~# kubectl get po -n kube-system kube-flannel-ds-amd64-8c2lc -o yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: "2019-07-01T07:53:25Z"
generateName: kube-flannel-ds-amd64-
labels:
app: flannel
controller-revision-hash: 7c75959b75
pod-template-generation: "1"
tier: node
name: kube-flannel-ds-amd64-8c2lc
namespace: kube-system
ownerReferences:
- apiVersion: apps/v1
blockOwnerDeletion: true
controller: true
kind: DaemonSet
name: kube-flannel-ds-amd64
uid: df09fb4c-5390-4498-b539-74cb5d90f66d
resourceVersion: "126940"
selfLink: /api/v1/namespaces/kube-system/pods/kube-flannel-ds-amd64-8c2lc
uid: 31d11bc6-b8f3-492a-9f92-abac1d330663
將找到的配置文件名填入sudo kubectl edit daemonset <配置文件名> -n kube-system
并執(zhí)行即可打開配置文件。
修改配置文件迅办,指定目標網(wǎng)卡
在打開的配置文件中找到spec.template.spec.containers[0].args
字段宅静,如下:
...
spec:
revisionHistoryLimit: 10
selector:
matchLabels:
app: flannel
tier: node
template:
metadata:
creationTimestamp: null
labels:
app: flannel
tier: node
spec:
containers:
# 看這里
- args:
- --ip-masq
- --kube-subnet-mgr
command:
- /opt/bin/flanneld
env:
...
這個字段表示了flannel
啟動時都要附加那些參數(shù),我們要手動添加參數(shù)--iface=網(wǎng)卡名
來進行指定站欺,如下:
- args:
- --ip-masq
- --kube-subnet-mgr
- --iface=enp0s8
這里的enp0s8
是我的網(wǎng)卡名姨夹,你可以通過ifconfig
來找到自己的網(wǎng)卡名。
修改完成之后輸入:wq
保存退出矾策。命令行會提示:
daemonset.extensions/kube-flannel-ds-amd64 edited
這就說明保存成功了磷账。然后就要重啟所有已經(jīng)存在的flannel
。使用kubectl delete pod -n kube-system <pod名1> <pod名2> ...
把所有的flannel
刪除即可贾虽。k8s 會自動按照你修改好的yaml
配置重建flannel
逃糟。
root@master1:~# kubectl delete pod -n kube-system \
kube-flannel-ds-amd64-8c2lc \
kube-flannel-ds-amd64-dflsl \
kube-flannel-ds-amd64-hgp55 \
kube-flannel-ds-amd64-jb79v
pod "kube-flannel-ds-amd64-8c2lc" deleted
pod "kube-flannel-ds-amd64-dflsl" deleted
pod "kube-flannel-ds-amd64-hgp55" deleted
pod "kube-flannel-ds-amd64-jb79v" deleted
然后再次kubectl get pod -n kube-system | grep flannel
就發(fā)現(xiàn)所有flannel
都已經(jīng)重啟成功了:
root@master1:~# kubectl get pod -n kube-system | grep flannel
kube-flannel-ds-amd64-2d6tb 1/1 Running 0 89s
kube-flannel-ds-amd64-kp5xs 1/1 Running 0 86s
kube-flannel-ds-amd64-l9728 1/1 Running 0 92s
kube-flannel-ds-amd64-r87qc 1/1 Running 0 91s
然后再隨便找個pod
試一下就可以看到問題解決了:
root@master1:~# k exec kubia-d7kjl -- curl -s http://10.103.214.110
You've hit kubia-d7kjl
root@master1:~# k exec kubia-d7kjl -- curl -s http://10.103.214.110
You've hit kubia-d7kjl
root@master1:~# k exec kubia-d7kjl -- curl -s http://10.103.214.110
You've hit kubia-kdjgf
root@master1:~# k exec kubia-d7kjl -- curl -s http://10.103.214.110
You've hit kubia-d7kjl
問題發(fā)現(xiàn)
這里記錄一下問題的發(fā)現(xiàn)經(jīng)過,希望對大家有所幫助榄鉴。當我一開始遇到這個問題的時候還以為是svc
的問題履磨,但是在查看了對應(yīng)svc
的endpoint
之后,并沒有發(fā)現(xiàn)有什么顯式的問題出現(xiàn)庆尘,如下剃诅,可以看到svc
正確的識別到了已存在的兩個pod
:
root@master1:~# kubectl get ep kubia
NAME ENDPOINTS AGE
kubia 10.244.1.5:8080,10.244.3.4:8080 8h
什么是
endpoint
?
endpoint
可以簡單理解成路由導(dǎo)向的終點,因為 svc 是將許多個動態(tài)的 ip 映射成一個靜態(tài)的 ip驶忌。那么就可以把這些動態(tài)的 pod ip 稱為 svc 的endpoint
矛辕。
繼續(xù)說,因為在測試過程中向 svc 發(fā)了很多請求付魔,也可以察覺到其實 svc 已經(jīng)隨機的將你的請求分發(fā)到了不同的 pod聊品,只是目標 pod 不在當前節(jié)點的時候就會返回exit code 7
。然后嘗試一下繞過 svc 直接請求 pod几苍,首先新建出來一個 pod翻屈,然后使用kubectl get po -o wide
查看 pod ip。
root@master1:~# kubectl get po -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kubia-d7kjl 1/1 Running 0 8h 10.244.1.5 worker1 <none> <none>
kubia-kdjgf 1/1 Running 0 9h 10.244.3.4 worker2 <none> <none>
kubia-kn45c 1/1 Running 0 13s 10.244.1.6 worker1 <none> <none>
可以看到 k8s 把新的 pod 放在了worker1
上妻坝,所以我們就拿這個新的 pod 去直接訪問其他兩個 pod伸眶。這里不能在主機上直接 ping
pod ip惊窖,因為 pod 都是開放在虛擬網(wǎng)絡(luò)10.244.x.x
上的,在主機上訪問不到:
訪問相同節(jié)點上的 pod
root@master1:~# k exec -it kubia-d7kjl -- ping 10.244.1.6
PING 10.244.1.6 (10.244.1.6): 56 data bytes
64 bytes from 10.244.1.6: icmp_seq=0 ttl=64 time=0.377 ms
64 bytes from 10.244.1.6: icmp_seq=1 ttl=64 time=0.114 ms
...
訪問不同節(jié)點上的 pod
root@master1:~# k exec -it kubia-d7kjl -- ping 10.244.3.4
PING 10.244.3.4 (10.244.3.4): 56 data bytes
# 沒反應(yīng)了
# 死一般寂靜
這么看的話其實問題不在svc
上厘贼,而是兩個節(jié)點之間的網(wǎng)絡(luò)聯(lián)通出現(xiàn)了問題界酒。而10.244.x.x
虛擬網(wǎng)段是通過flannel
搭建的,所以問題自然就是出在它上嘴秸。在翻閱了官方文檔后可以發(fā)現(xiàn)毁欣,官方明確指出了在vagrant
類型的虛擬機上運行時要注意默認網(wǎng)卡的問題,再結(jié)合自己的網(wǎng)絡(luò)情況岳掐,問題就已經(jīng)很明確了了凭疮。