iptables加载顺序问题及优化方法

1. 问题背景

近期, 在跟进存储节点升级 RAID 卡固件的事情时, 发现部分集群在重启机器后, 有极大的概率出现 client request block 的问题, block 时业务受到影响, 但隔一小段时间后, 故障能自行恢复. 问题重现机率高, 影响面大, 所以深入进一步排查.

2. 问题排查

  1. 通过 OSD 日志发现, 故障期间 OSD 日志有报出连接问题, 并在问题连接最终断开并重新连上后, 故障恢复
  2. 检查所有节点的网络通迅, 路由表, MTU, 防火墙, 均无发现问题
  3. 线索1: 在解决部分 block request 时, 为解决 block request, 停了全部 OSD; 发现全停了 OSD 后, 再次启动后并没有出现 block request, 获得线索1 
    • 线索1: 重新启动的 OSD 表现正常, 并多次验证依然如此, 推测第一次 OSD 启动时, 可能有部分设置有问题导致故障
  4. 根据线索1, 第一时间想到了 /etc/rc.local 中最后加载的配置, 其中存储节点只有防火墙及 sysctl 配置加载
  5. 验证: 注释 rc.local, 进行重启, 确认没有出现 block request, 问题原因缩小到防火墙及 sysctl 配置差异
  6. 一开始怀疑到 sysctl 最后才加载, 导致前面 OSD 节点在并发启动 OSD 服务时, backlog等网络参数过小, 导致丢包或连接丢失问题
  7. 排除验证: 通过对 /etc/rcS.d 的过滤, 确认在 ceph 服务启动前, sysctl 已经由系统内置的加载过一遍
  8. 钩子验证: 通过在 /etc/init.d/ceph 的启动配置中, 加入输出 sysctl 配置的操作, 进一步验证了 sysctl 的配置已经是加载过(在 /etc/rcS.d/S11procps 中加载)
  9. 至此基本可以确认防火墙的加载导致故障, 但尚未进行根因分析

3. 根因分析

这段时间正好遇到新上的一波计算节点出现不少节点的 nova 服务异常故障, 一联想可能是同个问题导致, 并做进一步的根因分析

  1. 拿两台有问题的计算节点, 一台注释防火墙加载, 一台保持原配置, 重启机器, 观察到不加载防火墙的计算节点nova-compute服务正常, 而加载了防火墙的节点 nova-compute 服务异常 
    • 表现: nova-compute 服务异常时, 日志不定时刷新, 但从master的nova service-list 以及 rabbitmap的状态中, 却能观察到正常的心跳及连接
  2. 通过观察防火墙规则, 初步判断为 TCP 连接的建立先于 conntrack 规则的加载, 导致 conntrack 规则加载后, 原来已经握手完成的 TCP 数据包被识别为异常数据包, 进而被 Drop, 导致 网络连接状态异常

    • 这也就可以解释为什么重启一次服务后, 又能正常, 因为此次 conntrack 规则已经生效中
    • 这也就可以解释为什么nova-compute服务异常后, 还能有正常的心跳反馈出去(因为这只是出去的包, 无限制)
  3. 通过开启iptables的 LOG, 进行debug, 确认该猜测, 原因明确

root@cld-acc162-32:/etc/rcS.d# dmesg  | grep 'DROP' | grep '10.200.12.102'
[  140.173826] INPUT:DROP IN=eth0 OUT= MAC=9c:dc:71:64:9e:b0:5c:b9:01:d0:9e:c0:08:00 SRC=10.200.12.102 DST=10.200.13.135 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=47100 DF PROTO=TCP SPT=5672 DPT=40445 WINDOW=59 RES=0x00 ACK PSH URGP=0
[  140.381274] INPUT:DROP IN=eth0 OUT= MAC=9c:dc:71:64:9e:b0:5c:b9:01:d0:9e:c0:08:00 SRC=10.200.12.102 DST=10.200.13.135 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=47101 DF PROTO=TCP SPT=5672 DPT=40445 WINDOW=59 RES=0x00 ACK PSH URGP=0
[  140.589186] INPUT:DROP IN=eth0 OUT= MAC=9c:dc:71:64:9e:b0:5c:b9:01:d0:9e:c0:08:00 SRC=10.200.12.102 DST=10.200.13.135 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=47102 DF PROTO=TCP SPT=5672 DPT=40445 WINDOW=59 RES=0x00 ACK PSH URGP=0
[  141.005051] INPUT:DROP IN=eth0 OUT= MAC=9c:dc:71:64:9e:b0:5c:b9:01:d0:9e:c0:08:00 SRC=10.200.12.102 DST=10.200.13.135 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=47103 DF PROTO=TCP SPT=5672 DPT=40445 WINDOW=59 RES=0x00 ACK PSH URGP=0
root@cld-acc162-32:/etc/rcS.d# cat /etc/rc.local
#!/bin/bash

