netfilter 无法正确替换 UDP 响应包的目标 IP

netfilter 无法正确替换 UDP 响应包的目标 IP

我们正在运行小型 kuberentes 集群(CentOS 7、Kuberenetes 1.13 + Flannel),经过一些调整 TCP 配置(见下文)后,我们注意到 DNS 无法正常工作。

我不认为我们的改变与我所观察到的情况直接相关,kubernetes 也不负有责任。我查了一下 IP 表,据我所知,一切看起来都很好。我观察到的情况如下:

  1. Pod 10.23.118.10 发送 UDP(53) 包到 DNS ClusterIP 10.22.0.10
  2. 然后将包的目标 IP 从 ClusterIP (10.22.0.10) 更改为 DNS 服务器 Pod 的 IP (10.23.118.2) (DNAT)
  3. 服务器收到请求,处理它,然后将响应发送回 10.23.118.10
  4. 此时netfilter应该在转发包之前将源IP 10.23.118.2替换为10.22.0.10,但由于某种原因它没有这样做
  5. Libc 收到数据包并拒绝它,因为它看到响应来自 10.23.118.2 而不是 10.22.0.10,或者我们收到 ICMP 数据包,说端口无法访问。

在此输入图像描述

奇怪的是,只有当 DNS 请求发送到在同一台机器上运行的 pod 时才会发生这种情况。如果 DNS 请求来自其他机器上运行的 pod,则一切正常。

我想我们并不是唯一看到这一点的人。你有类似的情况吗?我不确定这是 linux 的 netfilter 中的错误还是 docker/kubernetes 在配置桥接接口时破坏了某些东西。我应该在哪里寻找更多信息?

这是我们尝试应用的 TCP 配置:

net.core.somaxconn = 1000
net.core.netdev_max_backlog = 5000
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_wmem = 4096 12582912 16777216
net.ipv4.tcp_rmem = 4096 12582912 16777216
net.ipv4.tcp_max_syn_backlog = 8096
net.ipv4.tcp_slow_start_after_idle = 0

答案1

问题似乎是 CentOS 7 默认配置。

当重新加载配置时sysctl -p --system,它也会重新加载/usr/lib/sysctl.d/00-system.conf。在 中/usr/lib/sysctl.d/00-system.conf,我们可以看到以下内容:

# Disable netfilter on bridges.
net.bridge.bridge-nf-call-ip6tables = 0
net.bridge.bridge-nf-call-iptables = 0
net.bridge.bridge-nf-call-arptables = 0

一旦完成(在网桥上禁用 netfilter),NAT-ing 将无法在docker0网桥上正常工作。

有趣的是,一旦你重新启动 docker 并使用 查询系统sysctl -a,你可以看到以下内容:

net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1

我只能假设这个设置是在启动过程中由 docker 本身更改的。

这解释了为什么重新启动 docker 通常会有所帮助。

相关内容