背景
公司内部连续测试8轮,在封版之前最后几次测试,突然发现istio流量监控及Tracing不正常。距离11月30号发版日只剩到计时3天时,突然出现问题。
问题定位过程
- 应用访问正常,业务未受影响。
- 进容器 curl 127.0.0.1:15000/stats/prometheus 未看到istio_requests_total指标,但是有istio_开头的指标。
- 检查 envoyfilter正常存在,检查envoy的指标,存在 istio.stats filter。
- istio-proxy容器无不正常日志,istiod无不正常日志,相关pod无不正常日志。
- 使用Iptables命令,手动查看iptables规则为空。
第5步的时候发现了异常,说明iptables规则未正常下发。检查 istio-init容器,可以看到有以下报错:
[root@prctyjs4jwzkvv ~]# kubectl -n xxy-1127aa logs -f xx-557d868d7d-sz2fm -c istio-init
2021-11-27T13:43:36.924014Z error Command error output: iptables-restore v1.8.4 (legacy): iptables-restore: unable to initialize table 'nat'
Error occurred at line: 1
Try `iptables-restore -h' or 'iptables-restore --help' for more information.
该日志说明在执行 iptables-restore时失败。
查看一个正常的 istio-init 容器日志,对比:
[root@prctyjs4jwzkvv ~]# kubectl -n xxy-1127aa logs -f xx-557d868d7d-427s5 -c istio-init
2021-11-27T14:38:35.714344Z info Istio iptables environment:
ENVOY_PORT=
INBOUND_CAPTURE_PORT=
ISTIO_INBOUND_INTERCEPTION_MODE=
ISTIO_INBOUND_TPROXY_ROUTE_TABLE=
ISTIO_INBOUND_PORTS=
ISTIO_OUTBOUND_PORTS=
ISTIO_LOCAL_EXCLUDE_PORTS=
ISTIO_EXCLUDE_INTERFACES=
ISTIO_SERVICE_CIDR=
ISTIO_SERVICE_EXCLUDE_CIDR=
ISTIO_META_DNS_CAPTURE=
2021-11-27T14:38:35.714403Z info Istio iptables variables:
PROXY_PORT=15001
PROXY_INBOUND_CAPTURE_PORT=15006
PROXY_TUNNEL_PORT=15008
PROXY_UID=1337
PROXY_GID=1337
INBOUND_INTERCEPTION_MODE=REDIRECT
INBOUND_TPROXY_MARK=1337
INBOUND_TPROXY_ROUTE_TABLE=133
INBOUND_PORTS_INCLUDE=*
INBOUND_PORTS_EXCLUDE=15090,15021,15020
OUTBOUND_IP_RANGES_INCLUDE=*
OUTBOUND_IP_RANGES_EXCLUDE=
OUTBOUND_PORTS_INCLUDE=
OUTBOUND_PORTS_EXCLUDE=
KUBEVIRT_INTERFACES=
ENABLE_INBOUND_IPV6=false
DNS_CAPTURE=false
CAPTURE_ALL_DNS=false
DNS_SERVERS=[],[]
OUTPUT_PATH=
NETWORK_NAMESPACE=
CNI_MODE=false
EXCLUDE_INTERFACES=
2021-11-27T14:38:35.716883Z info Writing following contents to rules file: /tmp/iptables-rules-1638023915714479778.txt526996950
* nat
-N ISTIO_INBOUND
-N ISTIO_REDIRECT
-N ISTIO_IN_REDIRECT
-N ISTIO_OUTPUT
-A ISTIO_INBOUND -p tcp --dport 15008 -j RETURN
-A ISTIO_REDIRECT -p tcp -j REDIRECT --to-ports 15001
-A ISTIO_IN_REDIRECT -p tcp -j REDIRECT --to-ports 15006
-A PREROUTING -p tcp -j ISTIO_INBOUND
-A ISTIO_INBOUND -p tcp --dport 22 -j RETURN
-A ISTIO_INBOUND -p tcp --dport 15090 -j RETURN
-A ISTIO_INBOUND -p tcp --dport 15021 -j RETURN
-A ISTIO_INBOUND -p tcp --dport 15020 -j RETURN
-A ISTIO_INBOUND -p tcp -j ISTIO_IN_REDIRECT
-A OUTPUT -p tcp -j ISTIO_OUTPUT
-A ISTIO_OUTPUT -o lo -s 127.0.0.6/32 -j RETURN
-A ISTIO_OUTPUT -o lo ! -d 127.0.0.1/32 -m owner --uid-owner 1337 -j ISTIO_IN_REDIRECT
-A ISTIO_OUTPUT -o lo -m owner ! --uid-owner 1337 -j RETURN
-A ISTIO_OUTPUT -m owner --uid-owner 1337 -j RETURN
-A ISTIO_OUTPUT -o lo ! -d 127.0.0.1/32 -m owner --gid-owner 1337 -j ISTIO_IN_REDIRECT
-A ISTIO_OUTPUT -o lo -m owner ! --gid-owner 1337 -j RETURN
-A ISTIO_OUTPUT -m owner --gid-owner 1337 -j RETURN
-A ISTIO_OUTPUT -d 127.0.0.1/32 -j RETURN
-A ISTIO_OUTPUT -j ISTIO_REDIRECT
COMMIT
2021-11-27T14:38:35.716934Z info Running command: iptables-restore --noflush /tmp/ iptables-rules-1638023915714479778.txt526996950 # 该步骤失败
2021-11-27T14:38:35.982415Z info Writing following contents to rules file: /tmp/ip6tables-rules-1638023915982320176.txt160569149
2021-11-27T14:38:35.982855Z info Running command: ip6tables-restore --noflush /tmp/ip6tables-rules-1638023915982320176.txt160569149
2021-11-27T14:38:38.040088Z info Running command: iptables-save
2021-11-27T14:38:38.042112Z info Command output:
# Generated by iptables-save v1.8.4 on Sat Nov 27 14:38:38 2021
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:ISTIO_INBOUND - [0:0]
:ISTIO_IN_REDIRECT - [0:0]
:ISTIO_OUTPUT - [0:0]
:ISTIO_REDIRECT - [0:0]
-A PREROUTING -p tcp -j ISTIO_INBOUND
-A OUTPUT -p tcp -j ISTIO_OUTPUT
-A ISTIO_INBOUND -p tcp -m tcp --dport 15008 -j RETURN
-A ISTIO_INBOUND -p tcp -m tcp --dport 22 -j RETURN
-A ISTIO_INBOUND -p tcp -m tcp --dport 15090 -j RETURN
-A ISTIO_INBOUND -p tcp -m tcp --dport 15021 -j RETURN
-A ISTIO_INBOUND -p tcp -m tcp --dport 15020 -j RETURN
-A ISTIO_INBOUND -p tcp -j ISTIO_IN_REDIRECT
-A ISTIO_IN_REDIRECT -p tcp -j REDIRECT --to-ports 15006
-A ISTIO_OUTPUT -s 127.0.0.6/32 -o lo -j RETURN
-A ISTIO_OUTPUT ! -d 127.0.0.1/32 -o lo -m owner --uid-owner 1337 -j ISTIO_IN_REDIRECT
-A ISTIO_OUTPUT -o lo -m owner ! --uid-owner 1337 -j RETURN
-A ISTIO_OUTPUT -m owner --uid-owner 1337 -j RETURN
-A ISTIO_OUTPUT ! -d 127.0.0.1/32 -o lo -m owner --gid-owner 1337 -j ISTIO_IN_REDIRECT
-A ISTIO_OUTPUT -o lo -m owner ! --gid-owner 1337 -j RETURN
-A ISTIO_OUTPUT -m owner --gid-owner 1337 -j RETURN
-A ISTIO_OUTPUT -d 127.0.0.1/32 -j RETURN
-A ISTIO_OUTPUT -j ISTIO_REDIRECT
-A ISTIO_REDIRECT -p tcp -j REDIRECT --to-ports 15001
COMMIT
# Completed on Sat Nov 27 14:38:38 2021
[root@prctyjs4jwzkvv ~]#
从正常的日志中可以看到,istio会先把文件写到一个文件中 /tmp/xxxx
,然后执行 iptables-restore --noflush /tmp/xxx
下发iptables的规则。但是在该步骤时失败了。
问题诊断
检查操作系统版本,发现是centos8.2
root@prctyjs4jwzkvv ~]# uname -a
Linux prctyjs4jwzkvv 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Tue Nov 16 14:42:35 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
[root@prctyjs4jwzkvv ~]# uname -r
4.18.0-348.2.1.el8_5.x86_64
[root@prctyjs4jwzkvv ~]# cat /etc/redhat-release
CentOS Linux release 8.2.2004 (Core)
centos8使用iptables-nft
替换centos7的iptables-legacy
,iptables
及iptables-restore
均是legacy模式下的命令。
[root@prctyjs4jwzkvv ~]# iptables -V
iptables v1.8.4 (nf_tables)
[root@prctyjs4jwzkvv ~]# which iptables
/usr/sbin/iptables
[root@prctyjs4jwzkvv ~]# ls -l /usr/sbin/iptables
lrwxrwxrwx 1 root root 17 Aug 25 07:13 /usr/sbin/iptables -> xtables-nft-multi
问题根本原因:centos8默认使用iptables-nft模式,并没有开启iptables legacy,而istio使用legacy模式,导致报错。
更专业的说法:
在centos 8上,更准确地说是在Linux 4.x内核里,nftables已经取代了iptables。用户态iptables命令还可以用,完全是出于兼容原来的一些用法,调用到内核还是走nftables。所以,有nf_nat模块没有iptables_nat模块是正常的。如果上层强依赖iptables_nat这个内核模块,反而不正常了,这样的话上层在标准的CentOS 8上运行就有问题。nf_nat和nft_chain_nat结合起来完全可以实现iptables nat原来的功能。nf是netfilter,nft是nftables。
解决办法:启用iptable_nat内核模块
modprobe iptable_nat
但是笔者是启用了所有netfilter相关的内核:
modprobe br_netfilter ; modprobe nf_nat ; modprobe xt_REDIRECT ; modprobe xt_owner; modprobe iptable_nat
所有的node节点开启该内核后,重启pod,sidecar正常,initContainer不会再报 iptables-restore
的错误。
再次检查监控及Tracing,数据正常。
插曲:使用iptables
命令仍然看不到iptables中nat表的规则?
手动进入容器网络协议栈,还是看不到相关规则
[root@prctyjs4jwzkvv ~]# kubectl -n xxy-1127aa get po xx-5c698bff6b-4wq57 -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
xx-5c698bff6b-4wq57 2/2 Running 0 8m56s 10.0.1.39 192.168.0.3 <none> <none>
[root@prctyjs4jwzkvv ~]# kubectl -n xxy-1127aa get po xx-5c698bff6b-4wq57 -owide^C
[root@prctyjs4jwzkvv ~]# ssh 192.168.0.3
Last login: Sun Nov 28 10:59:10 2021 from 192.168.0.6
[root@prafnkteojp7uc ~]# nsenter -n -t 1011551
[root@prafnkteojp7uc ~]# iptables -vS
-P INPUT ACCEPT -c 0 0
-P FORWARD ACCEPT -c 0 0
-P OUTPUT ACCEPT -c 0 0
# Warning: iptables-legacy tables present, use iptables-legacy to see them
[root@prafnkteojp7uc ~]# exit
logout
[root@prafnkteojp7uc ~]# nsenter -n -t 1011551
[root@prafnkteojp7uc ~]# iptables -V
iptables v1.8.4 (nf_tables)
原因:centos8使用 iptables-nft,cetons7是iptables-legacy,iptables
的命令是 centos7的(legacy),看不到 iptables-nft的规则,此时需要装nft
的命令才能查看规则。或是在单独再启动一个centos7的容器,网络使用container in container模式,然后在该容器中使用iptables命令查看规则。
root@rhel-8 # iptables -V
iptables v1.8.4 (nf_tables) # 这个是 iptable-nft,centos8使用该版本
root@rhel-7 # iptables -V
iptables v1.4.21 # centos7 使用iptable-legacy