Kubernetesピット(二):Service IP(LVS)間欠性TCP接続障害チェック


問題フェーズ(一):
ユーザーはあるredisがカートンを使用していることに反応し、そのredisサービスに接続するにはsvcエージェント、すなわちipvs snatの方式が使用されている.ipvsadm-Lは、VIPが受け取った6379ポートのパケットがrrの方式でpodの80 6379ポートにそれぞれ転送され、50%のパケットを失うことに相当することを発見した.カードを使わないのはおかしい.
# ipvsadm | grep -2 10.108.152.210
TCP  10.108.152.210:6379 rr
  -> 172.26.6.185:http            Masq    1      0          0         
  -> 172.26.6.185:6379            Masq    1      3          3

2.svcを検査する:
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: 2018-12-06T02:45:49Z
  labels:
    app: skuapi-rds-prod
    run: skuapi-rds-prod
  name: skuapi-rds-prod
  namespace: default
  resourceVersion: "41888273"
  selfLink: /api/v1/namespaces/default/services/skuapi-rds-prod
  uid: 09e1a61f-f901-11e8-878f-141877468256
spec:
  clusterIP: 10.108.152.210
  ports:
  - name: redis
    port: 6379
    protocol: TCP
    targetPort: 6379
  selector:
    app: skuapi-rds-prod
  sessionAffinity: None
  type: ClusterIP

svcの構成に問題はないことがわかり、これまでこのsvcを構成していたことを思い出すと、最初はportとtargetPortの設定をデフォルト値80に設定して変更を忘れ、後で手動kubectl edit svcでポートを6379に変更しました.保存を修正した後も、元のtargetPort 80はipvsでRIPの1つとして保持されているはずであり、これはバグであるべきである.
3.解決策:ipvsadmツールを使用して余分なRIPを削除するか、svcを削除して再構築します.
# ipvsadm | grep -2 10.108.152.210
TCP  10.108.152.210:6379 rr
  -> 172.26.6.185:6379            Masq    1      4          0  

問題フェーズ(2):
現象:
svc vip接続が失敗することが多いというユーザーのフィードバックがあり、redisの複数のipに限らず、チェックを開始します.
チェック:
ipvsとシステムの接続状態を調べることで、2つの問題が発見された:1.大量のTIMEが発見されましたWAITのtcp接続は、システム接続の多くが短い接続であることを証明し、ipvs tcpfinの待ち時間を2分と表示し、2分が長すぎるか、短く修正する必要がある.30秒は合理的な値であり、忙しいサービスであれば、この値をより低く変更することができる.2.忘れ物が少なくない
[root@p020107 ~]# ipvsadm -lnc |wc -l
23776
[root@p020107 ~]# ipvsadm -lnc |grep TIME_WAIT | wc -l
10003
[root@p020107 ~]# ipvsadm -L --timeout 
Timeout (tcp tcpfin udp): 900 120 300

root@p020107:~# netstat -s | grep timestamp
    17855 packets rejects in established connections because of timestamp

備考:tcp四回手を振るプロトコルによって、自発的に切断接続要求の一端を発起し(簡単にクライアントと理解する)、その切断接続要求の送信から、その接続のライフサイクルは4段階を経てそれぞれFIN-WAIT 1-->FIN_である.WAIT2 --> TIME_WAIT-->CLOSE、そのうち2つのFIN-WAITフェーズが待つ時間がカーネル構成のnet.ipv4.tcp_fin_timeoutの値は、最初の2つのFIN-WAITフェーズをすばやくスキップするためにTIME_に入るWAIT状態、net.ipv4.tcp_fin_timeout値は短縮を推奨します.TIME_に入るWAIT状態後、デフォルトでは2つのMSL(Max Segment Lifetime)時間を待ち、最後のステップCLOSE状態に達し、tcp接続を閉じてリソースを解放する.注意:MSL時間は異なるプラットフォームでは一般的に30 s-2 minで等しくなく、基本的には変更できません(linuxはこの時間値をカーネルに書き込んでいます).
ではなぜ2*MSLを待つのでしょうか.stackoverflowでは、わかりやすい説明が見つかりました.
So the TIME_WAIT time is generally set to double the packets maximum age. This value is the maximum age your packets will be allowed to get to before the network discards them. That guarantees that, before you’re allowed to create a connection with the same tuple, all the packets belonging to previous incarnations of that tuple will be dead.
time_wait時間は、tcpスライスの最大生存時間の2倍に設計されている.これは、ネットワークが遅延していると同時に、tcpスライスがネットワーク伝送中に予期せぬ事故を起こす可能性があり、送信側が予期せぬ(例えばMSL時間に達した後)ことを確認した後にデータスライスの再送を送信するためである.SOcket接続が待機せずに閉じられ、ポート番号が一致する接続が再開されると、新しく起動したsocket接続が破棄されたsocket接続のデータを受信する可能性があります.そこで、デザインTIME_WAIT待ち時間が2 MSLであるのは、2 MSL待ちの後、これまで古いソケットのデータスライスが受信側に到着していなくても、ネットワーク転送中に期限切れになって消えていることを保証するためであり、新しく起動したソケットはこれまでの古いデータスライスを受信しない.
さいてきかほうしき
最適化の考え方1.接続解除時にTIME_へ加速WAIT状態で、利用可能な接続ポート2を迅速に提供する.timestampsのパケット損失問題の解決
#ipvsが設定した各種接続のタイムアウト時間を表示し、デフォルトのtcpfinを変更して2分で30秒
[root@p020107 ~]# ipvsadm -L --timeout 
Timeout (tcp tcpfin udp): 900 120 300
[root@p020107 ~]# ipvsadm --set 900 30 300

