如何检查Kubernetes网络

来自菜鸟教程
跳转至:导航、​搜索

介绍

Kubernetes 是一个容器编排系统,可以跨服务器节点集群管理容器化应用程序。 维护集群中所有容器之间的网络连接需要一些先进的网络技术。 在本文中,我们将简要介绍一些用于检查此网络设置的工具和技术。

如果您正在调试连接问题、调查网络吞吐量问题或探索 Kubernetes 以了解其运行方式,这些工具可能会很有用。

如果您想全面了解 Kubernetes 的更多信息,我们的指南 An Introduction to Kubernetes 涵盖了基础知识。 有关 Kubernetes 网络特定的概述,请阅读 Kubernetes Networking Under the Hood

入门

本教程将假设您有一个 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

服务 IP 可以在 CLUSTER-IP 列中找到。

查找并输入 Pod 网络命名空间

每个 Kubernetes pod 都被分配了自己的网络命名空间。 网络命名空间(或 netns)是一种 Linux 网络原语,可在网络设备之间提供隔离。

从 pod 的 netns 中运行命令以检查 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
. . .

在您感兴趣的 pod 中找到任何容器的 容器 ID名称。 在上面的输出中,我们展示了两个容器:

  • 第一个容器是在 hello-world pod 中运行的 hello-world 应用程序
  • 第二个是在 hello-world pod 中运行的 pause 容器。 此容器的存在仅用于保存 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 的命名空间中运行命令的一个优势——与使用 docker exec 之类的东西相比——是您可以访问所有可用的命令node,而不是安装在容器中的通常有限的命令集。


查找 Pod 的虚拟以太网接口

每个 pod 的网络命名空间通过虚拟以太网管道与节点的根 netns 通信。 在节点端,此管道显示为通常以 veth 开头并以唯一标识符结尾的设备,例如 veth77f2275veth01。 在 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

如果您的节点在建立与服务的可靠连接时遇到问题,则可能是您的连接跟踪表已满,并且正在删除新连接。 如果是这种情况,您可能会在系统日志中看到如下消息:

/var/log/系统日志

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 文件中:

/etc/sysctl.conf

. . .
net.ipv4.netfilter.ip_conntrack_max = 198000

检查 iptables 规则

在 1.11 版本之前,Kubernetes 使用 iptables NAT 来实现 Service 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 的另一种方法是使用节点中的 dignsenter。 如果没有安装 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-name.namespace.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 官方文档