Kubernetes网络和云厂商实践浅析

Kubernetes网络和云厂商实践浅析

原创 张向阳 云网漫步 2020-11-22
https://mp.weixin.qq.com/s?src=11&timestamp=1617936055&ver=2997&signature=czoNtYoc1oSn7KtlQknWvo*D*Q0GOWU2VI3rEKh6YtE9kSX4TOoMWQLrj8cPiKi9jDE-u4SIMSdM1iYpGw63aXBXZlz7XHUcOgrTiL335Qm9mxs0cJFYp7j1VpUx6IkF&new=1

0 前言

Kubernetes 是一个可移植的、可扩展的开源平台,用于管理容器化的工作负载和服务,可促进声明式配置和自动化。Kubernetes 源于希腊语,意为 "舵手" 或 "飞行员",Google 在 2014 年开源了 Kubernetes 项目,Kubernetes 建立在 Google 在大规模运行生产工作负载方面拥有十几年的经验的基础上(Brog系统),结合了社区中最好的想法和实践。

图片

    为了能实现Kubernetes有效的管理大规模的容器,需要优秀网络技术的支撑,本文主要从Kubernetes网络的角度去介绍Kubernetes网络的需求、网络模型、实现技术、云厂商Kubernetes的网络实践。

1 Kubernetes网络系统需求

集群网络系统是 Kubernetes 的核心部分,它需要解决下面四个问题。

  1. Pod内容器间通信。

  2. Pod 间通信。

  3. Pod 和服务间通信。

  4. 外部和服务间通信。

     Kubernetes 的宗旨就是在应用之间共享机器,共享机器需要两个应用之间不能使用相同的端口,但是在多个应用开发者之间去大规模地协调端口是件很困难的事情,尤其是还要让用户暴露在他们控制范围之外的集群级别的问题上。同时动态分配端口也会给系统带来很多复杂度,每个应用都需要设置一个端口的参数,而 API服务器还需要知道如何将动态端口数值插入到配置模块中,服务也需要知道如何找到对方等等。

    与其去解决这些问题,Kubernetes 选择了其他不同的方法,下面我们介绍一下Kubernetes 网络模型。

2 Kubernetes 网络模型

    Kubernetes 对所有网络设施的实施,都需要满足以下的基本要求(除非有设置一些特定的网络分段策略):
  1. 节点上的 Pod 可以不通过 NAT 和其他任何节点上的 Pod 通信。

  2. 节点上的代理(例如,系统守护进程、kubelet)可以和节点上的所有Pod通信。

    每一个Pod都有它自己的IP地址,这就意味着不需要显式地在每个Pod之间创建链接,也不需要处理容器端口到主机端口之间的映射。这样将创建一个干净的、向后兼容的模型,在这个模型里,从端口分配、命名、服务发现、负载均衡、应用配置和迁移的角度来看,Pod可以被视作虚拟机或者物理主机。同时还和 Kubernetes 的实现廉价的从虚拟机向容器迁移的初衷相兼容,如果你的工作开始是在虚拟机中运行的,你的虚拟机有一个 IP,这样就可以和其他的虚拟机进行通信,这是基本相同的模型。

3 Kubernetes 网络技术

    从上文看出,每个pod有自己唯一的IP地址,可通过一个扁平的、非NAT网络和其他Pod通信。Kubernetes是如何做到这一点呢?其实,Kubernetes不负责这块,网络是有Container Network Interface(CNI)插件进行管理。CNI是 CNCF 旗下的一个项目,由一组用于配置 Linux 容器的网络接口的规范和库组成,同时还包含了一些插件,CNI 仅关心容器创建时的网络分配,和当容器被删除时释放网络资源,如下图所示。

图片

    Kubernetes网络实现模型很多,从本质上看,使用网络技术有两大类,路由方案和Overlay网络方案。

3.1 Pod

3.1.1 Pod内container(容器)通信

图片