[root@p020107 ~]# ipvsadm -L --timeout 
Timeout (tcp tcpfin udp): 900 30 300

#カーネルパラメータ最適化追加/etc/sysctl.confファイル
#       。   TIME-WAIT sockets      TCP  ,   0,    ;
  net.ipv4.tcp_tw_reuse = 1

  #     TCP   TIME-WAIT sockets     ,   0,    。  ,net.ipv4.tcp_timestamps     ,tcp_tw_recycle       ,tcp timestamp      ,      ,    tcp_timestamps  ,         。
  net.ipv4.tcp_tw_recycle = 1

  #   tcp    fin        ,       
  net.ipv4.tcp_fin_timeout = 30

  #   TIME_WAIT   socket  ,   180 000,       socket     
  net.ipv4.tcp_max_tw_buckets=180000

  # tcp     ,RFC1323    ,      ip      ,      ip tcp                (        
),     ,          ,        。      ,        ,  nat   ,   ip       ip   
    server , server   , ip     ,                   ,          ,  ,   nat    ,       。
  net.ipv4.tcp_timestamps = 0

これらのパラメータの間にはいくつかの関連関係があり、この記事を参照して、非常に詳細に書かれています.http://www.freeoa.net/osuport/cluster/lvs-inuse-problem-sets_3111.html
問題フェーズ(3):
げんしょう
以上の操作が完了すると、TIME_WAIT数は4桁に減少し,パケット損失数はこれ以上増加しなかった.しかし、数日後には、たまに個別のVIPが接続できない場合が再び発生した.そのうちの1つを選んだVIP 10.111.99.131はclient:192.168.58.36 DIP:10.111.99.131 RIP:172.26.8.17の調査を開始した
チェックを開始
3層接続に問題はありません:
ywq@ywq:~$ traceroute 10.111.99.131
traceroute to 10.111.99.131 (10.111.99.131), 30 hops max, 60 byte packets
 1  192.168.58.254 (192.168.58.254)  7.952 ms  8.510 ms  9.131 ms
 2  10.111.99.131 (10.111.99.131)  0.253 ms  0.243 ms  0.226 ms

ywq@ywq:~$ ping 10.111.99.131
PING 10.111.99.131 (10.111.99.131) 56(84) bytes of data.
64 bytes from 10.111.99.131: icmp_seq=1 ttl=63 time=0.296 ms
64 bytes from 10.111.99.131: icmp_seq=2 ttl=63 time=0.318 ms
^C
--- 10.111.99.131 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1020ms
rtt min/avg/max/mdev = 0.296/0.307/0.318/0.011 ms

tcp接続が確立できません
ywq@ywq:~$ telnet 10.111.99.131 80
Trying 10.111.99.131...
telnet: Unable to connect to remote host: Connection timeout

