Kubernetes 1.15.5和romana 2.0.2在添加或删除ANY pod时出现网络错误



我在kubernetes集群中遇到了一些神秘的网络错误。虽然我最初在使用ingress时遇到了这些错误,但当我绕过负载均衡器、绕过kube代理和绕过nginx ingress时,会出现更多错误。当直接转到服务和直接转到pod IP时,出现的错误最多。我相信这是因为负载均衡器和nginx比原始iptable路由有更好的错误处理。

为了测试错误,我使用来自同一子网上VM的apache基准测试,任何并发级别,没有保持活动,连接到pod IP,并使用足够高的请求号,以便有时间扩大或缩小部署。奇怪的是,我修改哪个部署根本无关紧要,因为它总是会导致相同的错误集,即使它与我正在修改的pod无关。任何pod的添加或删除都会触发apache基准测试错误。手动删除、放大/缩小、自动缩放所有触发错误。如果在ab测试运行时没有pod更改,则不会报告任何错误。注意,如果不能消除错误的话,keep-alive似乎可以大大减少错误,但我只测试了几次,从未发现错误。

除了一些奇怪的iptable冲突之外,我真的不明白删除pod A会如何影响pod B的网络连接。由于错误很短,几秒钟内就会消失,这看起来更像是短暂的网络中断。

样本ab测试:ab -n 5000 -c 2 https://10.112.0.24/

使用HTTPS时出错:

SSL handshake failed (5).
SSL read failed (5) - closing connection

使用HTTP:时出错

apr_socket_recv: Connection reset by peer (104)
apr_socket_recv: Connection refused (111)

ab输出示例。遇到第一个错误后的I ctl-C:

$ ab -n 5000 -c 2 https://10.112.0.24/
This is ApacheBench, Version 2.3 <$Revision: 1826891 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 10.112.0.24 (be patient)
Completed 500 requests
Completed 1000 requests
SSL read failed (5) - closing connection
Completed 1500 requests
^C
Server Software:        nginx
Server Hostname:        10.112.0.24
Server Port:            443
SSL/TLS Protocol:       TLSv1.2,ECDHE-RSA-AES256-GCM-SHA384,2048,256
Document Path:          /
Document Length:        2575 bytes
Concurrency Level:      2
Time taken for tests:   21.670 seconds
Complete requests:      1824
Failed requests:        2
(Connect: 0, Receive: 0, Length: 1, Exceptions: 1)
Total transferred:      5142683 bytes
HTML transferred:       4694225 bytes
Requests per second:    84.17 [#/sec] (mean)
Time per request:       23.761 [ms] (mean)
Time per request:       11.881 [ms] (mean, across all concurrent requests)
Transfer rate:          231.75 [Kbytes/sec] received
Connection Times (ms)
min  mean[+/-sd] median   max
Connect:        5   15   9.8     12      82
Processing:     1    9   9.0      6     130
Waiting:        0    8   8.9      6     129
Total:          7   23  14.4     19     142
Percentage of the requests served within a certain time (ms)
50%     19
66%     24
75%     28
80%     30
90%     40
95%     54
98%     66
99%     79
100%    142 (longest request)

可能相关的当前sysctl设置:

net.netfilter.nf_conntrack_tcp_be_liberal = 1
net.nf_conntrack_max = 131072
net.netfilter.nf_conntrack_buckets = 65536
net.netfilter.nf_conntrack_count = 1280
net.ipv4.ip_local_port_range = 27050    65500

我没有看到任何连接"完全"错误。我能说的最好的是没有数据包丢失。我们最近从1.14升级,没有注意到这个问题,但我不能肯定它不存在。我相信我们很快就会被迫离开罗马,因为它似乎不再得到维护,而且当我们升级到kube 1.16.x时,我们在启动时遇到了问题。

我今天在网上搜索了一整天,寻找类似的问题,与我们的问题最相似的是https://tech.xing.com/a-reason-for-unexplained-connection-timeouts-on-kubernetes-docker-abd041cf7e02但我不知道如何实现iptable伪装——假设我们使用的是romana,我读过(https://github.com/kubernetes/kubernetes/pull/78547#issuecomment-527578153),随机完全是我们正在使用的linux内核5的默认值。有什么想法吗?

  • kubernetes 1.15.5
  • 罗马2.0.2
  • centos7
  • Linux kube-master01 5.0.7-1.el7.elrepo.x86_64#1 SMP美国东部时间2019年4月5日星期五18:07:52 x86_64 x86_66 GNU/Linux

======2019年11月5日更新======

有人建议测试替代CNI。我选择了印花布,因为我们在一个旧的基于Debian的kube集群中使用了印花布。我用我们最基本的Centos 7模板(vSphere)重建了一个虚拟机,所以我们的定制带来了一些负担。我不能列出我们在模板中定制的所有内容,但最显著的变化是内核5升级yum --enablerepo=elrepo-kernel -y install kernel-ml

启动虚拟机后,安装kubernetes并运行测试的最简单步骤如下:

yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum -y install docker-ce-3:18.09.6-3.el7.x86_64
systemctl start docker
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
EOF
# Set SELinux in permissive mode (effectively disabling it)
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
echo '1' > /proc/sys/net/bridge/bridge-nf-call-iptables
yum install -y kubeadm-1.15.5-0 kubelet-1.15.5-0 kubectl-1.15.5-0
systemctl enable --now kubelet
kubeadm init --pod-network-cidr=192.168.0.0/16
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
kubectl taint nodes --all node-role.kubernetes.io/master-
kubectl apply -f https://docs.projectcalico.org/v3.8/manifests/calico.yaml
cat <<EOF > /tmp/test-deploy.yml
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
name: test
spec:
selector:
matchLabels:
app: test
replicas: 1
template:
metadata:
labels:
app: test
spec:
containers:
- name: nginx
image: nginxdemos/hello
ports:
- containerPort: 80
EOF
# wait for control plane to become healthy
kubectl apply -f /tmp/test-deploy.yml

现在设置已经准备好了,这就是ab测试:

$ docker run --rm jordi/ab -n 100 -c 1  http://192.168.4.4/
This is ApacheBench, Version 2.3 <$Revision: 1826891 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 192.168.4.4 (be patient)...apr_pollset_poll: The timeout specified has expired (70007)
Total of 11 requests completed

ab测试在此错误后放弃。如果我减少请求数量以避免超时,这就是你会看到的:

$ docker run --rm jordi/ab -n 10 -c 1  http://192.168.4.4/
This is ApacheBench, Version 2.3 <$Revision: 1826891 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 192.168.4.4 (be patient).....done

Server Software:        nginx/1.13.8
Server Hostname:        192.168.4.4
Server Port:            80
Document Path:          /
Document Length:        7227 bytes
Concurrency Level:      1
Time taken for tests:   0.029 seconds
Complete requests:      10
Failed requests:        0
Total transferred:      74140 bytes
HTML transferred:       72270 bytes
Requests per second:    342.18 [#/sec] (mean)
Time per request:       2.922 [ms] (mean)
Time per request:       2.922 [ms] (mean, across all concurrent requests)
Transfer rate:          2477.50 [Kbytes/sec] received
Connection Times (ms)
min  mean[+/-sd] median   max
Connect:        0    1   0.8      1       3
Processing:     1    2   1.2      1       4
Waiting:        0    1   1.3      0       4
Total:          1    3   1.4      3       5
Percentage of the requests served within a certain time (ms)
50%      3
66%      3
75%      4
80%      5
90%      5
95%      5
98%      5
99%      5
100%      5 (longest request)

这个问题在技术上与我报道的原始问题不同,但这是一个不同的CNI,仍然存在网络问题。当我在kube/romana集群中运行相同的测试时,它确实有常见的超时错误:在与pod相同的节点上运行ab测试。两者都遇到了相同的超时错误,但在罗马,我可以在达到超时之前收到几千个请求。Calico在收到十几个请求之前遇到超时错误。

其他变体或注释:-netfilter.nf_conntrack_tcp_be_liberal=0/1似乎没有什么区别-较高的CCD_ 3值有时起作用,但它在很大程度上是随机的。-连续几次在低-n值下运行"ab"测试有时会触发超时

在这一点上,我很确定我们的centos安装有问题,但我甚至猜不出可能是什么。有没有其他限制,sysctl或其他配置可能导致这种情况?

======2019年11月6日更新======

我注意到我们安装了一个旧的内核,所以我用同样的新内核5.3.8-1.el7.elrepo.x86_64升级了我的kube/calico测试虚拟机。更新和几次重新启动后,我再也无法再现"apr_pollset_poll:指定的超时已过期(70007)"timout错误。

现在超时错误消失了,我可以重复原始测试,在vSphere虚拟机上加载测试吊舱A并终止吊舱B。在romana环境中,问题仍然存在,但仅当负载测试在与pod a所在的主机不同的主机上时。如果我在同一台主机上运行测试,则不会出现任何错误。使用Calico而不是romana,两台主机都没有负载测试错误,所以问题消失了。可能还有一些设置需要调整,可以帮助romana,但我认为这是romana的"罢工3",所以我将开始将整个环境过渡到Calico,并在那里进行一些验收测试,以确保没有隐藏的问题。

您提到,如果在ab测试运行时没有pod更改,则不会报告任何错误。因此,这意味着在添加或删除pod时会出现错误。

当pod被删除时,这是正常的行为;iptable规则更改的传播需要时间。可能发生的情况是,容器被删除了,但iptable规则尚未更改,但结束数据包正在转发到不存在的容器,这会导致错误(这有点像竞争条件)。

您可以做的第一件事始终是创建readiness probe,因为它将确保在容器准备好处理请求之前,流量不会转发到容器。

要做的第二件事是正确地处理删除容器的问题。这是一项有点困难的任务,因为它可能在许多级别上处理,但你能做的最简单的事情是向你的容器添加PreStop钩子,如下所示:

lifecycle:
preStop:
exec:
command:
- sh
- -c
- "sleep 5"

PreStop hook在pod删除请求的时刻被执行。从这一刻起,k8s开始更改iptable规则,它应该停止将新流量转发到即将被删除的容器。当sleeping时,您给k8s一些时间在集群中传播iptable更改,同时不中断现有连接。PreStop handle退出后,容器将收到SIGTERM信号。

我的建议是将这两种机制结合起来,并检查它是否有帮助。

您还提到绕过入口会导致更多错误。我认为这是由于ingress已经实现了重试机制。如果它无法打开与容器的连接,它会尝试几次,希望能找到一个可以处理其请求的容器。

相关内容

  • 没有找到相关文章

最新更新