sleep 60

conntrack -E >/tmp/conntrack.log 2>&1 &

# recover ipset every reboot
ipset -! restore < /home/cld/conf/fwrule/ipset/10.base_set.ipset

# restore iptable setting after reboot
iptables-restore /etc/network/iptables
conntrack -L >/tmp/init.log 2>&1 &

/sbin/sysctl --system
exit 0
root@cld-acc162-32:/etc/rcS.d# cat /tmp/init.log
conntrack v1.4.2 (conntrack-tools): 0 flow entries have been shown.
root@cld-acc162-32:/etc/rcS.d# cat /tmp/conntrack.log | grep 10.200.12.102
    [NEW] tcp      6 300 ESTABLISHED src=10.200.13.135 dst=10.200.12.102 sport=40449 dport=5672 [UNREPLIED] src=10.200.12.102 dst=10.200.13.135 sport=5672 dport=40449
 [UPDATE] tcp      6 300 src=10.200.13.135 dst=10.200.12.102 sport=40449 dport=5672 src=10.200.12.102 dst=10.200.13.135 sport=5672 dport=40449
    [NEW] tcp      6 300 ESTABLISHED src=10.200.13.135 dst=10.200.12.102 sport=40447 dport=5672 [UNREPLIED] src=10.200.12.102 dst=10.200.13.135 sport=5672 dport=40447
 [UPDATE] tcp      6 300 src=10.200.13.135 dst=10.200.12.102 sport=40447 dport=5672 src=10.200.12.102 dst=10.200.13.135 sport=5672 dport=40447
 [UPDATE] tcp      6 300 src=10.200.13.135 dst=10.200.12.102 sport=40447 dport=5672 src=10.200.12.102 dst=10.200.13.135 sport=5672 dport=40447 [ASSURED]
 [UPDATE] tcp      6 300 src=10.200.13.135 dst=10.200.12.102 sport=40449 dport=5672 src=10.200.12.102 dst=10.200.13.135 sport=5672 dport=40449 [ASSURED]
    [NEW] tcp      6 300 ESTABLISHED src=10.200.13.135 dst=10.200.12.102 sport=40445 dport=5672 [UNREPLIED] src=10.200.12.102 dst=10.200.13.135 sport=5672 dport=40445
 [UPDATE] tcp      6 300 src=10.200.13.135 dst=10.200.12.102 sport=40445 dport=5672 src=10.200.12.102 dst=10.200.13.135 sport=5672 dport=40445
 [UPDATE] tcp      6 432000 src=10.200.13.135 dst=10.200.12.102 sport=40445 dport=5672 src=10.200.12.102 dst=10.200.13.135 sport=5672 dport=40445 [ASSURED]

4. 附带影响

  1. 此问题查明了近期存储节点 block request 的原因
  2. 顺带查明了 nova-compute 线上集群时不时出现 nova-compute故障的原因(计算节点因故障重启即导致异常, 需人工重启服务恢复)
  3. 查明了运维登录刚重启的机器后, 有可能出现的 ssh 卡住只能重新登录的问题
  4. 查明了之前网关节点需要把quagga服务设置为不启动, 并在rc.local最后加载的历史问题

5. 解决方法

原因查明后, 解决该问题并不难, 规范来说, 防火墙应该在网络就绪前就优先加载完成, 所以需要在/etc/network/if-pre-up.d/ 下面增加 iptables 加载脚本, 为了一次性解决 ipset 以及 iptables 加载问题, 编写以下脚本并测试完成

#!/bin/sh

#only run one time
[ "$IFACE" != "lo" ] && exit 0

#reload ipset
for conf in /home/cld/conf/fwrule/ipset/*.ipset
do
    if [ -f "$conf" ]
    then
        ipset -! restore <$conf
    fi
done

#create MY_IPS
ipset create MY_IPS hash:ip

#reload iptables
for ipt in /etc/network/iptables.up.rules /etc/network/iptables /etc/iptables.netease
do
    if [ -e "$ipt" ]
    then
        iptables-restore $ipt
        exit 0
    fi
done

exit 0

5.后续安排

  1. 通过 puppet 部署 /etc/network/if-pre-up.d/iptables
  2. 去除所有机器的 /etc/rc.local 中加载 ipset 及 iptables 的操作

6. iptables涉及语句

-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp ! --tcp-flags FIN,SYN,RST,ACK SYN -m conntrack --ctstate NEW -j DROP
 
 
 
 
 
 

posted @ 2018-11-01 21:30  李尚衍  阅读(368)  评论(0编辑  收藏  举报