--- 摄于 2017 年 9 月 藏川线前段
上一篇说到 debian 镜像上 nftables 的问题,只是略略提及了一下,后面又花了一点时间去研究这里面复杂的关系,尤其是 nftables 是怎么把 iptables 干掉的。作为程序员来说,如果新的标准已经被执行,就必须得了解怎么使用这个新的东西,最好不要一直停留在历史切面上,这会导致整个层面上的停滞不前。接着,不查不知道,一查吓一跳,这背后远比想象中更复杂。
nftables 已经是 redhat 和 debian 系的默认实现了,虽然提供了 iptables-nft 作为兼容语法实现,但现在这两系都不推荐继续使用 iptables 作为网络规则的维护接口。iptables 最主要的问题可能是性能上,在大量规则被加入之后,首先它需要内核参与执行,其次它缺失批量更新能力。
而 nftables 采用 哈希表 和 二叉查找树 等非线性结构存储规则,相比 iptables 的线性规则链,在 1000+ 规则场景下,其包过滤速度提升 3-5 倍,例如 Kubernetes 集群在启用 nftables 后,kube-proxy 的规则处理效率提升 40%。nftables 在批处理方面也是支持原子操作,并且操作界面统一为了 nft 一个命令,不需要多个命令操作。
总之,nftables 确实相对 iptables 做了大幅优化,并且操作上可以更细腻,性能上没有线性降速问题。但是,世界运行逻辑从来不是优化就是对的,也并不是所有人都是受益者,一定会有人在转换过程中,以各种方式做出阻挠。
docker 的实现,几乎强依赖 iptables,而且它的规则会在启动的时候直接写入操作系统。nftables 已经作为事实依赖进入 Linux 各大发行版五六年了,docker 直到目前为止还在实验性支持并且默认以 iptables 作为实现。切换需要手动操作,看上去很简单,实际上麻烦事一堆, 在 /etc/docker/daemon.json
中修改:
{
"iptables": false,
"nftables": true
}
但问题是它会出事,网络上会出各种问题,逼得用户不得不使用 iptables 或者 iptables-nft 做兼容。各种问题可以看 issue 和 reddit 上的一些讨论,docker 什么时候默认实现切到 nftables 呢:目前无期限。而兼容层 iptablse-nft
也并不是能够完全兼容的,它只能将以这个命令执行的规则转换成 nft 规则加入其中,无法找到已经存在或者直接用 iptables-legacy 实现的规则,这里就需要自行注意这些问题了。
还有个常用命令 nft flush rulest
可能会意外刷掉 docker nft 模式加入的规则,两者配合上需要格外注意。比较容易出现的问题就是 container 无法联网,因为转发规则丢了。
这是一个 redhat 实现并维护的兼容容器引擎替代方案,podman 支持 rootless 方案,并且原生支持 nftables 网络管理。在这种冲突大背景下,它的吸引力陡然提升,但它也有它的问题,说是兼容 docker,实际上还是有一些毛刺点,需要一定的迁移成本。目前它已经是 redhat 上的默认方案了,最主要的原因应该还是它的网络实现是可以无特权执行的,对于强调安全的 redhat 来说,这也是 podman 诞生的原因。
与 debian 不一样,archlinux 目前还没有碰到这种问题,默认的命令还是 iptables,也就是这次构建 debian 镜像才发现了这种问题,平时对这个关注度还是有限。碰巧的是,在构建 docker-compose 的时候,我用的也是 iptables 而不是 nftables,刚好绕开 docker 与 nftables 的冲突问题,这番查询资料才知道这种选择又节省了一些 debug 时间。但是,nftables 的全面占领是可预见的未来,还是要积极拥抱它,我特意尝试将依赖的 iptables 规则转换成了 nftables 命令:
apk add --no-cache nftables &&
# create NAT rule,support ipv4 and ipv6
nft add table inet nat &&
nft add chain inet nat postrouting { type nat hook postrouting priority 100 \; } &&
nft add rule inet nat postrouting oifname eth1 counter masquerade &&
# create forword rule
nft add table inet filter &&
nft add chain inet filter forward { type filter hook forward priority 0 \; policy drop\; } &&
nft add rule inet filter forward iifname eth0 oifname eth1 counter accept &&
nft add rule inet filter forward iifname eth1 oifname eth0 ct state related,established counter accept
未来也许有机会用上
随着 linux 网络方面的技术迭代,旧工具与新实现的冲突不可避免,这种问题可能会存在很久很久,取决于 linux 社区与 docker 实现的决心,也许还有其他没有关注到的工具的冲突问题。这就好像 xserver 与 wayland 并行了小十年还未能看到统一的那一天。也许终究能看到统一的一天?
请登录后评论
评论区
加载更多