
容器和服务之间的通信
从使用交换机、路由器和以太网电缆的物理网络转移到使用软件定义的网络(SDN)和虚拟接口的虚拟网络,涉及到一个小小的学习曲线。当然,原则是不变的,但有不同的规范和最佳实践。Kubernetes有自己的一套规则,如果你在处理容器和云,那么了解Kubernetes网络的工作原理会有帮助。
Kubernetes网络模型有几条一般规则需要牢记。
- 每个Pod都有自己的IP地址。应该不需要在Pod之间建立链接,也不需要将容器端口映射到主机端口。
- NAT是不需要的。一个节点上的Pod应该能够与所有节点上的所有Pod进行通信而不需要NAT。
- 代理获得所有访问权限。一个节点上的代理(系统守护者,Kubelet)可以与该节点上的所有Pod进行通信。
- 共享命名空间。一个Pod中的容器共享一个网络命名空间(IP和MAC地址),因此它们可以使用回环地址相互通信。
Kubernetes网络解决了什么问题
Kubernetes网络的设计是为了确保Kubernetes内的不同实体类型能够进行通信。根据设计,Kubernetes基础设施的布局有很多分离。命名空间、容器和Pod是为了保持组件之间的区别,所以一个高度结构化的通信计划是很重要的。

Image by: (Nived Velayudhan, CC BY-SA 4.0)
容器到容器的联网
容器到容器的联网是通过Pod网络命名空间进行的。网络命名空间允许你拥有独立的网络接口和路由表,与系统的其他部分隔离,独立运行。每个Pod都有自己的网络命名空间,而该Pod内的容器共享相同的IP地址和端口。这些容器之间的所有通信都是通过localhost进行的,因为它们都是同一个命名空间的一部分。(图中的绿线表示)。
更多关于Kubernetes的信息
免费在线课程。容器、Kubernetes和红帽OpenShift技术课程。
电子书。在Raspberry Pi家庭实验室上运行Kubernetes
电子书。Kubernetes的SRE和sysadmins指南
Pod-to-Pod网络
有了Kubernetes,每个节点都有一个指定的CIDR范围的IP给Pod。这可以确保每个Pod收到一个唯一的IP地址,集群中的其他Pod可以看到。当一个新的Pod被创建时,IP地址绝不会重叠。与容器之间的网络不同,Pod与Pod之间的通信是使用真实的IP进行的,无论你将Pod部署在同一节点还是集群中的不同节点。
图中显示,为了让Pod相互通信,流量必须在Pod网络命名空间和Root网络命名空间之间流动。这是通过一个虚拟以太网设备或一个Veth对(图中Veth0到Pod命名空间1,Veth1到Pod命名空间2)连接Pod命名空间和Root命名空间来实现。一个虚拟网桥连接这些虚拟接口,允许使用地址解析协议(ARP)的流量在它们之间流动。
当数据从Pod 1发送至Pod 2时,事件的流向是。
- Pod 1的流量通过eth0流向Root网络命名空间的虚拟接口veth0。
- 然后流量通过veth0到虚拟网桥,虚拟网桥连接到veth1。
- 流量通过虚拟网桥流向veth1。
- 最后,流量通过veth1到达Pod 2的eth0接口。
Pod-to-Service网络
Pod是非常动态的。它们可能需要根据需求来扩大或缩小规模。在应用程序崩溃或节点故障的情况下,它们可能会被重新创建。这些事件会导致Pod的IP地址改变,这将使联网成为一个挑战。

