Kubernetes容器网络及Flannel插件详解

标签: kubernetes 容器 网络 | 发表时间:2022-05-30 15:07 | 作者:程序员王越
出处:https://juejin.cn/backend

theme: smartblue highlight: a11y-dark

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天, 点击查看活动详情

1.1.容器网络基础

图片

Kubernetes是一个开源容器调度编排引擎,管理大规模容器化应用,采用典型的Master-Worker主从分布式技术架构,由集中式管理节点(Master Node),分布式的工作节点(Worker Node)组成。向下屏蔽底层差异化的分布式基础设施,以应用为中心构建云计算的基础操作系统能力(即云原生操作系统),面向用户提供云原生时代的云计算的新界面。

其中,Kubernetes网络至关重要,如果管理节点是控制大脑,运行节点是执行载体,那么网络就是将整个容器集群打通形成一个整体的神经网络;与Docker网络相比,Kubernetes网络最大的特点就是让容器组(Pod)拥有自己的身份证,即独立IP,实现在任何节点上的Pod都可以互相直接通信,而不需要任何的NAT地址转换;在不做限制时,Pod可以访问任何网络,并且拥有独立的网络栈,集群内部可见地址与外部可见地址保持一致。

在容器网络的具体实现上,Kubernetes通过开放的CNI标准,以插件化方式引入多种容器网络实现,从而支持各种差异化的场景的需求;当前社区比较常见的网络插件主要有Flannel、Calico、Cilium、OVN等,每个插件有不同的模式,需要按照实际的场景来选择使用。按照POD通信方式,有同主机的容器通信与跨主机的容器通信两大类型。

图片

(一)同主机的容器通信

在kubernetes集群的节点上,会创建一个veth(virtual ethernet)虚拟设备,同时将veth一端插入到容器网络的命名空间中,一端连接到主机上的网桥(linux bridge)。这样在同一主机上的POD通过veth实现IP地址相互通信。网桥也会分配一个IP地址,充当从POD到不同节点的出口流量网关。

(二)跨主机的容器通信

在不同主机上运行的容器POD通过IP地址相互通信,需要通过网络插件实现,按照依赖底层的技术大致可以分为Overlay模式,路由模式,Underlay模式三大类:

图片

① Overlay模式是在二层或三层网络之上再构建起来一个独立的网络,这个网络通常会有自己独立的IP地址空间、交换或者路由的实现。VXLAN协议是目前最流行的Overlay网络隧道协议之一,显著优势就是灵活,对底层网络没有侵入性。

② 路由模式放弃了跨主机容器在L2的连通性,而专注于通过路由协议提供容器在L3的通信方案;路由模式更易于集成到现在的数据中心的基础设施之上,便捷地连接容器和主机,并在报文过滤和隔离方面有着更好的扩展能力及更精细的控制模型。

③ Underlay模式是借助驱动程序将宿主机的底层网络接口直接暴露给容器使用的一种网络构建技术,较为常见的解决方案有MAC VLAN、IP VLAN和直接路由等。

1.2.Flannel网络插件

Flannel是由go语言开发,是一种基于overlay网络的跨主机容器网络插件。Flannel插件为集群中所有节点重新规划IP地址的分配规则,使得不同节点上的容器能够在同一个子网内,且IP地址不重复,实现不同节点上的容器通过内网IP直接通信。Flannel目前支持udp、vxlan、host-gw、aws-vpc、gce和alloc路由等多种灵活模式。但Flannel缺少必要的安全隔离,Qos等能力,适合常见简单,安全隔离要求较低的场景。以下是Flannel三种模式比较:

模式 底层网络要求 实现模式 封包/解包 overlay网络 转发效率
Flannel UDP 三层网络 overlay 用户态 三层
Flannel VXLAN 三层网络 overlay 内核态 二层
Flannel host-gw 二层网络 路由 三层

在Flannel VXLAN模式时,插件会在kubernetes集群的每个节点上创建vxlan设备与路由表。发往不同主机上容器数据包都会通过vxlan设备,封装成UDP数据发往目的地;在目的主机上,封装的UDP数据包会被解压并路由到目标POD。但是具体到POD如何分配IP,以及整个容器生命周期过程中CNI插件与其他组件怎么交互配合,是一个相当复杂的过程,本文通过Flannel插件,以及容器运行时Containerd,详细的说明容器网络运行的全过程。

