Kubernetes 网络排错指南

作者: wencst 分类:docker,架构设计 发布时间: 2018-12-25 11:25 阅读: 1,611 次

本文介绍各种常见的网络问题以及排错方法,包括 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 配置路由,但如果配置不当(如认证授权失败、超出配额等),也有可能导致无法配置路由

Flannel Pods 一直处于 Init:CrashLoopBackOff 状态

Flannel 网络插件非常容易部署,只要一条命令即可

  1. kubectl apply - f https : //raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

然而,部署完成后,Flannel Pod 有可能会碰到初始化失败的错误

  1. $ kubectl - n kube - system get pod
  2. NAME                            READY     STATUS                  RESTARTS   AGE
  3. kube - flannel - ds - ckfdc 0 / 1 Init : CrashLoopBackOff 4 2m
  4. kube - flannel - ds - jpp96 0 / 1 Init : CrashLoopBackOff 4 2m

查看日志会发现

  1. $ kubectl - n kube - system logs kube - flannel - ds - jpp96 - c install - cni
  2. 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,比如

  1. echo "ExecStartPost=/sbin/iptables -P FORWARD ACCEPT" >> /etc/ systemd / system / docker . service . d / exec_start . conf
  2. systemctl daemon - reload
  3. systemctl restart docker

如果使用了 flannel/weave 网络插件,更新为最新版本也可以解决这个问题。

DNS 无法解析也有可能是 kube-dns 服务异常导致的,可以通过下面的命令来检查 kube-dns 是否处于正常运行状态

  1. $ kubectl get pods -- namespace = kube - system - l k8s - app = kube - dns
  2. NAME                    READY     STATUS    RESTARTS   AGE
  3. ...
  4. kube - dns - v19 - ezo1y 3 / 3 Running 0 1h
  5. ...

如果 kube-dns 处于 CrashLoopBackOff 状态,那么可以参考 Kube-dns/Dashboard CrashLoopBackOff 排错 来查看具体排错方法。

如果 kube-dns Pod 处于正常 Running 状态,则需要进一步检查是否正确配置了 kube-dns 服务:

  1. $ kubectl get svc kube - dns -- namespace = kube - system
  2. NAME          CLUSTER - IP     EXTERNAL - IP   PORT ( S ) AGE
  3. kube - dns 10.0 . 0.10 <none> 53 / UDP , 53 / TCP 1h
  4. $ kubectl get ep kube - dns -- namespace = kube - system
  5. NAME       ENDPOINTS                       AGE
  6. kube - dns 10.180 . 3.17 : 53 , 10.180 . 3.17 : 53 1h

如果 kube-dns service 不存在,或者 endpoints 列表为空,则说明 kube-dns service 配置错误,可以重新创建 kube-dns service,比如

  1. apiVersion : v1
  2. kind : Service
  3. metadata :
  4. name : kube - dns
  5. namespace : kube - system
  6. labels :
  7. k8s - app : kube - dns
  8. kubernetes . io / cluster - service : "true"
  9. kubernetes . io / name : "KubeDNS"
  10. spec :
  11. selector :
  12. k8s - app : kube - dns
  13. clusterIP : 10.0 . 0.10
  14. ports :
  15. - name : dns
  16. port : 53
  17. protocol : UDP
  18. - name : dns - tcp
  19. port : 53
  20. protocol : TCP

Service 无法访问

访问 Service ClusterIP 失败时,可以首先确认是否有对应的 Endpoints

  1. kubectl get endpoints < service - name >

如果该列表为空,则有可能是该 Service 的 LabelSelector 配置错误,可以用下面的方法确认一下

  1. # 查询 Service 的 LabelSelector
  2. kubectl get svc < service - name > - o jsonpath = '{.spec.selector}'
  3. # 查询匹配 LabelSelector 的 Pod
  4. kubectl get pods - l key1 = value1 , key2 = value2

