gpt4 book ai didi

amazon-ec2 - Kubernetes - 连接跟踪不会将包破坏回原始目标 IP (DNAT)

转载 作者:行者123 更新时间:2023-12-02 12:18:53 25 4
gpt4 key购买 nike

我们有一个使用 KOPS 创建的 AWS EC2 实例的 Kubernetes 集群设置。我们在通过 kubernetes 服务进行内部 pod 通信时遇到问题(这将负载平衡目标 pod 之间的流量)。当源 pod 和目标 pod 位于同一个 EC2 实例(节点)上时,就会出现问题。 Kubernetes 使用 flannel 设置,用于使用 vxlan 进行节点间通信,并且 kubernetes 服务由 kube-proxy 使用 iptables 管理。

在以下情况下:

  • 在 EC2 实例 1(ip-172-20-121-84,us-east-1c)上运行的 PodA:100.96.54.240
  • 在 EC2 实例 1(ip-172-20-121-84,us-east-1c)上运行的 PodB:100.96.54.247
  • ServiceB(PodB 是可能的目标端点的服务):100.67.30.133

  • 如果我们进入 PodA 并执行“curl -v http://ServiceB/”,则没有收到任何响应,最后会产生超时。

    当我们检查流量(实例 1 中的 cni0 接口(interface))时,我们观察到:
  • PodA 向 ServiceB IP
  • 发送 SYN 包
  • 包被破坏,目标 IP 从 ServiceB IP 更改为 PodB IP
  • Conntrack 记录发生变化:
    root@ip-172-20-121-84:/home/admin# conntrack -L|grep 100.67.30.133
    tcp 6 118 SYN_SENT src=100.96.54.240 dst=100.67.30.133 sport=53084 dport=80 [UNREPLIED] src=100.96.54.247 dst=100.96.54.240 sport=80 dport=43534 mark=0 use=1
  • PodB 向 PodA 发送 SYN+ACK 包
  • SYN+ACK 包的源 IP 不会从 PodB IP 恢复到 ServiceB IP
  • PodA 从 PodB 收到一个 SYN+ACK 包,这是意料之外的,它发回了一个 RESET 包
  • PodA超时后再次向ServiceB发送SYN包,整个过程重复

  • 这里 tcpdump 注释的详细信息:
    root@ip-172-20-121-84:/home/admin# tcpdump -vv -i cni0 -n "src host 100.96.54.240 or dst host 100.96.54.240"
    TCP SYN:
    15:26:01.221833 IP (tos 0x0, ttl 64, id 2160, offset 0, flags [DF], proto TCP (6), length 60)
    100.96.54.240.43534 > 100.67.30.133.80: Flags [S], cksum 0x1e47 (incorrect -> 0x3e31), seq 506285654, win 26733, options [mss 8911,sackOK,TS val 153372198 ecr 0,nop,wscale 9], length 0
    15:26:01.221866 IP (tos 0x0, ttl 63, id 2160, offset 0, flags [DF], proto TCP (6), length 60)
    100.96.54.240.43534 > 100.96.54.247.80: Flags [S], cksum 0x36d6 (incorrect -> 0x25a2), seq 506285654, win 26733, options [mss 8911,sackOK,TS val 153372198 ecr 0,nop,wscale 9], length 0

    Level 2:
    15:26:01.221898 ARP, Ethernet (len 6), IPv4 (len 4), Request who-has 100.96.54.240 tell 100.96.54.247, length 28
    15:26:01.222050 ARP, Ethernet (len 6), IPv4 (len 4), Reply 100.96.54.240 is-at 0a:58:64:60:36:f0, length 28

    TCP SYN+ACK:
    15:26:01.222151 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 60)
    100.96.54.247.80 > 100.96.54.240.43534: Flags [S.], cksum 0x36d6 (incorrect -> 0xc318), seq 2871879716, ack 506285655, win 26697, options [mss 8911,sackOK,TS val 153372198 ecr 153372198,nop,wscale 9], length 0

    TCP RESET:
    15:26:01.222166 IP (tos 0x0, ttl 64, id 32433, offset 0, flags [DF], proto TCP (6), length 40)
    100.96.54.240.43534 > 100.96.54.247.80: Flags [R], cksum 0x6256 (correct), seq 506285655, win 0, length 0

    TCP SYN (2nd time):
    15:26:02.220815 IP (tos 0x0, ttl 64, id 2161, offset 0, flags [DF], proto TCP (6), length 60)
    100.96.54.240.43534 > 100.67.30.133.80: Flags [S], cksum 0x1e47 (incorrect -> 0x3d37), seq 506285654, win 26733, options [mss 8911,sackOK,TS val 153372448 ecr 0,nop,wscale 9], length 0
    15:26:02.220855 IP (tos 0x0, ttl 63, id 2161, offset 0, flags [DF], proto TCP (6), length 60)
    100.96.54.240.43534 > 100.96.54.247.80: Flags [S], cksum 0x36d6 (incorrect -> 0x24a8), seq 506285654, win 26733, options [mss 8911,sackOK,TS val 153372448 ecr 0,nop,wscale 9], length 0
    15:26:02.220897 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto TCP (6), length 60)
    100.96.54.247.80 > 100.96.54.240.43534: Flags [S.], cksum 0x36d6 (incorrect -> 0x91f0), seq 2887489130, ack 506285655, win 26697, options [mss 8911,sackOK,TS val 153372448 ecr 153372448,nop,wscale 9], length 0
    15:26:02.220915 IP (tos 0x0, ttl 64, id 32492, offset 0, flags [DF], proto TCP (6), length 40)
    100.96.54.240.43534 > 100.96.54.247.80: Flags [R], cksum 0x6256 (correct), seq 506285655, win 0, length 0

    实例 1 (ip-172-20-121-84, us-east-1c) 上的相关 iptable 规则(由 kube-proxy 自动管理):
    -A INPUT -m comment --comment "kubernetes service portals" -j KUBE-SERVICES
    -A PREROUTING -m comment --comment "kubernetes service portals" -j KUBE-SERVICES
    -A OUTPUT -m comment --comment "kubernetes service portals" -j KUBE-SERVICES

    -A KUBE-SERVICES ! -s 100.96.0.0/11 -d 100.67.30.133/32 -p tcp -m comment --comment "prod/export: cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ
    -A KUBE-SERVICES -d 100.67.30.133/32 -p tcp -m comment --comment "prod/export: cluster IP" -m tcp --dport 80 -j KUBE-SVC-3IL52ANAN3BQ2L74

    -A KUBE-SVC-3IL52ANAN3BQ2L74 -m comment --comment "prod/export:" -m statistic --mode random --probability 0.10000000009 -j KUBE-SEP-4XYJJELQ3E7C4ILJ
    -A KUBE-SVC-3IL52ANAN3BQ2L74 -m comment --comment "prod/export:" -m statistic --mode random --probability 0.11110999994 -j KUBE-SEP-2ARYYMMMNDJELHE4
    -A KUBE-SVC-3IL52ANAN3BQ2L74 -m comment --comment "prod/export:" -m statistic --mode random --probability 0.12500000000 -j KUBE-SEP-OAQPXBQCZ2RBB4R7
    -A KUBE-SVC-3IL52ANAN3BQ2L74 -m comment --comment "prod/export:" -m statistic --mode random --probability 0.14286000002 -j KUBE-SEP-SCYIBWIJAXIRXS6R
    -A KUBE-SVC-3IL52ANAN3BQ2L74 -m comment --comment "prod/export:" -m statistic --mode random --probability 0.16667000018 -j KUBE-SEP-G4DTLZEMDSEVF3G4
    -A KUBE-SVC-3IL52ANAN3BQ2L74 -m comment --comment "prod/export:" -m statistic --mode random --probability 0.20000000019 -j KUBE-SEP-NXPFCT6ZBXHAOXQN
    -A KUBE-SVC-3IL52ANAN3BQ2L74 -m comment --comment "prod/export:" -m statistic --mode random --probability 0.25000000000 -j KUBE-SEP-7DUMGWOXA5S7CFHJ
    -A KUBE-SVC-3IL52ANAN3BQ2L74 -m comment --comment "prod/export:" -m statistic --mode random --probability 0.33332999982 -j KUBE-SEP-LNIY4F5PIJA3CQPM
    -A KUBE-SVC-3IL52ANAN3BQ2L74 -m comment --comment "prod/export:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-SLBETXT7UIBTZCPK
    -A KUBE-SVC-3IL52ANAN3BQ2L74 -m comment --comment "prod/export:" -j KUBE-SEP-FMCOTKNLEICO2V37

    -A KUBE-SEP-OAQPXBQCZ2RBB4R7 -s 100.96.54.247/32 -m comment --comment "prod/export:" -j KUBE-MARK-MASQ
    -A KUBE-SEP-OAQPXBQCZ2RBB4R7 -p tcp -m comment --comment "prod/export:" -m tcp -j DNAT --to-destination 100.96.54.247:80

    -A KUBE-MARK-MASQ -j MARK --set-xmark 0x4000/0x4000
    -A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -m mark --mark 0x4000/0x4000 -j MASQUERADE

    这是服务定义:
    root@adsvm010:/yamls# kubectl describe service export
    Name: export
    Namespace: prod
    Labels: <none>
    Annotations: <none>
    Selector: run=export
    Type: ClusterIP
    IP: 100.67.30.133
    Port: <unset> 80/TCP
    TargetPort: 80/TCP
    Endpoints: 100.96.5.44:80,100.96.54.235:80,100.96.54.247:80 + 7 more...
    Session Affinity: None
    Events: <none>

    如果我们直接使用 PodB IP 而不是服务(因此无需破坏包),则连接有效。

    如果我们使用该服务,但随机选择的目标 pod 在不同的实例中运行,则连接跟踪机制正常工作,它会破坏包,以便 PodA 按预期看到 SYN+ACK 包(来自 ServiceB IP) .在这种情况下,流量通过 cni0 和 flannel.0 接口(interface)。

    这种行为是几周前开始的,在我们没有发现任何问题之前(一年多),我们不记得对集群设置或我们正在运行的 Pod 有任何重大更改。有没有人有任何想法可以解释为什么 SYN+ACK 包没有重新回到预期的 src/dst IPs?

    最佳答案

    我终于找到了答案。 cni0 接口(interface)与所有 pod 虚拟接口(interface)处于桥接模式(在该节点上运行的每个 pod 一个 veth0):

    root@ip-172-20-121-84:/home/admin# brctl show
    bridge name bridge id STP enabled interfaces
    cni0 8000.0a5864603601 no veth05420679
    veth078b53a1
    veth0a60985d
    ...


    root@ip-172-20-121-84:/home/admin# ip addr
    5: cni0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 8951 qdisc noqueue state UP group default qlen 1000
    link/ether 0a:58:64:60:36:01 brd ff:ff:ff:ff:ff:ff
    inet 100.96.54.1/24 scope global cni0
    valid_lft forever preferred_lft forever
    inet6 fe80::1c66:76ff:feb6:2122/64 scope link
    valid_lft forever preferred_lft forever

    从/到桥接接口(interface)到/从其他接口(interface)的流量由 netfilter/iptables 处理,但不离开桥接接口(interface)的流量(例如,从一个 veth0 到另一个,都属于同一个桥)不是由 netfilter/iptables 处理。

    在我在问题中公开的示例中,PodA (100.96.54.240) 向不在 cni0 子网 (100.96.54.1/24) 中的 ServiceB (100.67.30.133) 发送 SYN 包,因此该包不会留在桥接的 cni0 interface 和 iptable 处理它。这就是为什么我们看到 DNAT 发生并在 conntrack 中注册的原因。但是,如果选定的目标 pod 位于同一节点中,例如 PodB (100.96.54.247),则 PodB 会看到 SYN 包并以 SYN+ACK 响应,其中源为 100.96.54.247,目标为 100.96.54.240。这些是 cni0 子网中的 IP,不需要离开它,因此 netfilter/iptables 不会处理它,也不会根据 conntrack 信息破坏包(即,真实源 100.96.54.247 不会被预期源替换100.67.30.133)。

    幸好有 bridge-netfilter内核模块,可以使 netfilter/iptables 处理桥接接口(interface)中发生的流量:
    root@ip-172-20-121-84:/home/admin# modprobe br_netfilter
    root@ip-172-20-121-84:/home/admin# cat /proc/sys/net/bridge/bridge-nf-call-iptables
    1

    要在使用 KOPS ( credits) 的 Kubernetes 集群设置中解决此问题,请使用 kops edit cluster 编辑集群 list 及以下 spec:包括:
    hooks:
    - name: fix-bridge.service
    roles:
    - Node
    - Master
    before:
    - network-pre.target
    - kubelet.service
    manifest: |
    Type=oneshot
    ExecStart=/sbin/modprobe br_netfilter
    [Unit]
    Wants=network-pre.target
    [Install]
    WantedBy=multi-user.target

    这将在 /lib/systemd/system/fix-bridge.service 中创建一个 systemd 服务在启动时运行的节点中,它将确保 br_netfilter模块在 kubernetes(即 kubelet)启动之前加载。如果我们不这样做,我们对 AWS EC2 实例(Debian Jessie 镜像)的体验是,有时模块会在启动期间加载,有时则不会(我不知道为什么会有这样的可变性),因此取决于问题可能会出现,也可能不会。

    关于amazon-ec2 - Kubernetes - 连接跟踪不会将包破坏回原始目标 IP (DNAT),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52976081/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com