图片由: (Nived Velayudhan, CC BY-SA 4.0)
Kubernetes通过使用服务功能解决了这个问题,它的作用如下。
- 在前端分配一个静态的虚拟IP地址,以连接与该服务相关的任何后端Pod。
- 负载平衡任何发送到该虚拟IP的流量到后端Pod的集合。
- 追踪一个Pod的IP地址,这样即使Pod的IP地址发生变化,客户端在连接Pod时也不会有任何问题,因为他们只直接与服务本身的静态虚拟IP地址连接。
簇内负载平衡以两种方式发生。
- IPTABLES:在这种模式下,kube-proxy观察API服务器的变化。对于每个新的服务,它安装了iptables规则,捕获到服务的集群IP和端口的流量,然后将流量重定向到服务的后端Pod。该Pod是随机选择的。这种模式很可靠,而且系统开销较低,因为Linux Netfilter处理流量时不需要在用户空间和内核空间之间切换。
- IPVS:IPVS建立在Netfilter之上,实现了传输层的负载平衡。IPVS使用Netfilter的钩子功能,使用哈希表作为底层数据结构,并在内核空间工作。这意味着IPVS模式下的kube-proxy比iptables模式下的kube-proxy重定向流量的延迟更低,吞吐量更大,性能更好。
上图显示了从Pod 1到Pod 3的包通过Service流向不同的节点(红色标记)。流向虚拟网桥的包必须使用默认路由(eth0),因为网桥上运行的ARP无法理解该服务。之后,包必须被iptables过滤,它使用kube-proxy在节点上定义的规则。因此,图中显示的路径是这样的。
互联网到服务网络
到目前为止,我已经讨论了流量如何在集群内被路由。不过,Kubernetes网络还有另一面,那就是将一个应用程序暴露在外部网络中。

图片由: (Nived Velayudhan, CC BY-SA 4.0)
你可以通过两种不同的方式将一个应用程序暴露在外部网络中。
- 出口。当你想把流量从你的Kubernetes服务路由到互联网时,使用这种方式。在这种情况下,iptables执行源NAT,所以流量看起来是来自节点而不是Pod。
- 入站。这是从外部世界到服务的传入流量。入站也允许和阻止与服务的特定通信,使用连接规则。通常情况下,有两个在不同网络堆栈区域发挥作用的入口解决方案:服务负载平衡器和入口控制器。
发现服务
Kubernetes有两种发现服务的方式。
- 环境变量。在你的Pod运行的节点上运行的kubelet服务负责为每个活动服务设置环境变量,格式为{SVCNAME}_SERVICE_HOST和{SVCNAME}_SERVICE_PORT。你必须在客户端Pod出现之前创建服务。否则,这些客户Pod将不会有他们的环境变量被填充。
- DNS。DNS服务是作为Kubernetes服务实现的,它映射到一个或多个DNS服务器Pod,这些Pod就像其他Pod一样被安排。集群中的Pod被配置为使用DNS服务,其DNS搜索列表包括Pod自己的命名空间和集群的默认域。一个集群感知的DNS服务器,如CoreDNS,观察Kubernetes API的新服务,并为每个服务创建一组DNS记录。如果DNS在整个集群中被启用,所有的Pod都可以通过其DNS名称自动解析服务。Kubernetes DNS服务器是访问ExternalName服务的唯一途径。
用于发布服务的ServiceTypes。
Kubernetes服务为你提供了一种访问一组Pod的方式,通常通过使用标签选择器来定义。这可能是应用程序试图访问集群内的其他应用程序,或者它可以让你将集群中运行的应用程序暴露给外部世界。Kubernetes ServiceTypes使你能够指定你想要的服务类型。

图片由: (Ahmet Alp Balkan, CC BY-SA 4.0)
不同的服务类型有。
- ClusterIP:这是默认的服务类型。它使该服务只能从集群内到达,并允许集群内的应用程序相互通信。不存在外部访问。
- LoadBalancer。该服务类型使用云提供商的负载平衡器将服务暴露在外部。来自外部负载平衡器的流量被引导到后端Pod。云提供商决定如何进行负载平衡。
- NodePort:这允许外部流量通过在所有节点上打开一个特定的端口来访问服务。任何发送到该端口的流量将被转发到该服务。
- 外部名称。这种类型的服务通过使用externalName字段的内容,以其值返回CNAME记录,将一个服务映射到一个DNS名称。没有设置任何形式的代理。
联网软件
只要你了解所使用的技术,Kubernetes内的网络与物理世界的网络没有什么不同。学习一下,记住网络基础知识,你就会毫不费力地实现容器、Pod和服务之间的通信。