如果 Endpoints 正常,可以进一步检查

  • Pod 的 containerPort 与 Service 的 containerPort 是否对应
  • 直接访问 podIP:containerPort 是否正常 再进一步,即使上述配置都正确无误,还有其他的原因会导致 Service 无法访问,比如
  • Pod 内的容器有可能未正常运行或者没有监听在指定的 containerPort 上
  • CNI 网络或主机路由异常也会导致类似的问题
  • kube-proxy 服务有可能未启动或者未正确配置相应的 iptables 规则,比如正常情况下名为 hostnames的服务会配置以下 iptables 规则
  1. $ iptables - save | grep hostnames
  2. - A KUBE - SEP - 57KPRZ3JQVENLNBR - s 10.244 . 3.6 / 32 - m comment -- comment "default/hostnames:" - j MARK -- set - xmark 0x00004000 / 0x00004000
  3. - A KUBE - SEP - 57KPRZ3JQVENLNBR - p tcp - m comment -- comment "default/hostnames:" - m tcp - j DNAT -- to - destination 10.244 . 3.6 : 9376
  4. - A KUBE - SEP - WNBA2IHDGP2BOBGZ - s 10.244 . 1.7 / 32 - m comment -- comment "default/hostnames:" - j MARK -- set - xmark 0x00004000 / 0x00004000
  5. - A KUBE - SEP - WNBA2IHDGP2BOBGZ - p tcp - m comment -- comment "default/hostnames:" - m tcp - j DNAT -- to - destination 10.244 . 1.7 : 9376
  6. - A KUBE - SEP - X3P2623AGDH6CDF3 - s 10.244 . 2.3 / 32 - m comment -- comment "default/hostnames:" - j MARK -- set - xmark 0x00004000 / 0x00004000
  7. - A KUBE - SEP - X3P2623AGDH6CDF3 - p tcp - m comment -- comment "default/hostnames:" - m tcp - j DNAT -- to - destination 10.244 . 2.3 : 9376
  8. - 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
  9. - A KUBE - SVC - NWV5X2332I4OT4T3 - m comment -- comment "default/hostnames:" - m statistic -- mode random -- probability 0.33332999982 - j KUBE - SEP - WNBA2IHDGP2BOBGZ
  10. - A KUBE - SVC - NWV5X2332I4OT4T3 - m comment -- comment "default/hostnames:" - m statistic -- mode random -- probability 0.50000000000 - j KUBE - SEP - X3P2623AGDH6CDF3
  11. - 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 模式,可以通过以下命令来确认是否生效

  1. $ for intf in / sys / devices / virtual / net / cbr0 / brif /*; do cat $intf/hairpin_mode; done
  2. 1
  3. 1
  4. 1
  5. 1

而对于 promiscuous-bridge 模式,可以通过以下命令来确认是否生效

  1. $ ifconfig cbr0 | grep PROMISC
  2. UP BROADCAST RUNNING PROMISC MULTICAST  MTU : 1460 Metric : 1

无法访问 Kubernetes API

很多扩展服务需要访问 Kubernetes API 查询需要的数据(比如 kube-dns、Operator 等)。通常在 Kubernetes API 无法访问时,可以首先通过下面的命令验证 Kubernetes API 是正常的:

  1. $ kubectl run curl -- image = appropriate / curl - i - t -- restart = Never -- command -- sh
  2. If you don 't see a command prompt, try pressing enter.
  3. / #
  4. / # KUBE_TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
  5. / # curl -sSk -H "Authorization: Bearer $KUBE_TOKEN" https://$KUBERNETES_SERVICE_HOST:$KUBERNETES_SERVICE_PORT/api/v1/namespaces/default/pods
  6. {
  7. "kind": "PodList",
  8. "apiVersion": "v1",
  9. "metadata": {
  10. "selfLink": "/api/v1/namespaces/default/pods",
  11. "resourceVersion": "2285"
  12. },
  13. "items": [
  14. ...
  15. ]
  16. }

如果出现超时错误,则需要进一步确认名为 kubernetes 的服务以及 endpoints 列表是正常的:

  1. $ kubectl get service kubernetes
  2. NAME         TYPE        CLUSTER - IP   EXTERNAL - IP   PORT ( S ) AGE
  3. kubernetes ClusterIP 10.96 . 0.1 <none> 443 / TCP 25m
  4. $ kubectl get endpoints kubernetes
  5. NAME         ENDPOINTS          AGE
  6. kubernetes 172.17 . 0.62 : 6443 25m

然后可以直接访问 endpoints 查看 kube-apiserver 是否可以正常访问。无法访问时通常说明 kube-apiserver 未正常启动,或者有防火墙规则阻止了访问。

但如果出现了 403 – Forbidden 错误,则说明 Kubernetes 集群开启了访问授权控制(如 RBAC),此时就需要给 Pod 所用的 ServiceAccount 创建角色和角色绑定授权访问所需要的资源。比如 CoreDNS 就需要创建以下 ServiceAccount 以及角色绑定:

  1. # 1. service account
  2. apiVersion : v1
  3. kind : ServiceAccount
  4. metadata :
  5. name : coredns
  6. namespace : kube - system
  7. labels :
  8. kubernetes . io / cluster - service : "true"
  9. addonmanager . kubernetes . io / mode : Reconcile
  10. ---
  11. # 2. cluster role
  12. apiVersion : rbac . authorization . k8s . io / v1
  13. kind : ClusterRole
  14. metadata :
  15. labels :
  16. kubernetes . io / bootstrapping : rbac - defaults
  17. addonmanager . kubernetes . io / mode : Reconcile
  18. name : system : coredns
  19. rules :
  20. - apiGroups :
  21. - ""
  22. resources :
  23. - endpoints
  24. - services
  25. - pods
  26. - namespaces
  27. verbs :
  28. - list
  29. - watch
  30. ---
  31. # 3. cluster role binding
  32. apiVersion : rbac . authorization . k8s . io / v1
  33. kind : ClusterRoleBinding
  34. metadata :
  35. annotations :
  36. rbac . authorization . kubernetes . io / autoupdate : "true"
  37. labels :
  38. kubernetes . io / bootstrapping : rbac - defaults
  39. addonmanager . kubernetes . io / mode : EnsureExists
  40. name : system : coredns
  41. roleRef :
  42. apiGroup : rbac . authorization . k8s . io
  43. kind : ClusterRole
  44. name : system : coredns
  45. subjects :
  46. - kind : ServiceAccount
  47. name : coredns
  48. namespace : kube - system
  49. ---
  50. # 4. use created service account
  51. apiVersion : extensions / v1beta1
  52. kind : Deployment
  53. metadata :
  54. name : coredns
  55. namespace : kube - system
  56. labels :
  57. k8s - app : coredns
  58. kubernetes . io / cluster - service : "true"
  59. addonmanager . kubernetes . io / mode : Reconcile
  60. kubernetes . io / name : "CoreDNS"
  61. spec :
  62. replicas : 2
  63. selector :
  64. matchLabels :
  65. k8s - app : coredns
  66. template :
  67. metadata :
  68. labels :
  69. k8s - app : coredns
  70. spec :
  71. serviceAccountName : coredns
  72. ...

如果文章对您有用,扫一下支付宝的红包,不胜感激!

欢迎加入QQ群进行技术交流:656897351(各种技术、招聘、兼职、培训欢迎加入)



Leave a Reply