Pod中管理着一组容器,这些容器共享同一个网络命名空间。Pod中的每个容器拥有与Pod相同的IP和port地址空间,并且由于他们在同一个网络命名空间,他们之间可以通过localhost相互访问。

每个Pod容器有一个pause容器其有独立的网络命名空间,在Pod内启动容器时候使用 –net=container就可以让当前容器加入到Pod容器拥有的网络命名空间(pause容器)。

3.1.2 同节点的Pod通信

图片

每个Pod拥有一个ip地址,不同的Pod之间可以直接使用改ip与彼此进行通讯。在同一个Node上,从Pod的视角看,它存在于自己的网络命名空间中,并且需要与该Node上的其他网络命名空间上的Pod进行通信。

为了让多个Pod的网络命名空间链接起来,会创建一下veth pair对,veth对的一端链接到宿主机的网络命名空间,另一端链接到Pod的网络命名空间,并重新命名为eth0。

宿主机网络命名空间的接口会绑定到容器运行时配置使用的网络桥接上。从网桥的地址段中去IP地址赋值给容器的eth0接口。应用的任何运行在容器内部的程序都会发送数据到eht0网络接口,数据从宿主机命名空间的另外一个veth接口出来,然后发送给网桥。

3.1.3 不同节点的Pod通信

图片 不同节点上的pod能够通信,需要把这些节点的网桥以某种方式连接起来,有多种连接不同节点上的网桥的方式,例如通过三层路由,或者Overlay网络(隧道技术,例如GRE和VxLAN等)。

图片

路由方案

图片

Overlay方案

    pod通常需要对来自集群内部其他pod,以及来自集群外部的客户端的HTTP请求作出反应。pod需要一种寻找其他pod的方法来使用其他pod提供的服务。而在Kubernetes的网络中,有特殊的地方。
  1. 一个服务经常会起多个pod,你到底访问那个pod的ip呢?

  2. pod经常会因为各种原因被调度,调度后一个pod的ip会发生变化。

  3. pod的ip是虚拟的且局域的,在集群内部访问没有问题,但是从Kubernetes集群的外部如何访问pod的ip呢?

    为了解决第1,2的问题,Kubernetes提供了一种资源类型,服务(service)。为了解决第3个问题,Kubernetes有将服务的类型设置为NodePort,将服务的类型设置为LoadBanlance,创建一个Ingress资源。

3.2 Service

    Kubernetes的service(服务)是一种为一组功能相同的pod提供单一不变的接入点的资源。当服务存在时,它的ip地址和端口不会变化,客户端通过IP地址和端口号建立连接,这些连接会被路由到提供该服务的任意一个pod上。通过这种方式,客户端不需要知道每个单独的提供服务的pod的地址,这样这些pod可以在集群中随时被创建或者移除。

Kubernetes的服务需要解决两个主要问题。

  1. 服务怎么做负载均衡?

  2. 服务怎么被发现?

3.2.1 负载均衡

    在 Kubernetes 集群中,每个 Node 运行一个 kube-proxy 进程。kube-proxy 负责为 Service 实现了一种 VIP的形式。其实,服务并不是和pod直接相连的,它们之间是一种EndPoint资源。EndPoint资源就是暴露一个服务的IP地址和端口列表。

3.2.1.1 userspace 代理模式

图片

    kube-proxy 会监视 Kubernetes 主控节点对 Service 对象和 Endpoints 对象的添加和移除操作。对每个 Service,它会在本地 Node 上打开一个端口(随机选择)。任何连接到“代理端口”的请求,都会被代理到 Service 的后端 Pods 中的某个上面(如 Endpoints 所报告的一样)。使用哪个后端 Pod,是 kube-proxy 基于 SessionAffinity 来确定的。

    最后,它配置 iptables 规则,捕获到达该 Service 的 clusterIP(是虚拟 IP) 和 Port 的请求,并重定向到代理端口,代理端口再代理请求到后端Pod。默认情况下,用户空间模式下的 kube-proxy 通过轮转算法选择后端。