1.3.Kubelet、Container Runtime和CNI插件

1.3.1.Pod IP地址分配机制

当节点首次向集群注册时,nodeipam作为选项传递给kube-controller-manager的--controllers参数,控制器就会从集群CIDR(集群网络的IP范围)中为每个节点分配一个专用子网(podCIDR)。由于节点子网podCIDR保证不会重复,所以在为节点POD分配的IP地址也确保了唯一;如果需要更改节点的podCIDR,可以通过取消注册节点再重新注册实现。使用以下命令列出节点的podCIDR:

  $ kubectl get no-o json | jq '.spec.podCIDR'10.244.0.0/24

1.3.2.Pod启动时网络配置过程

图片

当一个POD被调度到节点时,会有很多初始化操作,以下是网络配置相关的配置及初始化过程详细步骤:

① POD被调度到容器集群的某个节点上

② 节点的kubelet通过调用CRI插件来创建POD

③ CRI插件创建POD Sandbox ID与POD网络命名空间

④ CRI插件通过POD网络命名空间和POD Sandbox ID来调用CNI插件

⑤ CNI插件配置POD网络,调用顺序从Flannel CNI插件,Bridge CNI 插件到主机IPAM CNI 插件,最后返回POD IP地址。

⑥ 创建Pause容器,并将其添加第三步创建的POD的网络命名空间

⑦ Kubelet调用CRI插件拉取应用容器镜像

⑧ 容器运行时containerd拉取应用容器镜像

⑨ Kubelet调用CRI插件来启动应用容器

⑩ CRI插件调用容器运行时containerd来启动和配置在pod cgroup和namespaces中的应用容器。

1.3.3.CRI插件与CNI插件的交互

在POD初始化过程中,CRI插件会调用CNI插件来完成对POD网络的配置。CNI网络插件都会在kubernetes节点上安装配置代理,并附带CNI配置,然后CRI插件通过该配置来确定要调用那个CNI插件。CNI配置文件的位置默认值为/etc/cni/net.d/,可以自定义配置。同时在每个节点上都会有CNI插件,CNI插件位置默认值为/opt/cni/bin,也可以自定义配置。在containerd作为容器运行时,CNI配置和CNI插件二进制文件的路径可以在containerd配置的[plugins."io.containerd.grpc.v1.cri".cni]中指定。

对于Flannel插件,Flanneld作为Flannel守护进程,通常安装在 kubernetes集群的节点上,而install-cni作为init容器,在每个节点上创建 CNI配置文件-/etc/cni/net.d/10-flannel.conflist。Flanneld创建vxlan设备,从API-SERVER获取并监听POD网络元数据。在创建POD时,为整个集群中的所有POD分配路由,通过路由实现POD IP地址相互通信。CRI插件与CNI插件之间的交互如下:

图片

① Kubelet通过CRI插件调用容器运行时

② CRI插件通过CNI配置文件调用CNI插件,为POD创建网络命名空间,网络命名空间在/var/run/netns/文件下

③ Flannel CNI插件配置和调用Bridge CNI plugin

④ Bridge CNI插件在主机上创建cniO网桥,并创建了veth对,一端插入容器网络命名空间,另一端连接到cniO网桥。然后调用已配置的IPAM 插件。

⑤ host-local IPAM插件返回容器的IP地址和网关(cniO桥作为容器的网关),将IP地址分配给POD,桥接插件将网关IP地址分配给cniO桥接。所有分配的IP地址都存储在本地磁盘上的/var/lib/cni/networks/cni0/目录下。

1.3.4.CNI插件间的交互

图片

CNI插件配置POD网络,调用顺序从Flannel CNI插件,Bridge CNI 插件到主机IPAM CNI 插件,最后返回POD IP地址。详情如下:

① Flannel CNI插件:Containerd CRI插件使用CNI配置文件- /etc/cni/net.d/10-flannel.conflist调用Flannel CNI插件:

  $ cat /etc/cni/net.d/10-flannel.conflist{  "name": "cni0",  "plugins": [    {      "type": "flannel",      "delegate": {       "ipMasq": false,        "hairpinMode": true,        "isDefaultGateway": true      }    }  ]}

当Flanneld启动时,会从API-SERVER获取podCIDR和其他与网络相关的详细信息,并存储在 -/run/flannel/subnet.env文件中:

  FLANNEL_NETWORK=10.244.0.0/16 
FLANNEL_SUBNET=10.244.0.1/24
FLANNEL_MTU=1450 
FLANNEL_IPMASQ=false

Flannel CNI插件使用/run/flannel/subnet.env中的信息来配置和调用网桥CNI插件。

② Bridge CNI插件:Flannel CNI插件调用Bridge CNI插件,配置如下:

  {
  "name": "cni0",
  "type": "bridge",
  "mtu": 1450,
  "ipMasq": false,
  "isGateway": true,
  "ipam": {
    "type": "host-local",
    "subnet": "10.244.0.0/24"
  }
}

首次调用Bridge CNI插件时,会创建一个linux网桥,并在配置文件中指定“名称”:“cni0”。然后为每一个POD创建veth对,veth对一端位于容器的网络命名空间中,另一端连接到主机网络的网桥上,使用 Bridge CNI插件,主机上的所有容器都连接到主机网络的网桥上。

配置veth对后,Bridge插件调用主机本地IPAM CNI插件,可以在CNI config CRI插件中配置使用具体IPAM 插件。

③ 主机本地 IPAM CNI 插件:Bridge CNI插件使用以下配置调用主机本地 IPAM CNI 插件:

  {
  "name": "cni0",
  "ipam": {
    "type": "host-local",
    "subnet": "10.244.0.0/24",
    "dataDir": "/var/lib/cni/networks"
  }
}

Host-local IPAM(IP地址管理)插件从子网返回容器的IP地址,并将分配的IP本地存储在主机上dataDir下指定的目录下- /var/lib/cni/networks/。/var/lib/cni/networks/文件包含分配 IP 的容器 ID。

调用时,主机本地IPAM 插件返回以下结果:

  {
  "ip4": {
    "ip": "10.244.4.2",
    "gateway": "10.244.4.3"
  },
  "dns": {}
}

1.4.总结

总体来说,容器网络是Kubernetes最复杂部分,同时也是设计精华所在,通过CNI标准开放,根据实际需求实现不同的CNI来满足差异化的需求,尤其是与底层基础云能力深度集成的场景,每个云厂商都有实现各自高效的网络插件。整个容器网络大致从以下三个方面理解:

首先,在整体设计上,让POD有唯一的IP地址,通过为每个节点分配一个子网,从而保证节点为POD分配的IP地址,在整个集群内部不会重复。

其次,在容器网络是实现上,通过CNI将容器网络标准与具体实现解耦分类,通过插件引入不同的容器网络插件。

最后,在容器POD创建时,通过Kubelet,CRI插件,以及CNI插件相互配合,实现容器POD网络配置及初始化。

相关 [kubernetes 容器 网络] 推荐:

Kubernetes容器网络及Flannel插件详解

- - 掘金 后端
这是我参与「掘金日新计划 · 6 月更文挑战」的第2天, 点击查看活动详情. Kubernetes是一个开源容器调度编排引擎,管理大规模容器化应用,采用典型的Master-Worker主从分布式技术架构,由集中式管理节点(Master Node),分布式的工作节点(Worker Node)组成. 向下屏蔽底层差异化的分布式基础设施,以应用为中心构建云计算的基础操作系统能力(即云原生操作系统),面向用户提供云原生时代的云计算的新界面.

挖财的 Kubernetes 容器化之路

- - DockOne.io
【编者的话】挖财内部对容器化项目的代号为 K2 (乔戈里峰),乔戈里峰是世界第二高峰,但攀登极富挑战,寓意就是面对挑战,勇攀高峰;). 项目从 2016 年 11 月到现在已经有三年的时间了,如今挖财内部测试环境早已全部 Docker 容器化,而线上环境也运行着重要的业务. 经历从零到一的整个落地过程,回顾下来,这座高峰算是拿下了.

