介绍
Kubernetes是一个容器编排系统,可以跨服务器节点集群管理容器化应用程序。 维护群集中所有容器之间的网络连接需要一些高级网络技术。 在本文中,我们将简要介绍一些用于检查此网络设置的工具和技术。
如果您正在调试连接问题,调查网络吞吐量问题或探索Kubernetes以了解其运行方式,这些工具可能很有用。
如果您想了解更多关于Kubernetes的信息,我们的指南介绍Kubernetes涵盖了基础知识。 有关Kubernetes的网络特定概述,请阅读Kubernetes网络引擎 。
入门
本教程假设您有一个Kubernetes集群,其中kubectl
在本地安装并配置为连接到集群。
以下部分包含许多要在Kubernetes节点上运行的命令。 它们看起来像这样:
echo 'this is a node command'
应在本地计算机上运行的命令将具有以下外观:
echo 'this is a local command'
注意:本教程中的大多数命令都需要以root用户身份运行。 如果您在Kubernetes节点上使用启用了sudo的用户,请在必要时添加sudo
以运行命令。
查找Pod的群集IP
要查找Kubernetes pod的群集IP地址,请在本地计算机上使用kubectl get pod
命令,并使用-o wide
选项。 此选项将列出更多信息,包括Pod所在的节点以及pod的群集IP。
kubectl get pod -o wide
OutputNAME READY STATUS RESTARTS AGE IP NODE
hello-world-5b446dd74b-7c7pk 1/1 Running 0 22m 10.244.18.4 node-one
hello-world-5b446dd74b-pxtzt 1/1 Running 0 22m 10.244.3.4 node-two
IP列将包含每个pod的内部群集IP地址。
如果您没有看到正在寻找的pod,请确保您位于正确的命名空间中。 您可以通过添加标志--all-namespaces
列出所有命名空间中的所有pod。
寻找服务的IP
我们也可以使用kubectl
找到服务IP。 在这种情况下,我们将列出所有命名空间中的所有服务:
kubectl get service --all-namespaces
OutputNAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default kubernetes ClusterIP 10.32.0.1 <none> 443/TCP 6d
kube-system csi-attacher-doplugin ClusterIP 10.32.159.128 <none> 12345/TCP 6d
kube-system csi-provisioner-doplugin ClusterIP 10.32.61.61 <none> 12345/TCP 6d
kube-system kube-dns ClusterIP 10.32.0.10 <none> 53/UDP,53/TCP 6d
kube-system kubernetes-dashboard ClusterIP 10.32.226.209 <none> 443/TCP 6d
可以在CLUSTER-IP列中找到服务IP。
查找并输入Pod网络命名空间
每个Kubernetes pod都被分配了自己的网络命名空间。 网络命名空间(或netns)是一种Linux网络原语,可在网络设备之间提供隔离。
从pod的网络中运行命令,检查DNS解析或一般网络连接可能很有用。 为此,我们首先需要查找pod中其中一个容器的进程ID。 对于Docker,我们可以通过一系列两个命令来实现。 首先,列出节点上运行的容器:
docker ps
OutputCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
173ee46a3926 gcr.io/google-samples/node-hello "/bin/sh -c 'node se…" 9 days ago Up 9 days k8s_hello-world_hello-world-5b446dd74b-pxtzt_default_386a9073-7e35-11e8-8a3d-bae97d2c1afd_0
11ad51cb72df k8s.gcr.io/pause-amd64:3.1 "/pause" 9 days ago Up 9 days k8s_POD_hello-world-5b446dd74b-pxtzt_default_386a9073-7e35-11e8-8a3d-bae97d2c1afd_0
. . .
在您感兴趣的窗格中查找容器ID或容器的 名称 。在上面的输出中,我们显示了两个容器:
- 第一个容器是在
hello-world
pod中运行的hello-world
应用程序 - 第二个是在
hello-world
pod中运行的暂停容器。 此容器仅用于保留pod的网络命名空间
要获取任一容器的进程ID,请记下容器ID或名称,并在以下docker
命令中使用它:
docker inspect --format '{{ .State.Pid }}' container-id-or-name
Output14552
将输出进程ID(或PID)。 现在我们可以使用nsenter
程序在该进程的网络命名空间中运行命令:
nsenter -t your-container-pid -n ip addr
请务必使用您自己的PID,并将ip addr
替换为您要在pod的网络命名空间内运行的命令。
注意:使用nsenter
在pod的命名空间中运行命令(与使用nsenter
docker exec
类的命令相比)的一个优点是,您可以访问节点上可用的所有命令,而不是容器中安装的通常有限的命令集。
寻找Pod的虚拟以太网接口
每个pod的网络命名空间通过虚拟以太网管道与节点的根网络通信。 在节点端,此管道显示为通常以veth
并以唯一标识符结尾的设备,例如veth77f2275
或veth01
。 在pod中,此管道显示为eth0
。
关联哪个veth
设备与特定pod配对可能是有用的。 为此,我们将列出节点上的所有网络设备,然后列出pod的网络命名空间中的设备。 然后,我们可以关联两个列表之间的设备编号以建立连接。
首先,使用nsenter
在pod的网络命名空间中运行ip addr
。 请参阅上一节“ 查找和输入Pod网络命名空间”
有关如何执行此操作的详细信息:
nsenter -t your-container-pid -n ip addr
Output1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
10: eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default
link/ether 02:42:0a:f4:03:04 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 10.244.3.4/24 brd 10.244.3.255 scope global eth0
valid_lft forever preferred_lft forever
该命令将输出pod的接口列表。 请注意示例输出中eth0@
之后的if11
数字。 这意味着该pod的eth0
链接到节点的第11个接口。 现在在节点的默认命名空间中运行ip addr
以列出其接口:
ip addr
Output1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
. . .
7: veth77f2275@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master docker0 state UP group default
link/ether 26:05:99:58:0d:b9 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::2405:99ff:fe58:db9/64 scope link
valid_lft forever preferred_lft forever
9: vethd36cef3@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master docker0 state UP group default
link/ether ae:05:21:a2:9a:2b brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet6 fe80::ac05:21ff:fea2:9a2b/64 scope link
valid_lft forever preferred_lft forever
11: veth4f7342d@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master docker0 state UP group default
link/ether e6:4d:7b:6f:56:4c brd ff:ff:ff:ff:ff:ff link-netnsid 2
inet6 fe80::e44d:7bff:fe6f:564c/64 scope link
valid_lft forever preferred_lft forever
在此示例输出中,第11个接口是veth4f7342d
。 这是我们正在调查的pod的虚拟以太网管道。
检查Conntrack连接跟踪
在版本1.11之前,Kubernetes使用iptables NAT和conntrack内核模块来跟踪连接。 要列出当前正在跟踪的所有连接,请使用conntrack
命令:
conntrack -L
要连续观察新连接,请使用-E
标志:
conntrack -E
要列出与特定目标地址的conntrack跟踪连接,请使用-d
标志:
conntrack -L -d 10.32.0.1
如果您的节点在与服务建立可靠连接时遇到问题,则可能是您的连接跟踪表已满并且正在删除新连接。 如果是这种情况,您可能会在系统日志中看到如下消息:
Jul 12 15:32:11 worker-528 kernel: nf_conntrack: table full, dropping packet.
有一个sysctl设置可以跟踪要跟踪的最大连接数。 您可以使用以下命令列出当前值:
sysctl net.netfilter.nf_conntrack_max
Outputnet.netfilter.nf_conntrack_max = 131072
要设置新值,请使用-w
标志:
sysctl -w net.netfilter.nf_conntrack_max=198000
要使此设置永久化,请将其添加到sysctl.conf
文件中:
. . .
net.ipv4.netfilter.ip_conntrack_max = 198000
检查Iptables规则
在版本1.11之前,Kubernetes使用iptables NAT实现服务IP的虚拟IP转换和负载平衡。
要在节点上转储所有iptables规则,请使用iptables-save
命令:
iptables-save
因为输出可能很长,所以您可能希望通过管道传输到文件( iptables-save > output.txt
)或寻呼机( iptables-save | less
)来更轻松地查看规则。
要仅列出Kubernetes服务NAT规则,请使用iptables
命令和-L
标志指定正确的链:
iptables -t nat -L KUBE-SERVICES
OutputChain KUBE-SERVICES (2 references)
target prot opt source destination
KUBE-SVC-TCOU7JCQXEZGVUNU udp -- anywhere 10.32.0.10 /* kube-system/kube-dns:dns cluster IP */ udp dpt:domain
KUBE-SVC-ERIFXISQEP7F7OF4 tcp -- anywhere 10.32.0.10 /* kube-system/kube-dns:dns-tcp cluster IP */ tcp dpt:domain
KUBE-SVC-XGLOHA7QRQ3V22RZ tcp -- anywhere 10.32.226.209 /* kube-system/kubernetes-dashboard: cluster IP */ tcp dpt:https
. . .
查询群集DNS
调试群集DNS解析的一种方法是使用您需要的所有工具部署调试容器,然后使用kubectl
对其执行nslookup
。 这在Kubernetes官方文档中有所描述。
查询集群DNS的另一种方法是使用节点中的dig
和nsenter
。 如果没有安装dig
,可以在基于Debian的Linux发行版上安装apt
:
apt install dnsutils
首先,找到kube-dns服务的集群IP:
kubectl get service -n kube-system kube-dns
OutputNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kube-dns ClusterIP 10.32.0.10 <none> 53/UDP,53/TCP 15d
群集IP在上面突出显示。 接下来我们将使用nsenter
在容器命名空间中运行dig
。 有关详细信息,请查看“ 查找并输入Pod网络命名空间 ”部分:
nsenter -t 14346 -n dig kubernetes.default.svc.cluster.local @10.32.0.10
此dig
命令查找Service的service-name的完整域名。 命名空间 .svc.cluster.local并指定集群DNS服务IP的IP( @ 10.32.0.10
)。
查看IPVS详细信息
从Kubernetes 1.11开始, kube-proxy
可以配置IPVS来处理虚拟服务IP到pod IP的转换。 您可以使用ipvsadm
列出IP的转换表:
ipvsadm -Ln
OutputIP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 100.64.0.1:443 rr
-> 178.128.226.86:443 Masq 1 0 0
TCP 100.64.0.10:53 rr
-> 100.96.1.3:53 Masq 1 0 0
-> 100.96.1.4:53 Masq 1 0 0
UDP 100.64.0.10:53 rr
-> 100.96.1.3:53 Masq 1 0 0
-> 100.96.1.4:53 Masq 1 0 0
要显示单个服务IP,请使用-t
选项并指定所需的IP:
ipvsadm -Ln -t 100.64.0.10:53
OutputProt LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 100.64.0.10:53 rr
-> 100.96.1.3:53 Masq 1 0 0
-> 100.96.1.4:53 Masq 1 0 0
结论
在本文中,我们回顾了一些用于探索和检查Kubernetes集群网络细节的命令和技术。 有关Kubernetes的更多信息,请查看我们的Kubernetes教程标签和官方Kubernetes文档 。