3.2.1.2 iptables 代理模式

图片

    kube-proxy 会监视 Kubernetes 控制节点对 Service 对象和 Endpoints 对象的添加和移除。对每个 Service,它会配置 iptables 规则,从而捕获到达该 Service 的 clusterIP 和端口的请求,进而将请求重定向到 Service 的一组后端中的某个 Pod 上面。对于每个 Endpoints 对象,它也会配置 iptables 规则,这个规则会选择一个后端组合。默认的策略是,kube-proxy 在 iptables 模式下随机选择一个后端。

    使用 iptables 处理流量具有较低的系统开销,因为流量由 Linux netfilter 处理, 而无需在用户空间和内核空间之间切换。这种方法也可能更可靠。

    如果 kube-proxy 在 iptables 模式下运行,并且所选的第一个 Pod 没有响应, 则连接失败。这与用户空间模式不同:在这种情况下,kube-proxy 将检测到与第一个 Pod 的连接已失败, 并会自动使用其他后端 Pod 重试。

3.2.1.3 IPVS 代理模式

图片

    在 ipvs 模式下,kube-proxy监视Kubernetes服务和端点,调用 netlink 接口相应地创建 IPVS 规则, 并定期将 IPVS 规则与 Kubernetes 服务和端点同步。该控制循环可确保IPVS 状态与所需状态匹配。访问服务时,IPVS 将流量定向到后端Pod之一。

     IPVS代理模式基于类似于 iptables 模式的 netfilter 挂钩函数, 但是使用哈希表作为基础数据结构,并且在内核空间中工作。与iptables 模式下的 kube-proxy 相比,IPVS 模式下的 kube-proxy 重定向通信的延迟要短,并且在同步代理规则时具有更好的性能。与其他代理模式相比,IPVS 模式还支持更高的网络流量吞吐量。IPVS提供了更多选项来平衡后端Pod的流量。

3.2.2 服务发现

Kubernetes 支持两种基本的服务发现模式 —— 环境变量和 DNS。

通过环境变量发现服务

    在pod开始运行的时候,Kubernetes会初始化一系列的环境变量指向现在存在的服务

    注:当您具有需要访问服务的Pod时,并且您正在使用环境变量方法将端口和群集 IP 发布到客户端 Pod 时,必须在客户端 Pod 出现 之前 创建服务。否则,这些客户端 Pod 将不会设定其环境变量。

通过DNS发现服务

    支持群集的 DNS 服务器监视 Kubernetes API 中的新服务,并为每个服务创建一组 DNS 记录。如果在整个群集中都启用了 DNS,则所有 Pod 都应该能够通过其 DNS 名称自动解析服务。

3.2.3 发布服务

    对一些应用(如前端)的某些部分,可能希望通过外部 Kubernetes 集群外部 IP 地址暴露 Service。

    Kubernetes ServiceTypes 允许指定一个需要的类型的 Service,默认是 ClusterIP类型。

    ClusterIP:通过集群的内部 IP 暴露服务,选择该值,服务只能够在集群内部可以访问,这也是默认的 ServiceType。

    NodePort:通过每个 Node 上的 IP 和静态端口(NodePort)暴露服务。NodePort 服务会路由到 ClusterIP 服务,这个 ClusterIP 服务会自动创建。通过请求 <NodeIP>:<NodePort>,可以从集群的外部访问一个 NodePort 服务。

    LoadBalancer:使用云提供商的负载均衡器,可以向外部暴露服务。外部的负载均衡器可以路由到 NodePort 服务和 ClusterIP 服务。

3.3 Ingress

    我们也可以使用 Ingress 来暴露自己的服务。

    为什么需要Ingress呢?一个重要的原因是每个LoadBalancer服务都需要自己的负载均衡器,以及独有的公用IP地址,而Ingress只需要一个公网IP就能为很多服务提供访问。例如,当客户端向Ingress发送HTTP请求时,Ingress会根据请求的主机和路径决定请求转发到的服务。

