本文介紹各種常見的網絡問題以及排錯方法,包括 Pod 訪問異常、Service 訪問異常以及網絡安全策略異常等。
說到 Kubernetes 的網絡,其實無非就是以下三種情況之一
-
Pod 訪問容器外部網絡
-
從容器外部訪問 Pod 網絡
-
Pod 之間相互訪問
當然,以上每種情況還都分別包括本地訪問和跨主機訪問兩種場景,並且一般情況下都是通過 Service 間接訪問 Pod。
排查網絡問題基本上也是從這幾種情況出發,定位出具體的網絡異常點,再進而尋找解決方法。網絡異常可能的原因比較多,常見的有:
CNI 網絡插件配置錯誤,導致多主機網絡不通,比如
-
IP 網段與現有網絡沖突
-
插件使用了底層網絡不支持的協議
-
忘記開啟 IP 轉發等
-
sysctl net.ipv4.ip_forward
-
sysctl net.bridge.bridge-nf-call-iptables
Pod 網絡路由丟失,比如
-
kubenet 要求網絡中有 podCIDR 到主機 IP 地址的路由,這些路由如果沒有正確配置會導致 Pod 網絡通信等問題
-
在公有雲平台上,kube-controller-manager 會自動為所有 Node 配置路由,但如果配置不當(如認證授權失敗、超出配額等),也有可能導致無法配置路由
-
主機內或者雲平台的安全組、防火牆或者安全策略等阻止了 Pod 網絡,比如
-
非 Kubernetes 管理的 iptables 規則禁止了 Pod 網絡
-
公有雲平台的安全組禁止了 Pod 網絡(注意 Pod 網絡有可能與 Node 網絡不在同一個網段)
-
交換機或者路由器的 ACL 禁止了 Pod 網絡
Flannel Pods 一直處於 Init:CrashLoopBackOff 狀態
Flannel 網絡插件非常容易部署,只要一條命令即可
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.ymlubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
然而,部署完成后,Flannel Pod 有可能會碰到初始化失敗的錯誤
$ kubectl -n kube-system get pod
NAME READY STATUS RESTARTS AGE
kube-flannel-ds-ckfdc 0/1 Init:CrashLoopBackOff 4 2m
kube-flannel-ds-jpp96 0/1 Init:CrashLoopBackOff 4 2m
查看日志會發現
$ kubectl -n kube-system logs kube-flannel-ds-jpp96 -c install-cni
cp: can't create '/etc/cni/net.d/10-flannel.conflist': Permission denied
這一般是由於 SELinux 開啟導致的,關閉 SELinux 既可解決。有兩種方法:
-
修改
/etc/selinux/config
文件方法:SELINUX=disabled
-
通過命令臨時修改(重啟會丟失):
setenforce 0
Pod 無法解析 DNS
如果 Node 上安裝的 Docker 版本大於 1.12,那么 Docker 會把默認的 iptables FORWARD 策略改為 DROP。這會引發 Pod 網絡訪問的問題。解決方法則在每個 Node 上面運行 iptables -P FORWARD ACCEPT
,比如
echo "ExecStartPost=/sbin/iptables -P FORWARD ACCEPT" >> /etc/systemd/system/docker.service.d/exec_start.conf
systemctl daemon-reload
systemctl restart docker
如果使用了 flannel/weave 網絡插件,更新為最新版本也可以解決這個問題。
DNS 無法解析也有可能是 kube-dns 服務異常導致的,可以通過下面的命令來檢查 kube-dns 是否處於正常運行狀態
$ kubectl get pods --namespace=kube-system -l k8s-app=kube-dns
NAME READY STATUS RESTARTS AGE
...
kube-dns-v19-ezo1y 3/3 Running 0 1h
...
如果 kube-dns 處於 CrashLoopBackOff 狀態,那么可以參考 Kube-dns/Dashboard CrashLoopBackOff 排錯 來查看具體排錯方法。
如果 kube-dns Pod 處於正常 Running 狀態,則需要進一步檢查是否正確配置了 kube-dns 服務:
$ kubectl get svc kube-dns --namespace=kube-system
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns 10.0.0.10 <none> 53/UDP,53/TCP 1h
$ kubectl get ep kube-dns --namespace=kube-system
NAME ENDPOINTS AGE
kube-dns 10.180.3.17:53,10.180.3.17:53 1h
如果 kube-dns service 不存在,或者 endpoints 列表為空,則說明 kube-dns service 配置錯誤,可以重新創建 kube-dns service,比如
apiVersion: v1
kind: Service
metadata:
name: kube-dns
namespace: kube-system
labels:
k8s-app: kube-dns
kubernetes.io/cluster-service: "true"
kubernetes.io/name: "KubeDNS"
spec:
selector:
k8s-app: kube-dns
clusterIP: 10.0.0.10
ports:
- name: dns
port: 53
protocol: UDP
- name: dns-tcp
port: 53
protocol: TCP
Service 無法訪問
訪問 Service ClusterIP 失敗時,可以首先確認是否有對應的 Endpoints
kubectl get endpoints <service-name>
如果該列表為空,則有可能是該 Service 的 LabelSelector 配置錯誤,可以用下面的方法確認一下
# 查詢 Service 的 LabelSelector
kubectl get svc <service-name> -o jsonpath='{.spec.selector}'
# 查詢匹配 LabelSelector 的 Pod
kubectl get pods -l key1=value1,key2=value2
如果 Endpoints 正常,可以進一步檢查
-
Pod 的 containerPort 與 Service 的 containerPort 是否對應
-
直接訪問
podIP:containerPort
是否正常
再進一步,即使上述配置都正確無誤,還有其他的原因會導致 Service 無法訪問,比如
-
Pod 內的容器有可能未正常運行或者沒有監聽在指定的 containerPort 上
-
CNI 網絡或主機路由異常也會導致類似的問題
-
kube-proxy 服務有可能未啟動或者未正確配置相應的 iptables 規則,比如正常情況下名為
hostnames
的服務會配置以下 iptables 規則
$ iptables-save | grep hostnames
-A KUBE-SEP-57KPRZ3JQVENLNBR -s 10.244.3.6/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000
-A KUBE-SEP-57KPRZ3JQVENLNBR -p tcp -m comment --comment "default/hostnames:" -m tcp -j DNAT --to-destination 10.244.3.6:9376
-A KUBE-SEP-WNBA2IHDGP2BOBGZ -s 10.244.1.7/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000
-A KUBE-SEP-WNBA2IHDGP2BOBGZ -p tcp -m comment --comment "default/hostnames:" -m tcp -j DNAT --to-destination 10.244.1.7:9376
-A KUBE-SEP-X3P2623AGDH6CDF3 -s 10.244.2.3/32 -m comment --comment "default/hostnames:" -j MARK --set-xmark 0x00004000/0x00004000
-A KUBE-SEP-X3P2623AGDH6CDF3 -p tcp -m comment --comment "default/hostnames:" -m tcp -j DNAT --to-destination 10.244.2.3:9376
-A KUBE-SERVICES -d 10.0.1.175/32 -p tcp -m comment --comment "default/hostnames: cluster IP" -m tcp --dport 80 -j KUBE-SVC-NWV5X2332I4OT4T3
-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-WNBA2IHDGP2BOBGZ
-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-X3P2623AGDH6CDF3
-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -j KUBE-SEP-57KPRZ3JQVENLNBR
Pod 無法通過 Service 訪問自己
這通常是 hairpin 配置錯誤導致的,可以通過 Kubelet 的 --hairpin-mode
選項配置,可選參數包括 "promiscuous-bridge"、"hairpin-veth" 和 "none"(默認為"promiscuous-bridge")。
對於 hairpin-veth 模式,可以通過以下命令來確認是否生效
$ for intf in /sys/devices/virtual/net/cbr0/brif/*; do cat $intf/hairpin_mode; done
1
1
1
1
而對於 promiscuous-bridge 模式,可以通過以下命令來確認是否生效
$ ifconfig cbr0 |grep PROMISC
UP BROADCAST RUNNING PROMISC MULTICAST MTU:1460 Metric:1
無法訪問 Kubernetes API
很多擴展服務需要訪問 Kubernetes API 查詢需要的數據(比如 kube-dns、Operator 等)。通常在 Kubernetes API 無法訪問時,可以首先通過下面的命令驗證 Kubernetes API 是正常的:
$ kubectl run curl --image=appropriate/curl -i -t --restart=Never --command -- sh
If you don't see a command prompt, try pressing enter.
/ #
/ # KUBE_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
/ # curl -sSk -H "Authorization: Bearer $KUBE_TOKEN" https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT/api/v1/namespaces/default/pods
{
"kind": "PodList",
"apiVersion": "v1",
"metadata": {
"selfLink": "/api/v1/namespaces/default/pods",
"resourceVersion": "2285"
},
"items": [
...
]
}
如果出現超時錯誤,則需要進一步確認名為 kubernetes
的服務以及 endpoints 列表是正常的:
$ kubectl get service kubernetes
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 25m
$ kubectl get endpoints kubernetes
NAME ENDPOINTS AGE
kubernetes 172.17.0.62:6443 25m
然后可以直接訪問 endpoints 查看 kube-apiserver 是否可以正常訪問。無法訪問時通常說明 kube-apiserver 未正常啟動,或者有防火牆規則阻止了訪問。
但如果出現了 403 - Forbidden
錯誤,則說明 Kubernetes 集群開啟了訪問授權控制(如 RBAC),此時就需要給 Pod 所用的 ServiceAccount 創建角色和角色綁定授權訪問所需要的資源。比如 CoreDNS 就需要創建以下 ServiceAccount 以及角色綁定:
# 1. service account
apiVersion: v1
kind: ServiceAccount
metadata:
name: coredns
namespace: kube-system
labels:
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
---
# 2. cluster role
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
kubernetes.io/bootstrapping: rbac-defaults
addonmanager.kubernetes.io/mode: Reconcile
name: system:coredns
rules:
- apiGroups:
- ""
resources:
- endpoints
- services
- pods
- namespaces
verbs:
- list
- watch
---
# 3. cluster role binding
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
annotations:
rbac.authorization.kubernetes.io/autoupdate: "true"
labels:
kubernetes.io/bootstrapping: rbac-defaults
addonmanager.kubernetes.io/mode: EnsureExists
name: system:coredns
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:coredns
subjects:
- kind: ServiceAccount
name: coredns
namespace: kube-system
---
# 4. use created service account
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: coredns
namespace: kube-system
labels:
k8s-app: coredns
kubernetes.io/cluster-service: "true"
addonmanager.kubernetes.io/mode: Reconcile
kubernetes.io/name: "CoreDNS"
spec:
replicas: 2
selector:
matchLabels:
k8s-app: coredns
template:
metadata:
labels:
k8s-app: coredns
spec:
serviceAccountName: coredns
...
原文鏈接:
https://zhuanlan.zhihu.com/p/34558421
看到這里,相信很多小伙伴也已經了解了K8S常見的網絡問題及排錯方法,其實,對於任何一門技術點的學習,其理論基礎的掌握是第一步,繼而實踐操作是第二步,然后再自我總結方可全面掌握,那么,今天民工哥給大家帶來好書福利了,且看下面的精彩介紹。
送書福利:
今天給大家帶來的是由馬哥教育的創始人、CEO馬哥親自操刀撰寫的又一巨作,漸進式講解,手把手示范 ,大量實操案例,隨時動手驗證 是本書的特色。
本書致力於幫助容器編排技術的初級和中級用戶循序漸進地理解與使用Kubernetes系統,因此本書的編寫充分考慮到初學者進入新知識領域時的茫然,采用由淺入深、提綱挈領、再由點到面的方式講解每一個知識細節。
划重點:此次一共送出5本書,重點是好書+馬哥親筆簽名。
送書規則:
1、僅限公眾號讀者參與,活動截止時間2019年1月17號12:30。
2、留言分享你在學習K8S中的趣事、踩過的坑或需要此書的理由,在精選留言中隨機抽取2名留言最走心的讀者各送一本。
3、在精選留言中隨機抽取1名一直支持、關注公眾號的讀者各送出一本。
4、新規則:從點文章后面“好看”的讀者中 [ 小技巧先加民工哥微信好友再點好看可以大大提高中獎率哦,一般人我不告訴他 ] 隨機抽取2名名送出一本。
5、所有中獎者會在活動結束后【1月18號推文中】公布中獎者名單,請中獎者於一個工作日內加民工哥微信ken_chu1985,發送詳細收貨地址 [ 格式:姓名+聯系方式+詳細地址 ],逾期視為放棄。
最后,沒能獲獎的小伙伴也不要灰心哦,《Kubernetes進階實戰》現已上架京東,掃描二維碼即可享受8.2折價格購買!
- MORE | 往期精彩文章 -
如果你喜歡本文
請長按二維碼關注民工哥技術之路
轉發朋友圈,是對我最大的支持。
掃碼加群交流