CNI:容器网络接口
CNI 简介
不管是 docker 还是 kubernetes,在网络方面目前都没有一个完美的、终极的、普适性的解决方案,不同的用户和企业因为各种原因会使用不同的网络方案。目前存在网络方案 flannel、calico、openvswitch、weave、ipvlan等,而且以后一定会有其他的网络方案,这些方案接口和使用方法都不相同,而不同的容器平台都需要网络功能,它们之间的适配如果没有统一的标准,会有很大的工作量和重复劳动。
CNI 就是这样一个标准,它旨在为容器平台提供网络的标准化。不同的容器平台(比如目前的 kubernetes、mesos 和 rkt)能够通过相同的接口调用不同的网络组件。
CNI(Conteinre Network Interface) 是 google 和 CoreOS 主导制定的容器网络标准,它 本身并不是实现或者代码,可以理解成一个协议。这个标准是在 rkt 网络提议 的基础上发展起来的,综合考虑了灵活性、扩展性、ip 分配、多网卡等因素。
这个协议连接了两个组件:容器管理系统和网络插件。它们之间通过 JSON 格式的文件进行通信,实现容器的网络功能。具体的事情都是插件来实现的,包括:创建容器网络空间(network namespace)、把网络接口(interface)放到对应的网络空间、给网络接口分配 IP 等等。