图片

  1. 客户端先执行DNS查询,DNS服务器返回了Ingress控制器的IP地址。

  2. 客户端然后向Ingress控制器发送HTTP请求,并在Host头部中指定访问的域名。

  3. 控制器从该Host头部确认客户端尝试访问哪个服务,通过与该服务关联的Endpoint对象查看pod IP,并将客户端的请求转发给其中一个pod。

4. 云厂商Kubernetes实践

4.1 AWS Kubernetes网络方案

AWS上搭建Kubernetes集群环境有两种方式,一种是使用托管服务Amazon Elastic Kubernetes Service (Amazon EKS) ,一种是自建K8S集群。可以使用Amazon VPC CNI插件管理Pod的网络地址和通信。

图片

EKS网络架构

4.1.1 VPC CNI插件

    AWS VPC CNI 为 Kubernetes 集群提供了集成的 AWS 虚拟私有云(VPC)网络,使用该 CNI 插件,可使 Kubernetes Pod 拥有与在 VPC 网络上相同的 IP 地址。CNI 将 AWS 弹性网络接口(ENI)分配给每个 Kubernetes 节点,并将每个 ENI 的辅助 IP 范围用于该节点上的 Pod 。

图片

Kubernetes 的 Amazon VPC 容器网络接口 (CNI) 插件随每个节点一起部署,插件包含两个主要组件。

    **L-IPAM 守护程序**\-负责创建网络接口并将网络接口附加到 Amazon EC2 实例,将辅助 IP 地址分配给网络接口,并在每个节点上维护 IP 地址的地址池,以便在安排时分配到 Kubernetes Pod。

    **CNI 插件** – 负责连接主机网络(例如,配置网络接口和虚拟以太网对)并向 Pod 命名空间添加正确的网络接口。

4.1.2 Pod通信

    VPC 内的通信(如 Pod 到 Pod)在私有 IP 地址之间是直接通信。

4.1.2 Pod和外部通信

     当流量以 VPC 外部的地址为目标时,默认情况下,Kubernetes 的 Amazon VPC CNI 插件将每个 Pod 的私有 IP 地址转换为分配给 Pod 在其上运行的 节点的主 网络接口Amazon EC2(网络接口)的主私有IP地址,有如下两种方式。

图片

图片

4.1.3 Ingress

    AWS ALB Ingress 控制器将在Kubernetes 用户声明集群上的 Ingress 资源时触发创建 ALB 以及必要的 AWS 支持资源。Ingress 资源通过 ALB 将 HTTP\[s\] 流量路由至集群内的不同终端节点。

图片

  1. 控制器观察来自 API 服务器的进站事件。如果发现 Ingress 资源满足要求,则将开始创建 AWS 资源。

  2. 为 Ingress 资源创建 ALB。

  3. 为 Ingress 资源中指定的每个后端创建目标组。

  4. 为 Ingress 资源注释中指定的每个端口创建侦听器。如果未指定端口,则将使用合理的默认值(80 或 443)。

  5. 为 Ingress 资源中指定的每个路径创建规则。这将确保指向特定路径的流量将被路由至所创建的正确目标组。

4.2 GCP Kubernetes网络方案

Google Kubernetes Engine (GKE) 提供了一个托管环境,可以使用 Google 基础架构在其中部署、管理和扩缩容器化应用。

图片

4.2.1 Pod通信

图片

4.2.2 Service

图片

4.2.3 Loadbalancer

图片

具体细节,参考GCP的官方文档。

https://cloud.google.com/kubernetes-engine/docs/concepts/network-overview

4.3 阿里云Kubernetes网络方案

图片

阿里云容器服务产品线的整体架构

本章节是介绍阿里云容器服务Kubernetes版ACK(Alibaba Cloud Container Service for Kubernetes)。

