使用 nftables map 实现多端口到不同容器的 dnat 分发:先创建 inet_service : ipv4_addr . inet_service 类型映射,再于 nat prerouting 链中查表执行 dnat,配合 forward 放行和 rp_filter 调整,支持动态增删映射项。

用 nftables 的 map 实现“多入站端口 → 不同容器”的流量分发,核心是把端口和容器 IP:Port 映射关系存进内建字典,再在 nat 表的 PREROUTING 链中查表做 DNAT。它比写一堆重复的 DNAT 规则更简洁、可维护,也支持动态增删(如容器启停时更新 map)。
一、确认基础前提
确保系统已启用 IPv4 转发,并安装运行了 nftables(v0.9.0+):
- 执行 echo 1 > /proc/sys/net/ipv4/ip_forward 并写入 /etc/sysctl.conf 持久化
- 确认容器网络已就绪(如 docker0 网桥 UP,容器有 172.17.x.x 类地址)
- 避免 iptables 和 nftables 规则冲突:卸载 legacy 模块或清空旧规则(nft flush ruleset)
二、定义端口映射字典(map)
创建一个 type inet_service : ipv4_addr . inet_service 的 map,用于将外部端口映射到容器 IP 和端口组合:
nft add map inet filter port_to_container { type inet_service : ipv4_addr . inet_service \; }
然后批量插入映射项(示例):
- nft add element inet filter port_to_container { 8080 : 172.17.0.2 . 80 } → 外网 8080 → 容器 A 的 80
- nft add element inet filter port_to_container { 8081 : 172.17.0.3 . 3000 } → 外网 8081 → 容器 B 的 3000
- nft add element inet filter port_to_container { 5432 : 172.17.0.4 . 5432 } → 外网 5432 → 容器 C 的原端口
注意:map 中的 value 是 IP . Port 二元组,必须与 map 类型声明严格匹配;键(key)只能是单个端口(inet_service),不支持端口范围。
三、配置 DNAT 规则并查表
在 inet 地址簇的 nat 表中添加 PREROUTING 链,对目标端口查 map 并执行 DNAT:
nft add chain inet nat prerouting { type nat hook prerouting priority -100 \; }
nft add rule inet nat prerouting tcp dport @port_to_container dnat to ip . port
这条规则含义是:当 TCP 目标端口存在于 port_to_container 字典中时,将数据包的目标 IP 和端口替换为字典中对应值(即容器 IP 和端口)。nftables 自动展开 ip . port 为实际地址+端口。
补充建议:
- 加一条基础放行规则:nft add rule inet filter input tcp dport @port_to_container accept(若 host 本身监听这些端口需先禁用)
- 为防止回环干扰,可限制仅处理外网接口入向:iifname != "lo" tcp dport @port_to_container dnat to ip . port
四、配套转发与返回路径保障
仅 DNAT 不够,还需确保:
-
FORWARD 链放行:添加规则允许目的为容器网段的转发包
nft add rule inet filter forward ip daddr 172.17.0.0/16 accept -
SNAT/MASQUERADE(可选):若容器需主动访问外网且使用宿主机作为网关,需在 POSTROUTING 做源地址伪装
nft add rule inet nat postrouting ip saddr 172.17.0.0/16 oifname != "docker0" masquerade -
禁用反向路径校验:避免因不对称路由丢包,在容器网卡上关闭 rp_filter
echo 0 > /proc/sys/net/ipv4/conf/docker0/rp_filter(并写入 sysctl.conf)
完成之后,外部访问宿主机的 8080、8081 等端口,即可自动分发到对应容器,无需重启 nftables 服务即可通过 nft add/del element 动态调整映射。