关于网络,docker 也提出了 CNM 标准,它要解决的问题和 CNI 是重合的,也就是说目前两者是竞争关系。目前 CNM 只能使用在 docker 中,而 CNI 可以使用在任何容器运行时。CNM 主要用来实现 docker 自身的网络问题,也就是 docker network 子命令提供的功能。
官方网络插件
所有的标准和协议都要有具体的实现,才能够被大家使用。CNI 也不例外,目前官方在 github 上维护了同名的 CNI 代码库,里面已经有很多可以直接拿来使用的 CNI 插件。
官方提供的插件目前分成三类:main、meta 和 ipam。main 是主要的实现了某种特定网络功能的插件;meta 本身并不会提供具体的网络功能,它会调用其他插件,或者单纯是为了测试;ipam 是分配 IP 地址的插件。
ipam 并不提供某种网络功能,只是为了灵活性把它单独抽象出来,这样不同的网络插件可以根据需求选择 ipam,或者实现自己的 ipam。
这些插件的功能说明如下:
- main
- loopback:这个插件很简单,负责生成
lo网卡,并配置上127.0.0.1/8地址 - bridge:和 docker 默认的网络模型很像,把所有的容器连接到虚拟交换机上
- macvlan:使用 macvlan 技术,从某个物理网卡虚拟出多个虚拟网卡,它们有独立的 ip 和 mac 地址
- ipvlan:和 macvlan 类似,区别是虚拟网卡有着相同的 mac 地址
- ptp:通过 veth pair 在容器和主机之间建立通道
- loopback:这个插件很简单,负责生成
- meta
- flannel:结合 bridge 插件使用,根据 flannel 分配的网段信息,调用 bridge 插件,保证多主机情况下容器
- ipam
- host-local:基于本地文件的 ip 分配和管理,把分配的 IP 地址保存在文件中
- dhcp:从已经运行的 DHCP 服务器中获取 ip 地址
接口参数
网络插件是独立的可执行文件,被上层的容器管理平台调用。网络插件只有两件事情要做:把容器加入到网络以及把容器从网络中删除。调用插件的数据通过两种方式传递:环境变量和标准输入。一般插件需要三种类型的数据:容器相关的信息,比如 ns 的文件、容器 id 等;网络配置的信息,包括网段、网关、DNS 以及插件额外的信息等;还有就是 CNI 本身的信息,比如 CNI 插件的位置、添加网络还是删除网络。
我们来看一下为容器添加网络是怎么工作的,删除网络和它过程一样。
把容器加入到网络
调用插件的时候,这些参数会通过环境变量进行传递:
CNI_COMMAND:要执行的操作,可以是ADD(把容器加入到某个网络)、DEL(把容器从某个网络中删除)CNI_CONTAINERID:容器的 ID,比如 ipam 会把容器 ID 和分配的 IP 地址保存下来。可选的参数,但是推荐传递过去。需要保证在管理平台上是唯一的,如果容器被删除后可以循环使用CNI_NETNS:容器的 network namespace 文件,访问这个文件可以在容器的网络 namespace 中操作CNI_IFNAME:要配置的 interface 名字,比如eth0CNI_ARGS:额外的参数,是由分号;分割的键值对,比如 “FOO=BAR;hello=world”CNI_PATH:CNI 二进制查找的路径列表,多个路径用分隔符:分隔
网络信息主要通过标准输入,作为 JSON 字符串传递给插件,必须的参数包括:
cniVersion:CNI 标准的版本号。因为 CNI 在演化过程中,不同的版本有不同的要求name:网络的名字,在集群中应该保持唯一type:网络插件的类型,也就是 CNI 可执行文件的名称args:额外的信息,类型为字典ipMasq:是否在主机上为该网络配置 IP masqueradeipam:IP 分配相关的信息,类型为字典dns:DNS 相关的信息,类型为字典
插件接到这些数据,从输入和环境变量解析到需要的信息,根据这些信息执行程序逻辑,然后把结果返回给调用者,返回的结果中一般包括这些参数:
- IPs assigned to the interface:网络接口被分配的 ip,可以是 IPv4、IPv6 或者都有
- DNS 信息:包含 nameservers、domain、search domains 和其他选项的字典
CNI 协议的内容还在不断更新,请到官方文档获取当前的信息。
CNI 的特性
CNI 作为一个协议/标准,它有很强的扩展性和灵活性。如果用户对某个插件有额外的需求,可以通过输入中的 args 和环境变量 CNI_ARGS 传输,然后在插件中实现自定义的功能,这大大增加了它的扩展性;CNI 插件把 main 和 ipam 分开,用户可以自由组合它们,而且一个 CNI 插件也可以直接调用另外一个 CNI 插件,使用起来非常灵活。
如果要实现一个继承性的 CNI 插件也不复杂,可以编写自己的 CNI 插件,根据传入的配置调用 main 中已经有的插件,就能让用户自由选择容器的网络。
在 kubernetes 中的使用
CNI 目前已经在 kubernetes 中开始使用,也是目前官方推荐的网络方案,具体的配置方法可以参考kubernetes 官方文档。
kubernetes 使用了 CNI 网络插件之后,工作过程是这样的:
- kubernetes 先创建 pause 容器生成对应的 network namespace
- 调用网络 driver(因为配置的是 CNI,所以会调用 CNI 相关代码)
- CNI driver 根据配置调用具体的 cni 插件
- cni 插件给 pause 容器配置正确的网络
- pod 中其他的容器都是用 pause 的网络
参考资料
- CNI spec 文档
- Linux Network namespaces and CNI
- The container networking landscape: cni from coreos and cnm from docker
- CNI and OCI
http://cizixs.com/2017/05/23/container-network-cni
CNI:容器网络接口的更多相关文章
- Kubernetes CNI网络插件
CNI 容器网络接口,就是在网络解决方案由网络插件提供,这些插件配置容器网络则通过CNI定义的接口来完成,也就是CNI定义的是容器运行环境与网络插件之间的接口规范.这个接口只关心容器的网络连接,在创建 ...
- kubernets基础
1.定义和功能. 1.1定义:kubernets解释为舵手或者飞行员,以Borg为主衍生出. 1.2功能:自动装箱,自我修复,水平扩展,服务发现和负载均衡,自动发布和回滚. 密钥和配置管理,存储编排, ...
- k8s集群搭建指南
一.简介 Ansible Docker Docker compose,docker swarm,docker machine Mesos,marathon Kubernetes(占据80%的市场) D ...
- k8s入门简介
1.docker的三种编排工具 Docker的第一类编排工具: a.docker compose(docker原生):只能对一个主机上的容器进行编排,无法编排多个主机上的容器; b.docker sw ...
- K8s中的网络
Kubernetes的网络通信问题: 1. 容器间通信: 即同一个Pod内多个容器间通信,通常使用loopback来实现. 2. Pod间通信: K8s要求,Pod和Pod之间通信必须使用Pod-IP ...
- kubernetes基础——一文读懂k8s
容器 容器与虚拟机对比图(左边为容器.右边为虚拟机) 容器技术是虚拟化技术的一种,以Docker为例,Docker利用Linux的LXC(LinuX Containers)技术.CGroup(Co ...
- Flannel和Calico网络插件对比
1.Kubernetes通信问题 1.容器间通信:即同一个Pod内多个容器间通信,通常使用loopback来实现. 2.Pod间通信:K8s要求,Pod和Pod之间通信必须使用Pod-IP 直接访问另 ...
- kubernetes基础——1.基本概念
一.kubernetes特性 自动装箱,自我修复,水平扩展,服务发现和负载均衡,自动发布和回滚,密钥和配置管理,存储编排,批量处理执行. 二.kubernetes cluster Masters * ...
- calico和flannel的优缺点
1.Kubernetes通信问题 1.容器间通信:即同一个Pod内多个容器间通信,通常使用loopback来实现. 2.Pod间通信:K8s要求,Pod和Pod之间通信必须使用Pod-IP 直接访问另 ...
随机推荐
- less-!important关键字
//!important关键字 使用!important关键字混入调用之后,以标记它继承的所有属性!important,example: .test{ background:red; font-siz ...
- Flutter入门之有状态组件
StatefulComponent使用方法入门 在上一篇Flutter入门之无状态组件中我们讲到了无状态组件,所谓的无状态组件指的就是其内部的状态是来自其父组件并使用final类型的变量来存储,当组件 ...
- HDU 1863 畅通工程(Kruskal)
畅通工程 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submi ...
- requests 中response如何改变编码格式
查看初始编码 首先查看拿到的response编码格式: (就不放代码了,因为此例需要用到cookie,可自行找个网站具体测试) 可见初始编码为:ISO-8859-1 修改编码 初始编码: 修改后编码: ...
- plotly绘制直方图示例
计算数值出现的次数“ import cufflinks as cf cf.go_offline() import numpy as np import pandas as pd set_slippag ...
- 【算法题12 解码方法decode way】
1.来源LeetCode91 一条包含字母 A-Z 的消息通过以下方式进行了编码: 'A' -> 1 'B' -> 2 ... 'Z' -> 26 给定一个只包含数字的非空字符串,请 ...
- [Python] Send emails to the recepients specified in Message["CC"]
Recently, I'm working on a small program which needs to send emails to specific accounts. When I wan ...
- 配置数据库,Flask-Alchemy
Flask-Alchemy连接数据库的插件 获取当前项目路径(绝对路径) 来自为知笔记(Wiz)
- 动态切换数据库(EF框架)
文章简略:本文测试项目为Silverlight+EF+RIA Service动态切换数据库的问题 通常,Ado.net EntityFramework的数据库连接字符串Connect ...
- C语言预处理命令之条件编译(#ifdef,#else,#endif,#if等)
转自:http://www.kuqin.com/language/20090806/66164.html 预处理过程扫描源代码,对其进行初步的转换,产生新的源代码提供给编译器.可见预处理过程先于编译器 ...