解密OpenShift内部通信网络

本文深入浅出地解析了OpenShift中的网络通信,包括Pod间通信、Service的作用、负载均衡实现以及多租户网络隔离。通过5个关键问题,阐述了Service作为统一入口和负载均衡的重要性,同时也介绍了Service如何实现服务注册与发现。OpenShift通过CNI插件(如OVS)实现Pod间的二层通信,并依赖kube-proxy(iptables模式)进行负载均衡。此外,文章还讨论了集群外部访问Service的多种方式,以及OpenShift如何通过网络策略实现多租户的网络隔离。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一篇:PaaS中OpenShift持久化存储的管理实践

由于 OpenShift 网络通信概念较多,相对理解起来困难,为了方便读者能够清晰深入内部,在开始网络模型讲解之前,我们先尝试从 OpenShift 的用户角度,提出 5 个问题,并对 5 个问题作出解答,先对 OpenShift 网络通信有个大致的概念。然后读者带着对这 5 个问题的理解,阅读本章节更为详细的内容。

1. OpenShift 中 Pod 之间通讯是否一定需要 Service?

   

答案:Pod 之间的通信不需要 Service。

在同一个 Namespace 中, Pod A 开放了某个端口,在一个 Pod B 中 curl pod_A_IP:port,就能与之通信,如下图 2-45 所示。

aed0929214acc47c4da1b01308273b81.png

图 2-45 查看两个 pod 的 IP 地址

所以说:Pod 之间能不能通信,和两个 Pod 经不经过 Service、有没有 Service 无关。

2. 从一个 Pod 访问另外一个 Pod 可以通信,其数据链路是什么?

   

答案:两个 Pod 如果在一个 OpenShift 节点上,其通信流量没有绕出本宿主机的 OVS:如果两个 Pod 在不同节点上, Pod 之间的通信经过了 Vxlan。具体内容后文将展开说明。

3. 既然 Pod 之间通信不需要 Service,为何 Kubernetes 引入 Service?

   

我们首先要明确:Service 是对一组提供相同功能的 Pods 的抽象,并为它们提供一个统一的内部访问入口。它主要解决:

  1. 负载均衡:Service 提供其所属多个 Pod 的负载均衡

  2. 服务注册与发现:解决不同服务之间的通信问题。在 OpenShift 中的创建应用后,需要提供访问应用的地址供其他服务调用,这个地址就是由 Service 提供。

在 OpenShift 中,我们每创建一个 Service,会分配一个 IP 地址,称为 ClusterIP,这个 IP 地址是一个虚拟的地址(OpenShift 外部不可达),这样内部 DNS 就可以通过 Service 名称(FQDN)解析成 ClusterIP 地址。这就完成了服务注册,DNS 解析需要的信息全部保存在 Etcd 中。

那么,Service 注册到 Etcd 的内容是什么呢?

实际上是 Service 资源对象的 Yaml 包含的相关内容。

也就是说,Etcd 中记录的 Services 注册信息里有 Namespace,Service Name,ClusterIP 等,通过这三个信息就可组成 DNS A 记录,也就是,Service 的 FQDN 和 Service ip 之间的对应关系。需要说明的是,Etcd 不是 DNS,DNS A 记录是通过查询生成的。OpenShift 的 DNS 是由 SkyDNS/CoreDNS 实现的(后面内容详细介绍)。

服务发现这个词经常被妖魔化。它的作用是为了 OpenShift 某个服务发现另外一个服务。也就说,Service A 要和 ServiceB 通讯,我需要知道 ServiceB 是谁、在哪、Cluster IP、对应的 Pod IP 都是什么?这就叫服务发现。

4. 有了 Service 以后,Pod 之间的通讯和没有 Service 有何区别?

   

在数据通讯层,没区别,因为 Service 只是逻辑层面的东西。

但是,没有 Service,多个 Pod 无法实现统一入口,也无法实现负载均衡。也就是说,没有 Service,多个 Pod 之间的负载均衡就要依赖第三方实现。

那么,有了 Service 以后,Pod 之间怎么寻址?

回答这个问题,我们要站在开发者角度。如果一个程序员,要写微服务,微服务之间要相互调用,怎么写?写 Pod IP 和 ClusterIP 是不现实的,因为这两个 IP 可能发生变化。

如果程序员决定用 Kubernetes 做服务发现的前提下(如果使用微服务框架中的服务注册中心做服务注册发现,可以不使用 Kubernetes 的 Service),实现不同服务之间的调用,那么就需要使用 Kubernetes 的 Service 名称。因为 Service 名称我们是可以固定的。

OpenShift/Kubernetes 中 Service 有短名和长名。以下图 2-46 为例,jws-app 就是 Service 的短名,Service 长名的格式是:..svc.cluser.local,也就是 jws-app.web.svc.cluser.local。Service 短名可以自动补充成长名,这是 OpenShift 中的 DNS 做的,这个后面介绍。