Kubernetes Service iptables 网络通信验证

- - 三点水
Kubernetes gives Pods their own IP addresses and a single DNS name for a setof Pods, and can load-balance across them.. K8s Service会为每个 Pod 都设置一个它自己的 IP,并为一组 Pod 提供一个统一的 DNS 域名,还可以提供在它们间做负载均衡的能力.

使用 Cilium 增强 Kubernetes 网络安全

- - IT瘾-dev
在本篇,我们分别使用了 Kubernetes 原生的网络策略和 Cilium 的网络策略实现了 Pod 网络层面的隔离. 不同的是,前者只提供了基于 L3/4 的网络策略;后者支持 L3/4、L7 的网络策略. 通过网络策略来提升网络安全,可以极大降低了实现和维护的成本,同时对系统几乎没有影响. 尤其是基于 eBPF 技术的 Cilium,解决了内核扩展性不足的问题,从内核层面为工作负载提供安全可靠、可观测的网络连接.

将 Java 应用容器化改造并迁移到 Kubernetes 平台

- - IT瘾-dev
为了能够适应容器云平台的管理模式和管理理念,应用系统需要完成容器化的改造过程. 对于新开发的应用,建议直接基于微服务架构进行容器化的应用开发;对于已经运行多年的传统应用系统,也应该逐步将其改造成能够部署到容器云平台上的容器化应用. 本文针对传统的Java 应用,对如何将应用进行容器化改造和迁移到Kubernetes 平台上进行说明.

三小时学会Kubernetes:容器编排详细指南

- -
这份指南与其他文章有何不同之处. 大多数指南是从Kubernetes概念和kubectl命令这类简单的东西开始的. 它们假定读者熟悉应用程序开发、微服务和Docker容器. 而在我们这篇文章中,步骤是:. 在你的计算机上运行基于微服务的应用程序. 为微服务应用程序的每个服务构建容器镜像. 介绍Kubernetes.

小米Redis的Kubernetes容器化部署实践

- - DockOne.io
【编者的话】本文讲述了小米是如何将Redis Cluster部署在Kubernetes上提供高质量的服务的. 小米的Redis使用规模很大,现在有数万个实例,并且每天有百万亿次的访问频率,支撑了几乎所有的产品线和生态链公司. 之前所有的Redis都部署在物理机上,也没有做资源隔离,给管理治理带来了很大的困难.

Kubernetes - 集群内容器访问集群外服务

- - 掘金后端
GitHub地址: github.com/QingyaFan/c…. 企业内部一般存在很多的微服务,在逐步容器化的过程中,会有部分服务在集群外部,未完成容器化,比如数据库,而部分已经完成容器化的依赖于这些服务的服务,过渡过程中,需要集群内部的容器访问集群外部的服务. 为了在容器化过程中,让服务不中断,就需要让Kubernetes集群内部的容器能访问集群外部的服务,怎么做到呢,在每个应用的配置文件中使用外部IP或者外部rds名字吗.

有道Kubernetes容器API监控系统设计和实践

- - DockOne.io
【编者的话】本篇文章将分享有道容器服务API监控方案,这个方案同时具有轻量级和灵活性的特点,很好地体现了Kubernetes集群化管理的优势,解决了静态配置的监控不满足容器服务监控的需求. 并做了易用性和误报消减、可视化面板等一系列优化,目前已经超过80%的容器服务已经接入了该监控系统. Kubernetes 已经成为事实上的编排平台的领导者、下一代分布式架构的代表,其在自动化部署、监控、扩展性、以及管理容器化的应用中已经体现出独特的优势.

调试Kubernetes集群中的网络停顿问题

- - DockOne.io
我们曾经在这里中聊起过Kubernetes ( Kubernetes at GitHub : https://github.blog/2017-08-16. ithub/),在过去几年,Kubernetes在Github已经成为标准的部署模式. 目前在Github,我们在Kubernetes上运行着海量的面向内部团队以及面向C端的服务.