4.3.1 网络模型

    容器服务将Kubernetes网络和阿里云VPC的深度集成,提供了稳定高性能的容器网络。在容器服务中,支持以下类型的互联互通。
  1. 同一个容器集群中,Pod之间相互访问。

  2. 同一个容器集群中,Pod访问Service。

  3. 同一个容器集群中,ECS访问Service。

  4. Pod直接访问同一个VPC下的ECS。

  5. 同一个VPC下的ECS直接访问Pod。

4.3.2 阿里云Terway网络插件

    Terway网络插件是阿里云容器服务的网络插件,功能上完全兼容Flannel。

        支持将阿里云的弹性网卡分配给容器。

        支持基于Kubernetes标准的NetworkPolicy来定义容器间的访问策略,兼容Calico的Network Policy。

图片

    在Terway网络插件中,每个Pod拥有自己网络栈和IP地址。同一台ECS内的Pod之间通信,直接通过机器内部的转发,跨ECS的Pod通信,报文通过VPC的vRouter转发。由于不需要使用VxLAN等的隧道技术封装报文,因此具有较高的通信性能。

4.4 腾讯云Kubernetes网络方案

腾讯云容器服务(Tencent Kubernetes Engine ,TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务。

本章节主要参考以下文章,公众号:腾讯云原生 公众号文章:腾讯云容器服务TKE推出新一代零损耗容器网络

4.4.1 GlobalRouter 模式

    基于 vpc 实现的全局路由模式,目前是 TKE 默认网络方案。该模式依托于 vpc 底层路由能力,不需要在节点上配置 vxlan 等 overlay 设备,就可实现容器网络 和 vpc 网络的互访,并且相比于 calico/flannel 等网络方案,没有额外的解封包,性能也会更好。

图片

4.4.1 VPC-CNI 模式

    TKE 基于 CNI 和 VPC 弹性网卡实现的容器网络能力,适用于 Pod 固定 IP,CLB 直通 Pod,Pod 直绑 EIP 等场景。该网络模式下,容器与节点分布在同一网络平面,容器 IP 为 IPAMD 组件所分配的弹性网卡 IP。

图片

4.4.3 VPC-CNI-**独立网卡**

    依托于弹性网卡,将绑定到节点的弹性网卡通过 CNI 配置到容器网络命名空间,实现容器直接独享使用弹性网卡。

图片

4.5 其他CNI插件

参考链接

https://kubernetes.io/zh/docs/concepts/cluster-administration/networking/

5 总结

 本文主要介绍了Kubernetes的网络实现,包括pod的通信,服务(service),Ingress的实现,也简要介绍了云厂商的CNI插件的实现方法。Kubernetes还有其他优秀的网络插件,各个插件的实现方式有所不同,不过Kubernetes网络模型是不变。

最后欢迎大家留言沟通交流。

6 参考文献

Kubernetes集群网络系统

https://kubernetes.io/zh/docs/concepts/cluster-administration/networking/

Amazon EKS

https://docs.amazonaws.cn/eks/latest/userguide/external-snat.html

Amazon VPC CNI

https://aws.amazon.com/cn/blogs/china/use-amazon-vpc-cni-build-default-net-kubernetes-groups/

Google Kubernetes Engine (GKE)

https://cloud.google.com/kubernetes-engine/docs/concepts/network-overview

kubernetes网络和CNI简介

https://www.jianshu.com/p/88062fa25083

Understanding kubernetes networking: pods

https://medium.com/google-cloud/understanding-kubernetes-networking-pods-7117dd28727

containernetworking/cni

https://github.com/containernetworking/cni

Amazon Elastic Container Service

https://docs.aws.amazon.com/AmazonECS/latest/developerguide/Welcome.html

CNI - Container Network Interface(容器网络接口)

https://jimmysong.io/kubernetes-handbook/concepts/cni.html

containernetworking/cni

https://github.com/containernetworking/cni


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。也可以邮件至 1209453173@qq.com