lvs diretor serverでの接続ステータスの表示:[root@p020107 ~]# ipvsadm -lnc | grep 58.36 TCP 00:59 TIME_WAIT 192.168.9.13:58236 10.97.85.43:80 172.26.5.209:80 TCP 00:48 SYN_RECV 192.168.58.36:57964 10.111.99.131:80 172.26.8.17:80 TCP 00:48 SYN_RECV 192.168.58.36:57963 10.111.99.131:80 172.26.8.17:80 TCP 00:48 SYN_RECV 192.168.58.36:57965 10.111.99.131:80 172.26.8.17:80
tcp接続状態がSYN_であることが判明RECV状態では、3回の握手協定に従って、lvsのワークフローと結びつけて、LVS serverがclienのsynパケットを受信し、clientにsyn+ackを返信してSYN_に入ったことを説明する.RECVステータスで、direct serverはバックエンドのreal serverに接続の確立要求を開始します.direct serverがclient側と対話できるようになった以上、directサーバとrealサーバの間でパケットの対話が正常に行われていないか、パケットが失われているか、多くの資料を調べているはずです.rp_filterというカーネルパラメータは、この問題を引き起こす可能性があります.
このパラメータに関する公式の説明を見てみましょう.
rp_filter - INTEGER
	0 - No source validation.
	1 - Strict mode as defined in RFC3704 Strict Reverse Path
	    Each incoming packet is tested against the FIB and if the interface
	    is not the best reverse path the packet check will fail.
	    By default failed packets are discarded.
	2 - Loose mode as defined in RFC3704 Loose Reverse Path
	    Each incoming packet's source address is also tested against the FIB
	    and if the source address is not reachable via any interface
	    the packet check will fail.

	Current recommended practice in RFC3704 is to enable strict mode
	to prevent IP spoofing from DDos attacks. If using asymmetric routing
	or other complicated routing, then loose mode is recommended.

	The max value from conf/{all,interface}/rp_filter is used
	when doing source validation on the {interface}.

	Default value is 0. Note that some distributions enable it
	in startup scripts.

簡単に説明します:0:オープンソース検出1:厳格モードを表示しないで、パケットのソースによって、FIBテーブル(Forward Information Table、ルーティングテーブルと理解できる)を調べることによって、パケットがポートに入るのを検査するのは同時にポートを出るので、最適な経路と見なして、もし最適な経路に合わないならば、パケット2:ばらばらモードを捨てて、パケットのソースを検査して、FIBテーブルを調べて、いずれのポートでもこのソースに到達できない場合、パケット損失は使用シーンと組み合わせて、LVS(nat)+k 8 sの動作シーンでは、LVSサーバはReal Serverのパケットが移動可能なtunnelインタフェースに送られ、Real Serverはtunnelインタフェースを通じてパケットを受信した後、ルーティングテーブルを調べてパケットが物理eth/bondなどのインタフェースに戻ることを発見し、rp_filterが厳格なモードをオンにすると、ネットワークの異常が発生します.
各kube nodeのNIC構成パラメータを確認し、centos 7を発見した.4のいくつかのnodeのデフォルトは確かにrp_を開きましたフィルタ、ubuntuの大部分はありません:
#     veth     ,               
[root@p020114 ~]# sysctl -a | grep rp_filter | grep -v 'veth'
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.bond0.rp_filter = 1
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.docker0.rp_filter = 2
net.ipv4.conf.dummy0.rp_filter = 0
net.ipv4.conf.em1.rp_filter = 1
net.ipv4.conf.em2.rp_filter = 1
net.ipv4.conf.em3.rp_filter = 1
net.ipv4.conf.em4.rp_filter = 1
net.ipv4.conf.kube-bridge.rp_filter = 0
net.ipv4.conf.kube-dummy-if.rp_filter = 0
net.ipv4.conf.lo.rp_filter = 0
net.ipv4.conf.tun-192168926.rp_filter = 1
net.ipv4.conf.tun-192168927.rp_filter = 1
net.ipv4.conf.tun-192168928.rp_filter = 1
net.ipv4.conf.tun-192168929.rp_filter = 1
net.ipv4.conf.tunl0.rp_filter = 0

#この機能をオフにする
echo "
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.bond0.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.docker0.rp_filter = 2
net.ipv4.conf.dummy0.rp_filter = 0
net.ipv4.conf.em1.rp_filter = 0
net.ipv4.conf.em2.rp_filter = 0
net.ipv4.conf.em3.rp_filter = 0
net.ipv4.conf.em4.rp_filter = 0
net.ipv4.conf.kube-bridge.rp_filter = 0
net.ipv4.conf.kube-dummy-if.rp_filter = 0
net.ipv4.conf.lo.rp_filter = 0
net.ipv4.conf.tun-192168926.rp_filter = 0
net.ipv4.conf.tun-192168927.rp_filter = 0
net.ipv4.conf.tun-192168928.rp_filter = 0
net.ipv4.conf.tun-192168929.rp_filter = 0
net.ipv4.conf.tunl0.rp_filter = 0
" >> /etc/sysctl.conf

#ロード有効
sysctl -p

まとめ
VIPがたまにTCP接続を確立できない問題は解決し、1週間が過ぎても再現されず、ingを観察し続けた.