k8s CNI
文章目录
介绍什么是 CNI 以及如何动手写一个 CNI-IPAM-plugin
CNI
- CNI – Container Network Interface - networking for Linux containers.
- CNCF(Cloud Native Computing Foundation) 项目.
- 包含了 spec 规范和一些制作 CNI 插件(plugin)所可选用的(golang)库.
- CNI 项目地址: containernetworking/cni
- 部分实现的 plugin 项目地址: containernetworking/plugins
cni-spec
- 因为篇幅受限/懒, 以及官方的文档写的挺简单/清晰的, 所以参见: Container Networking Interface Proposal (0.3.1)
- 0.3.0 版本的 spec 竟然出现了一个语义上的 typo, 在 0.3.1 上修复了, 就是
ip: []
->ips: []
. (笑
cni-plugin
- 项目地址 containernetworking/plugins
- main plugin 是拥有完整实现容器连通性功能的插件, (e.g. bridge/macvlan/ptp/ipvlan)
- ipam plugin 是 IPAM (IP Address Management) 的实现.
To lessen the burden and make IP management strategy be orthogonal to the type of CNI plugin
, (e.g. dhcp/host-local) - meta plugin 是拥有部分功能的插件, 必须依赖其他的
main plugin
链式使用, 如 tuning 是为了It reads in its own netconf, it does not create any network interface but just changes the network sysctl
bridge (main)
- 在 host 的 ns 下将各个容器连接到 bridge(virtual switch) 上, 然后给容器内的 veth peer 分配 IP.
- 可以给该 bridge 绑定 IP, 就变成所有容器的网关, 或者当做一个纯 L2 交换机(此模式下, 容器与容器之间无法连通 To-be-confirmed).
- 如果 ipam 没提供 ip 的 gw, 会默认用
掩码+1
当做 gw. - 目前源码中看到 PromiscMode 只能 up 不能 down
ipvlan (main)
- 一种 L3 虚拟化.
- 和
macvlan
是表兄弟关系,Like its cousin macvlan, it virtualizes the host interface.
- 因为共享 mac, 目前不支持 dhcp ipam
- 虚拟 interface 不能和主机沟通
'ipvlan' does not allow virtual interfaces to communicate with the master interface.
- master interface 不能同时启用
ipvlan
和macvlan
macvlan (main)
- 一种 L2 虚拟化.
- 所有 interface 共享物理网卡, 但每个 interface 有不同的 mac 地址
- 因为每个 interface 都有自己的 mac 地址, 所以可以很简单地使用 dhcp ipam
- 大部分无线网卡可能不支持
- 和
ipvlan
是表兄弟关系 - master interface 不能同时启用
ipvlan
和macvlan
ptp (main)
- 似乎是
bridge
的简化版, 直接用 host 当做 bridge. - 所以似乎现在默认是用 host-local ipam.
dhcp (ipam)
- 依靠网络中现有的 DHCP server.
- 因为容器并不管/关心 IP 是怎么来的, 而 DHCP 的 IP 是需要续租的, 所以该插件有一个 daemon 模式, 除了给它当做 ipam 使用时候的 rpc 调用的服务器端, 还负责了 IP 的续租和释放.
host-local (ipam)
- 使用本地文件来保存 IP 的使用情况
- ranges 配置是个二层嵌套数组, 一般第一个是个 IPV4 子网可选列表, 第二个是 IPV6 子网可选列表, 每个列表中可以有多个子网, round-robin 算法来选 IP.
- 使用本地的 /etc/resolv.conf 中的 dns 配置(也可以另外指定文件)
- 支持 CNI_ARGS 参数, 可以指定分配某个 subnet 中的某几个 IP, 但也是哪个没用到就用哪个
- 数据存在
/var/lib/cni/networks/$NETWORK_NAME
, 如果想重启主机后, 自动释放这些 IP, 就可以将dataDir
指定在一些 tmpfs 的目录(e.g./var/run/cni
)
tuning (meta)
- 如前所述, meta plugin 不负责连通性 or IP 分配, 只是一些辅助性的插件.
- tuning 负责给容器修改内核参数.
1
2
3
4
5
6
7
8
9The following network configuration file
{
"name": "mytuning",
"type": "tuning",
"sysctl": {
"net.core.somaxconn": "500"
}
}
will set /proc/sys/net/core/somaxconn to 500.
flannel (meta)
- 给 flannel 用的, 不多说了
以上小结
ipam plugin
负责分配 IP, 而main plugin
负责想办法给容器连通.- 因为各个
main plugin
的实现具体原理, 并不是所有的ipam plugin
和main plugin
都可以两两配对. - 在一个生产的 k8s 集群中, 一般很少会有 dhcp server, 因为这相当于完全放弃了 IP 的管理.
- host-local ipam 因为分配的 IP 不与 host IP 在一个段, 但会需要额外的方式来保证连通, 不论是 bridge 的 L2/L3 方式, 还是第三方的如 flannel(不是上面的 flannel meta plugin) 的封包发 udp 的方式.
- 注意上面的 cni-plugin, 对一个集群内的网络环境, 都有部分
侵入
, 如 dhcp 占用掉和主机同网段的 IP. 而 host-local 在多主机之间, 给容器分配 IP 是会重复的, 而且不确定多主机之间是如何实现连通的.
第三方 cni-plugin 实现
- 以上分析了官方实现的部分 cni-plugin, 因为都有部分对现有网络的
侵入
, 而第三方在实现 cni 的时候, 部分会避免这种类似
的侵入, 而选择其他方式的侵入
.
calico
- 给容器 interface 是很简单地使用了 veth peer
- 给容器 IP 用的是和主机不同, 和 k8s service 也不同的独立网段
- 而容器之间的连通性是依靠在主机上写入路由表进行的
- 另外很独特的一点, cni 是个在单台主机上的可执行文件, 那在这台主机上新增/删除/修改了路由表, 别的主机上怎么知道呢? OK, 这里 calico 用了一个用在自治路由系统中的 BGP 协议来传递路由. (BGP 协议是个没个十几万字就解释不清楚的东西)
- 第 2 点说了, calico 用了和主机不同的独立的 IP 段, 那么如果 k8s 集群主机的 IP 就在不同的 IP 段怎么办呢? 而 calico 给这些不同子网主机上的容器还是用的同一个段. 这里 calico 用了一种 IP-in-IP 技术, 是一种 IP 层的标准协议, 在原有的 IP header 上再套一个 IP header. 那么在外层 header 上使用主机 IP, 内层 header 用容器 IP, 就实现了跨网段主机上容器的连通性了.
flannel
- TODO
write a CNI(IPAM)
- 要写一个 CNI 还是比较难的, 因为大部分可行的容器连通性的方案都有实现过, 要么是协议栈的虚拟化, 无论是二层虚拟/三层虚拟/桥接, 还是依赖封包解包, 还是靠 BGP 传递路由.
- 而 IPAM 在设计之初就是为了减轻 cni 的耦合程度, 并且可以将 IP 的分配功能单独区分出来. 另外国外工程师的想法似乎对 IP 的管理并没那么多的兴趣, 就是对 IP 的使用基本都是按网段掩码来分.
- 当然了, 我也觉得 IPAM 的将 IP 的分配和应用的属性/配置关联起来的想法很蠢, 但就是有企业对网络, 对流量的管理是依赖这种
死配置
的 IP. - 至于如何写一个 IPAM 呢, 首先可以参考 cni-spec 的描述,
main-plugin
和ipam-plugin
分别是接受哪些输入/环境变量, 以及需要输出什么格式的结果. - 其次参考 dhcp 和 host-local 的实现, 主要是实现两个函数
cmdAdd, cmdDel func(_ *CmdArgs) error, versionInfo version.PluginInfo)
ref: containernetworking/cni/pkg/skel/skel.go
References
containernetworking/cni
containernetworking/plugins
About Calico
flannel 0.9.0 Documentation
原文作者: Pike.SZ.fish
原文链接: https://page.pikeszfish.me/2017/11/10/k8s-CNI/
许可协议: 本文采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可