12e0fb6c470ba9dca47a08f22826ada5.png

图 2-46 查看 Service 的名称

那么,如果在两个不同的 Namespace 中,有两个相同的 Service 短名,微服务调用不是会出现混乱?程序员的代码里是不是要写 Service 全名?

首先,站在 OpenShift 集群管理员的角度,我们看所有的项目,有几十个或者而更多,会觉得在不同 Namespaces 中存在相同的 Service 短名是可能(比如 Namespace A 中有个 acat 的 Service,Namespace B 中也有个 acat 的 Service)。但站在程序员角度,他只是 OpenShift 的使用者、拥有有自己的 Namespace 的管理权,其他 Namespace 不能访问。而且绝大多数情况下,同一个业务项目的微服务一般会运行在同一个 Namespace 中,默认如果使用短名称(只写 Service Name),则会自动补全成当前 Namespace 的 FQDN,只有在跨 Namespace 调用的时候才必须写全名 FQDN。

所以,程序员写的程序用到了 Service Name。那么,真正运行应用的 Pod 之间的通讯,也必然会以 Service Name 去找。通过 Service 名称解析为 Service ClusterIP,然后经过 Kube-proxy(默认 Iptables 模式)的负载均衡最终选择一个实际的 Pod IP。找到 Pod IP 以后,接下来就会进行实际的数据交换,这就和 Service 没有关系了。

5. ClusterIP 到 Pod IP 这部分的负载均衡怎么实现的?

   

目前版本 OpenShift 中是通过 kube-proxy(iptables 模式)实现的。具体内容后面内容详细介绍。

6

   

通过以上 5 个问题的问答,相信很多读者关于 OpenShift 通信网络的疑问有了大致的了解。接下来,我们针对 OpenShift 的网络通信展开讲述。

7

   

OpenShift 的网络模型

OpenShift 的网络模型继承于 Kubernetes,从内到外共包含如下四个方面:

  1. Pod 内部容器通信的的网络。

  2. Pod 与 Pod 通信的网络。

  3. Pod 和 Service 之间通信的网络。

  4. 集群外部与 Service 或 Pod 通信的网络。

这四部分构成了整个 OpenShift 的网络模型,下面我们分别进行说明。

7.1

   

Pod 内部容器通信的网络

我们都知道 Pod 是一组容器的组合,意味着每个 Pod 中可以有多个容器存在,那么这多个容器之间如何通信呢?这就是这部分要解决的问题。

Kubernetes 通过为 Pod 分配统一的网络空间,实现了多个容器之间网络共享,也就是同一个 Pod 中的容器之间通过 Localhost 相互通信。

7.2

   

Pod 与 Pod 通信的网络

关于这部分 Kubernetes 在设计之时的目标就是 Pod 之间可以不经过 NAT 直接通信,即使 Pod 跨主机。而这部分 Kubernetes 早期并未提供统一标准的方案,需要用户提前将节点网络配置完成,各个厂商提供了不同的解决方案,诸如 Flannel、OVS 等等。随着 Kubernetes 的发展,在网络方向上希望通过统一的方式来集成不同的网络方案,也就有了现在的网络开放接口 CNI(Container Network Interface)。

CNI 项目是由多个公司和项目创建组成的,包括 CoreOS、红帽、Apache Mesos、Cloud Foundry、Kubernetes、Kurma 和 rkt。CoreOS 首先提出定义网络插件和容器之间的通用接口,CNI 被设计为规范,它仅关注容器的网络连接并在删除容器时删除分配的网络资源。

CNI 有三个主要组成部分:

  1. CNI 规范:定义容器运行时和网络插件之间的 API。

  2. 插件:对各种 SDN 对接的组件。

  3. 库:提供 CNI 规范的 Go 实现,容器运行时可以使用它来便捷地使用 CNI。

各厂商遵守规范开发网络组件,在技术实现上共分为两大阵营:

  1. 基于二层实现:通过将 Pod 放在一个大二层网络中,跨节点通信通常使用 Vxlan 或 UDP 封包实现,常用的此类插件有 Flannel(UDP 或 Vxlan 封包模式)、OVS、Contiv、OVN 等。

  2. 基于三层实现:将 Pod 放在一个互联互通的网络中,通常使用路由实现,常用的此类插件有 Calico、Flannel-GW、Contiv、OVN 等。

可以看到网络插件的种类较为繁多,OpenShift 默认使用的是基于 OVS 的二层网络实现 Pod 与 Pod 之间的通信,后面我们将详细介绍。

7.3

   

Pod 和 Service 之间通信的网络

Pod 与 Service 之间的通信主要指在 Pod 中访问 Service 的地址。在 OpenShift 中, Service 是对一组提供相同功能的 Pods 的抽象,并为它们提供一个统一的内部访问入口。主要解决以下两个问题:

服务注册与发现:服务注册发现在微服务架构中,解决不同服务之间的通信问题。在 OpenShift 中的创建应用后

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值