计算机网络解决的是计算机系统之间如何相互通信,而 Kubernetes 集群网络解决的是集群内的工作负载(主要是 Pod)之间如何相互通信,以及工作负载如何和外部相互通信。
Kubernetes 集群网络是一个很宽泛的话题,它也涉及到很多具体方面:Service, Ingress, DNS, Inter-node networking, kube-proxy, CNI plugin, LVS, iptables 等,这篇文章不是想把这些每个都讲清楚,而是试图提供一个简单介绍,而且这里不会列出完整的参考文献,它们主要分散在 Kubernetes 官网文档、具体某个 CNI Plugin 提供商官网、Linux kernel 文档、命令行 man page 等地方。
需要注意的是 Kubernetes 集群网络和节点构成的计算机网络并不是孤立的,某种程度来说前者依赖后者,通常来说一个 Pod 要和另一个节点的 Pod 通信,还需要借助于节点对封包的转发或者封装。并且事实上不同的集群分发版也会有不同的默认的集群网络实现方式。
Kubernetes 集群网络都分别解决了什么样的问题呢?
其中也包括集群内部同一节点内的 Pod 间通信,以及跨节点的 Pod 通信。
在 Kubernetes 网络模型中,Pod 和 Pod 之间的通信是点对点的,也就是说所有的 Pod 构成了一个网状拓扑的网络。一般来说每个 Pod 会被分配到一个(也可以是多个)IP 地址,任意两个 Pod 只要知道对方的 IP 地址,就可以和对方点对点通信。这样的 Pod IP 网络是没有 NAT 的,也没有层级,所有 Pod 的 IP 都是在一个同一个 CIDR 内(给定 IP 的版本),这个 CIDR 也叫做 Cluster CIDR, 或者 Pod CIDR.
Cluster CIDR 在集群部署时确定,可以是由系统管理员手动设定,例如 10.3.0.0/16, 也可以由 K8s 分发版自动确定(缺省状态下),但总之一旦集群安装后了之后,这个 CIDR 一般情况下就不会再变了。这个 Cluster CIDR 参数会交给 CNI 插件的 IPAM 部分(也叫 CNI IPAM plugin,负责给 Pod 分配 IP 地址),后续所有新创建的 Pod, 都在这个 CIDR 上分配地址。
CNI IPAM plugin 分配给 Pod 的 IP 地址会被 CNI Network plugin 绑定到 Pod 对应的虚拟网卡上,有一种实现方式是,CNI Network plugin 为 Pod 创建对应的 netns(网络命名空间)和 veth(虚拟以太网卡)设备,然后将 IP 地址添加到 veth 上。
要验证这一点,我们可以在某节点上创建一个测试 Pod, 同时观察该节点上 calico-node 的日志,可以看到一些 IP 地址有关的输出,以及一些网卡有关的输出,例如,和网卡有关的:
2023-11-12 11:48:37.196 [INFO][79] felix/int_dataplane.go 1254: Linux interface state changed. ifIndex=16 ifaceName="cali1037a54e65e" state="up"
接下来可以 ssh 到该节点上,查看该网卡的具体信息:
$ sudo ip --all -d link show cali1037a54e65e
16: cali1037a54e65e@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netns cni-4d913903-e17a-d0c8-6fc2-16161ee9b299 promiscuity 0 minmtu 68 maxmtu 65535
veth addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535