Docker Host模式下 Logstash 容器收到的日志竟全来自虚拟网桥的IP、cni0收不到日志、conntrack 连接跟踪

By | 2022年7月7日

Host 模式收到的日志却来自 docker_gwbridge 虚拟网桥

由于客户服务器已装 Docker 引擎,因此产品部署时选择 Docker Swarm 版,没有用K8S版。装好后流量服务器命中算法始终不工作,一番排查后发现,防火墙设备发来的syslog日志,host 值竟全是 docker_gwbridge 虚拟网桥IP,不是设备真实IP,这肯定不行。明明 logstash 收日志的 514 端口已经设置为 host 模式暴露在外,在其他客户那也已用过了,为何此客户这会出这种问题呢?尝试很多办法都无法解决!

在濒临绝望中,终于该文章拯救了我:UDP traffic source IP is lost 。这是文章的关键点:

结合我这边的情况,意思是说:正常情况下,数据包转发到 514 端口会走 DNAT,但有时 iptable DNAT 规则没到位,conntrack 表就会创建一条记录,导致即使在 iptable DNAT 规则创建后,数据包也会转发到 userland-proxy 514端口上,可以用命令 “conntrack -D -p udp“删除这个记录。设置 userland-proxy=false 可能也没用,conntrack 可能还会优先 DNAT 规则,此时若禁用 userland-proxy,514端口上可能再也收不到数据包了。

于是服务器 storm 节点服务起来后,让客户尝试安装了 conntrack,并运行命令 conntrack -D -p udp

此时, logstash udp 514 监听端口上收到的日志 host 值对了,是防火墙设备IP了,如图:

kafka 上日志 host 值已是防火墙IP(logstash 收到日志后会发往 kafka)

另一个客户那也遇到了这种情况,但执行完命令后没立即生效,重启 Storm 节点容器后才生效!

其他参考:理解Docker容器端口映射

cni0 收不到设备日志

在广发客户那遇到物理网卡能收日志,但 K8S cni0 虚拟网卡却收不到。

# 命令参考
tcpdump -i ens33 udp and host 192.168.1.122 and port 514 -vv
tcpdump -i cni0 udp and host 192.168.1.122 and port 514 -vv

此现象在南京电调也遇过,之前解决办法是让客户在设备上停止流量的发送,然后再开下。现在可直接调用 conntrack -D -p udp,此时 cni0 会立即收到日志(亲测有效)。

conntrack 连接跟踪

conntrack本质是一个内核里的hash表,每个node上的conntrack在跟踪流过它的每一条连接。

conntrack俗称流表,或者连接跟踪表,它属于netfilters框架,在PREROUTING mangle之前以及OUTPUT mangle之前都会经过一个connection tracking的表。

conntrack是实现nat地址转换的灵魂,一个连接仅在首次经过netfilters链条时会计算nat表,一旦conntrack记录下这次的改写关系,后续无论是去程包还是回程包都是依据conntrack表进行改写关系的处理,不会再重复执行nat表中的DNAT/SNAT规则。

在node的conntrack表中记录了大量的记录,每条记录包含2部分:

改写前的源IP和目标IP
改写后的源IP和目标IP

更多细节请参考:linux conntrack (connection tracking)

使用源代码自编译 conntrack:https://conntrack-tools.netfilter.org/


连接跟踪(conntrack):原理、应用及 Linux 内核实现

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注