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

Amazon ec2 Kubernetes-连接跟踪不会将包损坏回原始目标IP(DNAT),amazon-ec2,kubernetes,netfilter,flannel,kube-proxy,Amazon Ec2,Kubernetes,Netfilter,Flannel,Kube Proxy,我们有一个使用AWS EC2实例的Kubernetes集群设置,该实例是我们使用KOPS创建的。我们在通过kubernetes服务进行内部pod通信时遇到问题(这将在目标pod之间实现负载平衡)。当源和目标pod位于同一EC2实例(节点)上时,问题就会出现。Kubernetes使用flannel设置,用于使用vxlan进行节点间通信,Kubernetes服务由kube代理使用iptables进行管理 在以下情况下: 在EC2实例1上运行的PodA(ip-172-20-121-84,us-eas

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

在以下情况下:

  • 在EC2实例1上运行的PodA(ip-172-20-121-84,us-east-1c):100.96.54.240
  • 在EC2实例1上运行的PodB(ip-172-20-121-84,us-east-1c):100.96.54.247
  • ServiceB(其中PodB是可能的目标端点的服务):100.67.30.133
如果我们进入PodA并执行“curl-v”,则不会收到任何响应,最后会产生一个超时

当我们检查流量(实例1中的cni0接口)时,我们观察到:

  • PodA向ServiceB IP发送SYN包
  • 包已损坏,目标IP从ServiceB IP更改为PodB IP
  • 更改的跟踪寄存器:

    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包,这不是预期的,它会发回一个重置包
  • 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代理自动管理):

    这是服务定义:

    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>
    
    root@adsvm010:/yamls#kubectl描述服务导出
    名称:出口
    名称空间:prod
    标签:
    注释:
    选择器:运行=导出
    类型:集群
    IP:100.67.30.133
    端口:80/TCP
    目标端口:80/TCP
    终点:100.96.5.44:80100.96.54.235:80100.96.54.247:80+7更多。。。
    会话关联:无
    活动:
    
    如果我们不直接使用服务,而是直接使用PodB IP(因此不需要损坏包),那么连接就可以工作

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


    这种行为是在几周前开始的,那时我们还没有观察到任何问题(一年多),我们也不记得对集群设置或我们正在运行的pod有任何重大更改。有人知道为什么SYN+ACK包没有被损坏回预期的src/dst IP吗?

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

    要在使用KOPS()的Kubernetes群集设置中修复此问题,请使用
    KOPS edit cluster
    并在
    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服务,该服务将在启动时运行,并将确保在kubernetes(即kubelet)启动之前加载
    br_netfilter
    模块。如果我们不这样做,我们在AWS EC2实例(Debian Jessie images)中遇到的情况是,有时模块在启动时加载,有时则不加载(我不知道为什么会有这样的变化),因此这取决于问题是否会表现出来。

    它们是什么类型的服务<代码>节点端口
    LoadBalancer
    ?或者您可以添加输出
    kubectl描述服务B
    ?是否已满
    iptables save
    ?看起来第二个吊舱缺少了一些链条。这是一个ClusterIP@Rico,我也添加了描述。关于iptables,它不是完整的输出(它相当长),我只保留了我认为是示例的相关规则。对于PodB(100.96.54.247)没有其他规则,您希望@NickRak看到什么?如果您在iptables中对PodA和PodB有相同的规则,那么iptables中的所有规则都是好的,并且VPC的配置中存在问题,这可能是您提供的云的防火墙问题。您能检查一下防火墙中是否有与此相关的限制吗?
    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
    
    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
    
    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