1 CNI概述
1.1 什么是CNI?
Kubernetes 本身并没有实现自己的容器网络,而是借助 CNI 标准,通过插件化的方式来集成各种网络插件,实现集群内部网络相互通信。
CNI(Container Network Interface,容器网络的 API 接口),是 Google 和 CoreOS 联合定制的网络标准,它是在 RKT 网络提议的基础上发展起来的,综合考虑了灵活性、扩展性、IP 分配、多网卡等因素。Kubernetes 网络的发展方向是希望通过 Plugin 的方式来集成不同的网络方案, CNI 就是这一努力的结果。
CNI 旨在为容器平台提供网络的标准化,为解决容器网络连接和容器销毁时的资源释放,提供了一套框架。所以 CNI 可以支持大量不同的网络模式,并且容易实现。不同的容器平台(e.g. Kubernetes、Mesos 和 RKT)能够通过相同的接口调用不同的网络组件。
CNI(容器网络接口)是一个云原生计算基金会项目,它包含了一些规范和库,用于编写在 Linux 容器中配置网络接口的一系列插件。CNI 只关注容器的网络连接,并在容器被删除时移除所分配的资源。
Kubernetes 使用 CNI 作为网络提供商和 Kubernetes Pod 网络之间的接口。
1.2 CNI 规范
CNI 规范的几点原则:
- CNI Plugin 负责连接容器(Linux network namespace)。
- CNI 的网络定义以 JSON 的格式存储。
- 有关网络的配置通过 stdin(Linux 标准输入)的方式传递给 CNI Plugin,其他的参数通过 ENV(环境变量)的方式传递。
- CNI 插件是以 exec(可执行文件)的方式实现的。
CNI 规范定义的核心接口:
- ADD:将容器添加到网络;
- DEL:从网络中删除一个容器;
- CHECK:检查容器的网络是否符合预期等;
- ....
CNI 对象定义了两个组件,包括:
- Container Management System
- Network Plugin:CNI 接收到的具体请求都是由 Plugin 来完成的,例如:创建容器网络空间(network namespace)、把网络接口(interface)放到对应的网络空间、给网络接口分配 IP 等。
1.3 CNI Plugin
在部署 Kubernetes 的时候,有一个步骤是安装 kubernetes-cni 包,它的目的就是在宿主机上安装 CNI 插件所需的基础可执行文件。这些可执行文件包括(查看 /opt/cni/bin 目录可以看到):
$ ls -al /opt/cni/bin/
total 73088
-rwxr-xr-x 1 root root 3890407 Aug 17 2017 bridge
-rwxr-xr-x 1 root root 9921982 Aug 17 2017 dhcp
-rwxr-xr-x 1 root root 2814104 Aug 17 2017 flannel
-rwxr-xr-x 1 root root 2991965 Aug 17 2017 host-local
-rwxr-xr-x 1 root root 3475802 Aug 17 2017 ipvlan
-rwxr-xr-x 1 root root 3026388 Aug 17 2017 loopback
-rwxr-xr-x 1 root root 3520724 Aug 17 2017 macvlan
-rwxr-xr-x 1 root root 3470464 Aug 17 2017 portmap
-rwxr-xr-x 1 root root 3877986 Aug 17 2017 ptp
-rwxr-xr-x 1 root root 2605279 Aug 17 2017 sample
-rwxr-xr-x 1 root root 2808402 Aug 17 2017 tuning
-rwxr-xr-x 1 root root 3475750 Aug 17 2017 vlan
从 Network Plugin 实现的功能可以把 CNI Plugin 分为 5 类:
- Main 插件:创建具体的网络设备。有以下类型:
- bridge:网桥设备,连接 Container 和 Host;
- ipvlan:为容器增加 ipvlan 网卡;
- loopback:回环设备;
- macvlan:为容器创建一个 MAC 地址;
- ptp:创建一对 Veth Pair;
- vlan:分配一个 vlan 设备;
- host-device:将已存在的设备移入容器内。
- IPAM 插件:负责分配 IP 地址。有以下类型:
- dhcp:容器向 DHCP 服务器发起请求,给 Pod 发放或回收 IP 地址;
- host-local:使用预先配置的 IP 地址段来进行分配;
- static:为容器分配一个静态 IPv4/IPv6 地址,主要用于 Debug 场景。
- META 插件:其他功能的插件。有以下类型
- tuning:通过 sysctl 调整网络设备参数;
- portmap:通过 iptables 配置端口映射;
- bandwidth:使用 Token Bucket Filter 来限流;
- sbr:为网卡设置 source based routing;
- firewall:通过 iptables 给容器网络的进出流量进行限制。
- Windows 插件:专门用于 Windows 平台的 CNI 插件。
- win-bridge
- win-overlay 网络插件。
- 第三方网络插件:第三方开源的网络插件众多,每个组件都有各自的优点及适应的场景,难以形成统一的标准组件,常用有 Flannel、Calico、Cilium、OVN 网络插件。
大部分的 CN I插件功能设计上遵守功能职责单一原则,比如:
- Bridge 插件负责网桥的相关配置;
- Firewall 插件负责防火墙相关配置;
- Portmap 插件负责端口映射相关配置
1.4 CNI工作原理
CNI通过JSON格式的配置文件来描述网络配置,当需要设置容器网络时,由容器运行时负责执行CNI插件,并通过CNI插件的标准输入(stdin)来传递配置文件信息,通过标准输出(stdout)接收插件的执行结果。图中的 libcni 是CNI提供的一个go package,封装了一些符合CNI规范的标准操作,便于容器运行时和网络插件对接CNI标准。
案例:假如需要调用bridge插件将容器接入到主机网桥,则调用的命令如下:
# CNI_COMMAND=ADD 顾名思义表示创建。
# XXX=XXX 其他参数定义见下文。
# < config.json 表示从标准输入传递配置文件
CNI_COMMAND=ADD XXX=XXX ./bridge < config.json
1.5 CNI 使用了哪些网络模型?
CNI 网络插件使用封装网络模型(例如 Virtual Extensible Lan,缩写是 VXLAN)或非封装网络模型(例如 Border Gateway Protocol,缩写是 BGP)来实现网络结构。
1.5.1 什么是封装网络?
此网络模型提供了一个逻辑二层(L2)网络,该网络封装在跨 Kubernetes 集群节点的现有三层(L3)网络拓扑上。使用此模型,可以为容器提供一个隔离的 L2 网络,而无需分发路由。封装网络带来了少量的处理开销以及由于覆盖封装生成 IP header 造成的 IP 包大小增加。封装信息由 Kubernetes worker 之间的 UDP 端口分发,交换如何访问 MAC 地址的网络控制平面信息。此类网络模型中常用的封装是 VXLAN、Internet 协议安全性 (IPSec) 和 IP-in-IP。简单来说,封装网络模型在 Kubernetes worker 之间生成了一种扩展网桥,其中连接了 pod。
如果用户偏向使用扩展 L2 网桥,则可以选择此网络模型。此网络模型对 Kubernetes worker 的 L3 网络延迟很敏感。如果数据中心位于不同的地理位置,请确保它们之间的延迟较低,以避免最终的网络分段。
使用这种网络模型的 CNI 网络插件包括 Flannel、Canal、Weave 和 Cilium。默认情况下,Calico 不会使用此模型,但用户可以对其进行配置。
1.5.2 什么是非封装网络?
该网络模型提供了一个 L3 网络,用于在容器之间路由数据包。此模型不会生成隔离的 L2 网络,也不会产生开销。这些好处的代价是,Kubernetes worker 必须管理所需的所有路由分发。该网络模型不使用 IP header 进行封装,而是使用 Kubernetes Worker 之间的网络协议来分发路由信息以实现 Pod 连接,例如 BGP。
简而言之,这种网络模型在 Kubernetes worker 之间生成了一种扩展网络路由器,提供了如何连接 Pod 的信息。
如果用户偏向使用 L3 网络,则可以选择此网络模型。此模型在操作系统级别为 Kubernetes Worker 动态更新路由。对延迟较不敏感。
使用这种网络模型的 CNI 网络插件包括 Calico 和 Cilium。Cilium 可以使用此模型进行配置,即使这不是默认模式。
1.6 CNI社区插件
Kubernetes 它需要网络插件来提供集群内部和集群外部的网络通信。以下是一些常用的 k8s 网络插件:
- Flannel:Flannel 是最常用的 k8s 网络插件之一,它使用了虚拟网络技术来实现容器之间的通信,支持多种网络后端,如 VXLAN、UDP 和 Host-GW。
- Calico:Calico 是一种基于 BGP 的网络插件,它使用路由表来路由容器之间的流量,支持多种网络拓扑结构,并提供了安全性和网络策略功能。
- Canal:Canal 是一个组合了 Flannel 和 Calico 的网络插件,它使用 Flannel 来提供容器之间的通信,同时使用 Calico 来提供网络策略和安全性功能。
- Weave Net:Weave Net 是一种轻量级的网络插件,它使用虚拟网络技术来为容器提供 IP 地址,并支持多种网络后端,如 VXLAN、UDP 和 TCP/IP,同时还提供了网络策略和安全性功能。
- Cilium:Cilium 是一种基于 eBPF (Extended Berkeley Packet Filter) 技术的网络插件,它使用 Linux 内核的动态插件来提供网络功能,如路由、负载均衡、安全性和网络策略等。
- Contiv:Contiv 是一种基于 SDN 技术的网络插件,它提供了多种网络功能,如虚拟网络、网络隔离、负载均衡和安全策略等。
- Antrea:Antrea 是一种基于 OVS (Open vSwitch) 技术的网络插件,它提供了容器之间的通信、网络策略和安全性等功能,还支持多种网络拓扑结构。
-
kube-router:kube-router是一个开源的CNI插件,它结合了网络和服务代理功能。它支持BGP和IPIP协议,并具有负载均衡的特性。
提供商 | 项目 | Stars | Forks | Contributors |
Canal | GitHub - projectcalico/canal: Policy based networking for cloud native applications | 679 | 100 | 21 |
Flannel | GitHub - flannel-io/flannel: flannel is a network fabric for containers, designed for Kubernetes | 7k | 2.5k | 185 |
Calico | GitHub - projectcalico/calico: Cloud native networking and network security | 3.1k | 741 | 224 |
Weave | GitHub - weaveworks/weave: Simple, resilient multi-host containers networking and more. | 6.2k | 635 | 84 |
Cilium | GitHub - cilium/cilium: eBPF-based Networking, Security, and Observability | 10.6k | 1.3k | 352 |
1.7 第三方网络插件的功能
插件 | 网络模型 | 路线分发 | 网络策略 | 网络 | 外部数据存储 | 加密 | Ingress/Egress策略 |
Canal | 封装 (VXLAN) | 否 | 是 | 否 | K8s API | 是 | 是 |
Flannel | 封装 (VXLAN) | 否 | 否 | 否 | K8s API | 是 | 否 |
Calico | 封装(VXLAN,IPIP)或未封装 | 是 | 是 | 是 | Etcd 和 K8s API | 是 | 是 |
Weave | 封装 | 是 | 是 | 是 | 否 | 是 | 是 |
Cilium | 封装 (VXLAN) | 是 | 是 | 是 | Etcd 和 K8s API | 是 | 是 |
- 网络模型:封装或未封装
- 路由分发:一种外部网关协议,用于在互联网上交换路由和可达性信息。BGP 可以帮助进行跨集群 pod 之间的网络。此功能对于未封装的 CNI 网络插件是必须的,并且通常由 BGP 完成。如果想构建跨网段拆分的集群,路由分发是一个很好的功能。
- 网络策略:Kubernetes 提供了强制执行规则的功能,这些规则决定了哪些 service 可以使用网络策略进行相互通信。这是从 Kubernetes 1.7 起稳定的功能,可以与某些网络插件一起使用。
- 网格:允许在不同的 Kubernetes 集群间进行 service 之间的网络通信。
- 外部数据存储:具有此功能的 CNI 网络插件需要一个外部数据存储来存储数据。
- 加密:允许加密和安全的网络控制和数据平面。
- Ingress/Egress 策略:允许你管理 Kubernetes 和非 Kubernetes 通信的路由控制。
1.8 第三方插件实现方式
CNI 第三方网络插件通常有 3 种实现模式:
-
Overlay:靠隧道打通,不依赖底层网络;
-
Underlay:靠底层网络打通,强依赖底层网络;
-
路由:靠路由打通,部分依赖底层网络;
1.9 CNI 使用的 I/O 接口虚拟化
根据 CNI 插件不同的实现方式,也会使用到不同的 I/O 接口虚拟化技术。
- Veth-Pair:创建一个 Veth-Pair 对,两端分别接入到 Host root namespace(Linux Bridge / Open vSwitch)和 Container network namespace。Container 内发出的网络数据包,通过 vSwitch 进入到 Host OS Kernel Network Stack。
- Multi-Plexing(多路复用):使用一个 MACVLAN / IPVLAN 中间网络设备,虚拟出多个 Virtual NIC 接入到 Container,根据 MAC/IP 地址来区分数据报文如何转发到具体的容器。
- Hardware switching(硬件交换):SR-IOV 内部实现了一个 Hardware Switch,通过 VFs 的方式接入到每个 Pods。
2 k8s 支持哪些 CNI 插件?
RKE 可选择的 CNI 插件集成包括:Canal、Flannel、Calico 和 Weave 。RKE2 可以使用的是 Cillium、Calico、Canal 和 Multus。