Kubernetes: (1.17) Kubelet ne se reconnectera pas à Apiserver après une panne de la carte réseau (utilisation d'une connexion réseau fermée)

Créé le 28 janv. 2020  ·  123Commentaires  ·  Source: kubernetes/kubernetes

Nous venons de mettre à niveau notre cluster de production vers 1.17.2.

Depuis la mise à jour de samedi, nous avons eu cette étrange panne : Kubelet, après un échec de liaison NIC (qui récupère peu de temps après), verra toutes ses connexions rompues et ne réessayera pas de les rétablir à moins d'être redémarré manuellement.

Voici la chronologie de la dernière fois que cela s'est produit :

01:31:16 : Le noyau reconnaît un échec sur l'interface de liaison. Cela dure un moment. Finalement, il récupère.

Jan 28 01:31:16 baremetal044 kernel: bond-mngmt: link status definitely down for interface eno1, disabling it
...
Jan 28 01:31:37 baremetal044  systemd-networkd[1702]: bond-mngmt: Lost carrier
Jan 28 01:31:37 baremetal044  systemd-networkd[1702]: bond-mngmt: Gained carrier
Jan 28 01:31:37 baremetal044  systemd-networkd[1702]: bond-mngmt: Configured

Comme prévu, toutes les montres sont fermées. Le message est le même pour tous :

...
Jan 28 01:31:44 baremetal044 kubelet-wrapper[2039]: W0128 04:31:44.352736    2039 reflector.go:326] object-"namespace"/"default-token-fjzcz": watch of *v1.Secret ended with: very short watch: object-"namespace"/"default-token-fjzcz": Unexpected watch close - watch lasted less than a second and no items received
...

Alors ces messages commencent :

`Jan 28 01:31:44 baremetal44 kubelet-wrapper[2039]: E0128 04:31:44.361582 2039 desired_state_of_world_populator.go:320] Error processing volume "disco-arquivo" for pod "pod-bb8854ddb-xkwm9_namespace(8151bfdc-ec91-48d4-9170-383f5070933f)": error processing PVC namespace/disco-arquivo: failed to fetch PVC from API server: Get https://apiserver:443/api/v1/namespaces/namespace/persistentvolumeclaims/disco-arquivo: write tcp baremetal44.ip:42518->10.79.32.131:443: use of closed network connection`

Ce qui, je suppose, ne devrait pas être un problème pendant un certain temps. Mais il ne s'en remet jamais. Notre événement s'est produit à 01h31 et a dû redémarrer manuellement Kubelet vers 9h pour que les choses soient normalisées.

# journalctl --since '2020-01-28 01:31'   | fgrep 'use of closed' | cut -f3 -d' ' | cut -f1 -d1 -d':' | sort | uniq -dc
   9757 01
  20663 02
  20622 03
  20651 04
  20664 05
  20666 06
  20664 07
  20661 08
  16655 09
      3 10

Les serveurs d'Api étaient opérationnels, tous les autres nœuds étaient opérationnels, tout le reste s'est déroulé sans incident. Celui-ci était le seul touché (aujourd'hui) par ce problème.

Existe-t-il un moyen d'atténuer ce genre d'événement?

Serait-ce un bug ?

kinsupport siapi-machinery sinode

Commentaire le plus utile

Je l'ai corrigé en exécutant ce script bash toutes les 5 minutes :

#!/bin/bash
output=$(journalctl -u kubelet -n 1 | grep "use of closed network connection")
if [[ $? != 0 ]]; then
  echo "Error not found in logs"
elif [[ $output ]]; then
  echo "Restart kubelet"
  systemctl restart kubelet
fi

Tous les 123 commentaires

/sig nœud
/sig api-machines

En regardant dans le code, l'erreur se produit ici

L'explication du code est qu'il suppose son EOF probable (IsProbbableEOF) alors que dans ce cas, cela ne semble pas être le cas.

/assign @caesarxuchao

@rikatz pouvez-vous expliquer comment avez-vous

Ma pensée est que le réflecteur aurait redémarré la montre, quelle que soit la façon dont il gère l'erreur ( code ), cela n'explique donc pas l'échec de la récupération.

Exactement @caesarxuchao donc c'est notre question.

J'ai suivi l'erreur en la saisissant dans le code et en la croisant avec ce que kubelet faisait à ce moment-là (en regardant les secrets) pour entrer dans cette partie.

Pas un moyen avancé, à travers cela semble être le point exact du code d'erreur.

La question est, parce que la connexion est fermée, y a-t-il quelque part en train de signaler qu'il s'agit de la montre EOF au lieu de comprendre qu'il s'agit d'une erreur ?

Je n'ai rien d'autre de plus intelligent à ajouter que nous avons eu un autre nœud défaillant de la même manière, augmentant les occurrences des 4 derniers jours à 4.

J'essaierai de cartographier si des événements de déconnexion de liaison se produisent sur d'autres nœuds et si kubelet récupère - cela peut porter malheur sur certaines récupérations, et non un événement à 100%.

Je pense que nous voyons cela aussi, mais nous n'avons pas de liens, nous ne voyons que ces messages réseau "porteur perdu" pour les interfaces Calico cali* , et ce sont des périphériques veth locaux.

J'ai également rencontré cela, sans aucun lien impliqué. Le redémarrage du nœud résout le problème, mais le simple redémarrage du service Kubelet ne le fait pas (tous les appels d'API échouent avec "Non autorisé").

J'ai également rencontré cela, sans aucun lien impliqué. Le redémarrage du nœud résout le problème, mais le simple redémarrage du service Kubelet ne le fait pas (tous les appels d'API échouent avec "Non autorisé").

Mise à jour : le redémarrage de Kubelet a résolu le problème après que suffisamment de temps (1 heure ?) s'est écoulé.

Je constate ce même comportement. Installations propres d'Ubuntu 18.04.3 LTS. Cluster construit avec rancher 2.3.4. J'ai vu cela se produire périodiquement ces derniers temps et le simple fait de redémarrer kubelet a tendance à le réparer pour moi. Hier soir, mes 3 nœuds de travail ont présenté le même comportement. J'en ai corrigé 2 pour faire monter mon cluster. Le troisième est toujours dans cet état pendant que je fouille.

nous constatons le même problème sur CentOS 7, cluster fraîchement construit avec rancher (1.17.2). Nous utilisons le tissage. Les 3 nœuds de travail affichent ce problème. Le redémarrage de kubelet ne fonctionne pas pour nous, nous devons redémarrer l'ensemble du nœud

/sig nœud
/sig api-machines

En regardant dans le code, l'erreur se produit ici

L'explication du code est qu'il suppose son EOF probable (IsProbbableEOF) alors que dans ce cas, cela ne semble pas être le cas.

Nous constatons également le même problème. D'après le journal, nous avons constaté qu'une fois le problème survenu, toutes les demandes ultérieures étaient toujours envoyées sur la même connexion. Il semble que, bien que le client renvoie la demande à apiserver, la bibliothèque http2 sous-jacente conserve toujours l'ancienne connexion, de sorte que toutes les demandes ultérieures sont toujours envoyées sur cette connexion et reçoivent la même erreur use of closed connection .

La question est donc de savoir pourquoi http2 maintient toujours une connexion déjà fermée ? Peut-être que la connexion qu'il maintenait est bien vivante mais que certaines connexions intermédiaires sont fermées de manière inattendue ?

J'ai très souvent le même problème avec un cluster Raspberry Pi avec k8s 1.17.3. Sur la base de certains problèmes plus anciens, j'ai défini la limite de connexion http du serveur API kube à 1000 "- --http2-max-streams-per-connection=1000", cela a fonctionné pendant plus de 2 semaines après cela, il recommence maintenant.

Est-il possible de reconstruire kube-apiserver https://github.com/kubernetes/apiserver/blob/b214a49983bcd70ced138bd2717f78c0cff351b2/pkg/server/secure_serving.go#L50
définir le s.DisableHTTP2 sur true par défaut ?
Existe-t-il un fichier docker pour une image officielle ( k8s.gcr.io/kube-apiserver:v1.17.3 ) ?

idem ici. (ubuntu 18.04, kubernetes 1.17.3)

Nous l'avons également observé dans deux de nos clusters. Pas tout à fait sûr de la cause première, mais au moins nous avons pu voir cela se produire en cluster avec un nombre de surveillances très élevé. Cependant, je n'ai pas pu reproduire en forçant un nombre élevé de montres par kubelet (démarrage des pods avec 300 secrets par pod, ce qui a également entraîné 300 montres par pod dans les métriques Prometheus). La définition http2-max-streams-per-connection valeurs très faibles de

Comme solution de contournement, tous mes nœuds redémarrent chaque nuit kublet via cronjob local. Maintenant, il y a 10 jours, je peux dire que cela fonctionne pour moi, je n'ai plus "d'utilisation de connexion réseau fermée" sur mes nœuds.

@sbiermann
Merci d'avoir posté ceci. Quel intervalle de temps utilisez-vous pour cronjob ?

24 heures

Je peux également confirmer ce problème, nous ne sommes pas encore sur 1.17.3, exécutant actuellement Ubuntu 19.10 :

Linux <STRIPPED>-kube-node02 5.3.0-29-generic #31-Ubuntu SMP Fri Jan 17 17:27:26 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

NAME                  STATUS   ROLES    AGE   VERSION       INTERNAL-IP   EXTERNAL-IP   OS-IMAGE       KERNEL-VERSION     CONTAINER-RUNTIME
STRIPPED-kube-node02   Ready    <none>   43d   v1.16.6   10.6.0.12     <none>        Ubuntu 19.10   5.3.0-29-generic   docker://19.3.3

Je peux également le confirmer sur Kubernetes 1.17.4 déployé via Rancher 2.3.5 sur les nœuds RancherOS 1.5.5. Le redémarrage du kubelet semble fonctionner pour moi, je n'ai pas besoin de redémarrer tout le nœud.

La cause sous-jacente pour moi semble être que la RAM est sur le point de s'épuiser et que kswapd0 utilise jusqu'à 100% du processeur à cause de cela, car j'ai oublié de définir le swappiness sur 0 pour mes nœuds Kubernetes. Après avoir défini le swappiness sur 0 et ajouté de la RAM aux machines, le problème ne s'est pas encore reproduit pour moi.

Si le problème sous-jacent était "http2 utilisant des connexions mortes", le redémarrage de kubelet devrait résoudre le problème. https://github.com/kubernetes/kubernetes/pull/48670 a suggéré que la réduction de TCP_USER_TIMEOUT peut atténuer le problème. J'ai ouvert https://github.com/golang/net/pull/55 pour ajouter une vérification de l'état de la connexion côté client à la bibliothèque http2, mais cela prendra plus de temps pour atterrir.

Si le redémarrage de kubelet n'a pas résolu le problème, il s'agit probablement d'une cause racine différente.

J'ai le même problème avec la v1.17.2 lors du redémarrage du réseau, mais un seul des nœuds a ce problème (mon cluster a cinq nœuds), je ne peux pas le reproduire. Redémarrer kubelet a résolu ce problème.

Comment puis-je éviter ce problème ? Mettez à niveau la dernière version ou avez-vous un autre moyen de le réparer ?

Je l'ai corrigé en exécutant ce script bash toutes les 5 minutes :

#!/bin/bash
output=$(journalctl -u kubelet -n 1 | grep "use of closed network connection")
if [[ $? != 0 ]]; then
  echo "Error not found in logs"
elif [[ $output ]]; then
  echo "Restart kubelet"
  systemctl restart kubelet
fi

J'ai créé un patch sans redémarrer kubelet et il semble que le problème soit résolu.
correctif de date limite

diff --git a/staging/src/k8s.io/client-go/transport/cache.go b/staging/src/k8s.io/client-go/transport/cache.go
index 7c40848c79f..bd61b39551a 100644
--- a/staging/src/k8s.io/client-go/transport/cache.go
+++ b/staging/src/k8s.io/client-go/transport/cache.go
@@ -38,6 +38,8 @@ const idleConnsPerHost = 25

 var tlsCache = &tlsTransportCache{transports: make(map[tlsCacheKey]*http.Transport)}

+type dialFunc func(network, addr string) (net.Conn, error)
+
 type tlsCacheKey struct {
        insecure   bool
        caData     string
@@ -92,7 +94,7 @@ func (c *tlsTransportCache) get(config *Config) (http.RoundTripper, error) {
                TLSHandshakeTimeout: 10 * time.Second,
                TLSClientConfig:     tlsConfig,
                MaxIdleConnsPerHost: idleConnsPerHost,
-               Dial:                dial,
+               Dial:                setReadDeadlineAfterDial(dial, 30*time.Second),
        })
        return c.transports[key], nil
 }
@@ -111,3 +113,18 @@ func tlsConfigKey(c *Config) (tlsCacheKey, error) {
                serverName: c.TLS.ServerName,
        }, nil
 }
+
+func setReadDeadlineAfterDial(dialer dialFunc, timeout time.Duration) dialFunc {
+       return func(network, addr string) (net.Conn, error) {
+               c, err := dialer(network, addr)
+               if err != nil {
+                       return nil, err
+               }
+
+               if err := c.SetReadDeadline(time.Now().Add(timeout)); err != nil {
+                       return nil, err
+               }
+
+               return c, nil
+       }
+}

@mYmNeo Pouvez-vous s'il vous plaît expliquer comment reconstruire le client-go ?

@mYmNeo Pouvez-vous s'il vous plaît expliquer comment reconstruire le client-go ?

@ik9999 Appliquez ce correctif, puis reconstruisez kubelet et remplacez le binaire

@mYmNeo Comment puis-je reproduire ce problème et le tester ?

Je l'ai corrigé en exécutant ce script bash toutes les 5 minutes

@ik9999 Merci, ça marche.

cc @liggitt

le réglage SetReadDeadline signifie-t-il que toutes les montres se fermeront toutes les 30 secondes ?

le réglage SetReadDeadline signifie-t-il que toutes les montres se fermeront toutes les 30 secondes ?

Oui. C'est une mauvaise façon de résoudre ce problème (forcer la fermeture d'une connexion).

Juste un autre cas :

Nous le constatons également dans les clusters Kube 1.16.8. Le redémarrage de la machine virtuelle peut être utilisé pour ramener le nœud à un bon état (je soupçonne qu'un redémarrage de kubelet aurait également fonctionné).

Notre kubelet de configuration parle à une instance haproxy locale sur localhost qui agit comme un équilibreur de charge TCP pour les multiples instances principales du backend. Nous allons étudier si l'ajout

option clitcpka    # enables keep-alive only on client side
option srvtcpka    # enables keep-alive only on server side

Nos instances d'équilibrage de charge aident à réduire le besoin de redémarrage explicite et peuvent conduire à une récupération complète. Exemple de journaux répétés

Apr  8 00:04:25 kube-bnkjtdvd03sqjar31uhg-cgliksp01-cgliksp-00001442 kubelet.service[6175]: E0408 00:04:25.472682    6175 reflector.go:123] object-"ibm-observe"/"sysdig-agent": Failed to list *v1.ConfigMap: Get https://172.20.0.1:2040/api/v1/namespaces/ibm-observe/configmaps?fieldSelector=metadata.name%3Dsysdig-agent&limit=500&resourceVersion=0: write tcp 172.20.0.1:22501->172.20.0.1:2040: use of closed network connection
Apr  8 00:04:25 kube-bnkjtdvd03sqjar31uhg-cgliksp01-cgliksp-00001442 kubelet.service[6175]: E0408 00:04:25.472886    6175 reflector.go:123] object-"default"/"default-token-gvbk5": Failed to list *v1.Secret: Get https://172.20.0.1:2040/api/v1/namespaces/default/secrets?fieldSelector=metadata.name%3Ddefault-token-gvbk5&limit=500&resourceVersion=0: write tcp 172.20.0.1:22501->172.20.0.1:2040: use of closed network connection

Publiera une mise à jour si cela résout notre problème spécifique au cas où cela aiderait quelqu'un ici dans l'intervalle.

Curieux de savoir s'il existe un paramètre de configuration pour définir une limite supérieure absolue sur un temps de visionnage ? J'ai trouvé --streaming-idle-connection-timeout mais rien de spécifique pour les montres.

Nous voyons cela dans kube 1.17.4 après que le serveur API n'est pas sain en raison de « etcd a échoué : raison retenue ».

Salut les gars. J'ai recompilé le binaire kubernetes avec golang 1.14. Il semble que le problème ait disparu

@mYmNeo golang 1.14 + kubernetes v1.17 ?

@mYmNeo golang 1.14 + kubernetes v1.17 ?

@pytimer Nous utilisons 1.16.6 sans changer de code, juste en recompilant. Je pense que la cause première peut être le golang.

Hey! Vous avez le même problème ici, k8s 1.17.4 pensons-nous que nous pourrions obtenir un 1.17.5 recompilé avec go 1.14 si cela résout le problème?

Malheureusement, la mise à jour vers go1.14 nécessite des mises à jour de plusieurs composants clés, il est donc peu probable qu'elle soit ramenée à Kube 1.17. Vous pouvez suivre les problèmes et les progrès dans https://github.com/kubernetes/kubernetes/pull/88638

Bon à savoir, merci

@callicles a-t-il été confirmé que la recompilation avec go 1.14 a résolu le problème ?

Je vois un problème identique sur 1.16.8 - de temps en temps (parfois une fois tous les deux jours, parfois toutes les deux semaines), le nœud devient NotReady, avec la raison pour laquelle Kubelet a cessé de publier le statut du nœud et "l'utilisation d'une connexion réseau fermée" remplir les journaux

go peut avoir des problèmes avec la mise à niveau h2.
golang.org/x/net/http2/transport.go

    upgradeFn := func(authority string, c *tls.Conn) http.RoundTripper {
        addr := authorityAddr("https", authority)
        if used, err := connPool.addConnIfNeeded(addr, t2, c); err != nil {
            go c.Close()
            return erringRoundTripper{err}    <--- "use of closed network connection"  rised
        }

Salut les gars. J'ai recompilé le binaire kubernetes avec golang 1.14. Il semble que le problème ait disparu

@mYmNeo avez-vous déjà reproduit le problème après avoir recompilé avec go 1.14

Salut les gars. J'ai recompilé le binaire kubernetes avec golang 1.14. Il semble que le problème ait disparu

@mYmNeo avez-vous déjà reproduit le problème après avoir recompilé avec go 1.14

AFAIN, le problème n'existe plus.

Malheureusement, la mise à jour vers go1.14 nécessite des mises à jour de plusieurs composants clés, il est donc peu probable qu'elle soit ramenée à Kube 1.17. Vous pouvez suivre les problèmes et les progrès dans #88638

Savez-vous déjà si go1.14 sera rétroporté en 1.18 ?

Savez-vous déjà si go1.14 sera rétroporté en 1.18 ?

Je ne m'y attendrais pas. Les modifications apportées à etcd et bbolt semblent être nécessaires pour prendre en charge go1.14, ce qui est un changement plus important que celui généralement effectué dans les branches de publication.

@liggitt D'accord,

Ce problème se produit-il seulement après une panne de NIC ? Nous voyons le même message d'erreur dans nos clusters v1.16.8, mais il n'y a pas de panne de carte réseau associée.

Nous avons eu au moins une instance où la machine virtuelle sous-jacente avait une erreur SCSI lors de la connexion à un SAN. Le problème SCSI s'est résolu de lui-même, mais le kubelet n'a jamais récupéré.

L'option --goaway-chance été ajoutée en 1.18(#88567). Cette option résoudra-t-elle ce problème ?

Non. Cela n'a d'effet que si le kubelet est réellement capable d'atteindre le serveur API et d'obtenir une réponse.

un échec de liaison NIC (qui récupère peu de temps après), aura toutes ses connexions interrompues et n'essaiera pas de les rétablir à moins d'être redémarré manuellement.

pouvez-vous s'il vous plaît dire quel mode de liaison utilisez-vous? Je ne suis pas en mesure de reproduire cela sur mon cluster avec des liaisons de sauvegarde actives.

Après la mise à niveau vers Kubernetes 1.16, nous avons également commencé à voir l'erreur use of closed network connection et kubelet ne se reconnectant pas à l'apiserver, laissant les nœuds bloqués dans NotReady. Nous n'avons pas pu reproduire le problème en supprimant les cartes réseau (en définissant les liens vers le bas/vers le haut), mais nous avons remarqué que ce comportement ne se produisait que sur les clusters les plus chargés.

Nous avons fait plus de recherches et avons constaté que la valeur par défaut côté serveur valeur par défaut côté client est de 1000 , donc je suppose qu'une fois que kubelet a reçu une erreur de l'apiserver pour avoir atteint la limite de flux http2, il n'a jamais essayé de se reconnecter. Après avoir défini --http2-max-streams-per-connection=1000 nous n'avons pas vu le problème de blocage des nœuds dans NotReady autant qu'il l'avait initialement trouvé lors des tests. Cela n'a pas résolu le problème de la non reconnexion de kubelet, mais cela nous a aidés à atténuer le problème que nous voyions.

Après la mise à niveau vers Kubernetes 1.16, nous avons également commencé à voir l'erreur use of closed network connection et kubelet ne se reconnectant pas à l'apiserver, laissant les nœuds bloqués dans NotReady. Nous n'avons pas pu reproduire le problème en supprimant les cartes réseau (en définissant les liens vers le bas/vers le haut), mais nous avons remarqué que ce comportement ne se produisait que sur les clusters les plus chargés.

Nous avons fait plus de recherches et avons constaté que la valeur par défaut côté serveur valeur par défaut côté client est de 1000 , donc je suppose qu'une fois que kubelet a reçu une erreur de l'apiserver pour avoir atteint la limite de flux http2, il n'a jamais essayé de se reconnecter. Après avoir défini --http2-max-streams-per-connection=1000 nous n'avons pas vu le problème de blocage des nœuds dans NotReady autant qu'il l'avait initialement trouvé lors des tests. Cela n'a pas résolu le problème de la non reconnexion de kubelet, mais cela nous a aidés à atténuer le problème que nous voyions.

Salut, les flux https côté serveur par défaut sont 1000 dans kube-apiserver, c'est égal à la valeur du client.
https://github.com/kubernetes/kubernetes/blob/ae1103726f9aea1f9bbad1b215edfa47e0747dce/staging/src/k8s.io/apiserver/pkg/server/options/recommended.go#L62

@warmchang Je pense que cela s'applique aux apiextensions apiservers et à l'exemple d'apiserver :
https://github.com/kubernetes/kubernetes/blob/ae1103726f9aea1f9bbad1b215edfa47e0747dce/staging/src/k8s.io/apiserver/pkg/server/options/recommended.go#L62

Un test avec curl test sans définir --http2-max-streams-per-connection a ceci dans nos journaux apiserver (en utilisant la v1.16) :
I0603 10:18:08.038531 1 flags.go:33] FLAG: --http2-max-streams-per-connection="0"

Et une requête curl montre ceci dans la réponse :
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!

Lorsque j'utilise --http2-max-streams-per-connection=1000 la requête curl s'affiche alors
* Connection state changed (MAX_CONCURRENT_STREAMS == 1000)!

@jmcmeek @treytabner , tu as raison. J'ai mal lu le code. :+1:

En utilisant kubernetes 1.17.6 et idem ici. Il semble que kubelet utilise une connexion http2 morte.
J'ai remarqué que la valeur par défaut incohérente de MAX_CONCURRENT_STREAMS entre kube-apiserver et kubelet.

Il suffit de définir la valeur côté serveur sur 1000. Le rapportera plus tard.

Éleveur/RKE

Ajouter à la définition du cluster :

 kube-api:
      extra_args:
        http2-max-streams-per-connection: '1000'

Vérifiez sur le nœud maître :

docker exec -it kubelet bash
apt update && apt-get install -y nghttp2
nghttp -nsv https://127.0.0.1:6443
#Look for SETTINGS_MAX_CONCURRENT_STREAMS

La définition de MAX_CONCURRENT_STREAMS sur 1000 sur APIserver n'a aucun effet sur ce problème.
Je pensais que cela était dû à une faille dans golang http2 Transport . Voir au dessus

J'ai encore eu ce problème cette nuit.
On dirait que le réglage 'MAX_CONCURRENT_STREAMS' n'a pas aidé☹️

Salut les gars. Je pense avoir enfin cerné ce problème. Nous avons le même problème qui s'est produit hier soir. Mais récupéré avec succès avec un kubelet modifié.

Ce n'est pas un bug de Kubernetes, il s'agit du package standard net/http golang que client-go utilise également.
Je crois qu'il y a un défaut dans golang.org/x/net/http2/transport.go

J'ai déjà signalé cela au fonctionnaire de golang. En attente d'une discussion.
https://github.com/golang/go/issues/39750

Pour l'instant, j'ai modifié le code pour que le http2: perform connection health check introduit par https://github.com/golang/net/commit/0ba52f642ac2f9371a88bfdde41f4b4e195a37c0 soit activé par défaut.
Il s'avère être une aide sur ce problème. Mais une réponse un peu lente.

logs kubelet v1.17.6 (conformes au package golang.org/x/net auto-modifié)

Il a récupéré du problème d'écriture de connexions mortes, mais a coûté un peu plus de temps que prévu.

Notez que performing http2 healthCheck est un message de journal que j'avais l'intention de laisser là pour prouver que healthCheck func est appelé par readIdleTimer

 23 juin 03:14:45 vm10.company.com kubelet[22255]: E0623 03:14:45.912484 22255 kubelet_node_status.go:402] Erreur lors de la mise à jour de l'état du nœud, va réessayer : erreur lors de l'obtention du nœud "vm10.company.com": Get "https://vm10.company.com:8443/api/v1/nodes/vm10.company.com?timeout=10s" : écrivez tcp 16.155.199.4:39668->16.155.199.4:8443 : utilisation d'une connexion réseau fermée
 23 juin 03:14:45 vm10.company.com kubelet[22255]: E0623 03:14:45.912604 22255 kubelet_node_status.go:402] Erreur lors de la mise à jour de l'état du nœud, va réessayer : erreur lors de l'obtention du nœud "vm10.company.com": Get "https://vm10.company.com:8443/api/v1/nodes/vm10.company.com?timeout=10s" : écrivez tcp 16.155.199.4:39668->16.155.199.4:8443 : utilisation d'une connexion réseau fermée
 23 juin 03:14:45 vm10.company.com kubelet[22255]: E0623 03:14:45.912741 22255 kubelet_node_status.go:402] Erreur lors de la mise à jour de l'état du nœud, va réessayer : erreur lors de l'obtention du nœud "vm10.company.com": Get "https://vm10.company.com:8443/api/v1/nodes/vm10.company.com?timeout=10s": écrivez tcp 16.155.199.4:39668->16.155.199.4:8443: utilisation de la connexion réseau fermée
 23 juin 03:14:46 vm10.company.com kubelet[22255]: E0623 03:14:46.367046 22255 controller.go:135] n'a pas réussi à s'assurer que le bail de nœud existe, va réessayer dans 400ms, erreur : Get "https:// vm10.company.com:8443/apis/coordination.k8s.io/v1/namespaces/kube-node-lease/leases/vm10.company.com?timeout=10s": écrivez tcp 16.155.199.4:39668->16.155. 199.4:8443 : utilisation d'une connexion réseau fermée
 23 juin 03:14:48 vm10.company.com kubelet[22255]: E0623 03:14:47.737579 22255 controller.go:135] n'a pas réussi à s'assurer que le bail de nœud existe, va réessayer dans 800ms, erreur : Get "https:// vm10.company.com:8443/apis/coordination.k8s.io/v1/namespaces/kube-node-lease/leases/vm10.company.com?timeout=10s": écrivez tcp 16.155.199.4:39668->16.155. 199.4:8443 : utilisation d'une connexion réseau fermée
 23 juin 03:14:49 vm10.company.com kubelet[22255]: E0623 03:14:49.113920 22255 reflector.go:153] k8s.io/kubernetes/pkg/kubelet/kubelet.go:458: Échec de la liste * v1.Node : obtenez "https://vm10.company.com:8443/api/v1/nodes?fieldSelector=metadata.name%3Dvm10.company.com&limit=500&resourceVersion=0": écrivez tcp 16.155.199.4:39668-> 16.155.199.4:8443 : utilisation de la connexion réseau fermée
 23 juin 03:14:49 vm10.company.com kubelet[22255]: E0623 03:14:48.744770 22255 reflector.go:153] object-"kube-system"/"flannel-token-zvfwn": Échec de la liste * v1.Secret : obtenez "https://vm10.company.com:8443/api/v1/namespaces/kube-system/secrets?fieldSelector=metadata.name%3Dflannel-token-zvfwn&limit=500&resourceVersion=0": écrivez tcp 16.155 .199.4:39668->16.155.199.4:8443 : utilisation de la connexion réseau fermée
 23 juin 03:14:49 vm10.company.com kubelet[22255]: E0623 03:14:49.599631 22255 reflector.go:153] object-"kube-system"/"coredns": Échec de la liste *v1.ConfigMap : Obtenez "https://vm10.company.com:8443/api/v1/namespaces/kube-system/configmaps?fieldSelector=metadata.name%3Dcoredns&limit=500&resourceVersion=0": écrivez tcp 16.155.199.4:39668->16.155. 199.4:8443 : utilisation d'une connexion réseau fermée
 23 juin 03:14:49 vm10.company.com kubelet[22255]: E0623 03:14:49.599992 22255 controller.go:135] n'a pas réussi à s'assurer que le bail de nœud existe, va réessayer dans 1.6s, erreur: Get "https:/ /vm10.company.com:8443/apis/coordination.k8s.io/v1/namespaces/kube-node-lease/leases/vm10.company.com?timeout=10s": écrire tcp 16.155.199.4:39668->16.155 .199.4:8443 : utilisation d'une connexion réseau fermée
 23 juin 03:14:49 vm10.company.com kubelet[22255]: E0623 03:14:49.600182 22255 reflector.go:153] k8s.io/kubernetes/pkg/kubelet/kubelet.go:449: Échec de la liste * v1.Service : obtenez "https://vm10.company.com:8443/api/v1/services?limit=500&resourceVersion=0" : écrivez tcp 16.155.199.4:39668->16.155.199.4:8443 : utilisation du réseau fermé lien
 23 juin 03:14:49 vm10.company.com kubelet[22255]: E0623 03:14:49.600323 22255 reflector.go:153] object-"kube-system"/"kube-flanel-cfg": Échec de la liste * v1.ConfigMap : obtenez "https://vm10.company.com:8443/api/v1/namespaces/kube-system/configmaps?fieldSelector=metadata.name%3Dkube-flanel-cfg&limit=500&resourceVersion=0" : écrivez tcp 16.155 .199.4:39668->16.155.199.4:8443 : utilisation de la connexion réseau fermée
 23 juin 03:14:49 vm10.company.com kubelet[22255]: E0623 03:14:49.600463 22255 reflector.go:153] object-"core"/"registrypullsecret": Échec de la liste *v1.Secret: Get " https://vm10.company.com:8443/api/v1/namespaces/core/secrets?fieldSelector=metadata.name%3Dregistrypullsecret&limit=500&resourceVersion=0": écrire tcp 16.155.199.4:39668->16.155.199.4:8443 : utilisation d'une connexion réseau fermée
 23 juin 03:14:49 vm10.company.com kubelet[22255]: E0623 03:14:49.369097 22255 reflector.go:153] object-"kube-system"/"registrypullsecret" : Échec de la liste *v1.Secret : Obtenez "https://vm10.company.com:8443/api/v1/namespaces/kube-system/secrets?fieldSelector=metadata.name%3Dregistrypullsecret&limit=500&resourceVersion=0": écrivez tcp 16.155.199.4:39668->16.155. 199.4:8443 : utilisation d'une connexion réseau fermée
 23 juin 03:25:39 vm10.company.com kubelet[22255]: E0623 03:25:39.543880 22255 desire_state_of_world_populator.go:320] Erreur lors du traitement du volume "deployment-log-dir" pour le pod "fluentd-h76lr_core(e95c9200-3a0c) -4fea-bd7f-99ac1cc6ae7a)" : erreur de traitement du noyau PVC/itom-vol-claim : échec de la récupération du PVC à partir du serveur API : obtenez "https://vm10.company.com:8443/api/v1/namespaces/core/ persistentvolumeclaims/itom-vol-claim": read tcp 16.155.199.4:41512->16.155.199.4:8443: utilisation d'une connexion réseau fermée
 23 juin 03:25:39 vm10.company.com kubelet[22255]: E0623 03:25:39.666303 22255 kubelet_node_status.go:402] Erreur lors de la mise à jour de l'état du nœud, va réessayer : échec de la correction de l'état "{\"status\": {\"$setElementOrder/conditions\":[{\"type\":\"MemoryPressure\"},{\"type\":\"DiskPressure\"},{\"type\":\"PIDPressure\ "},{\"type\":\"Prêt\"}],\"conditions\":[{\"lastHeartbeatTime\":\"2020-06-22T19:25:29Z\",\"type\ ":\"MemoryPressure\"},{\"lastHeartbeatTime\":\"2020-06-22T19:25:29Z\",\"type\":\"DiskPressure\"},{\"lastHeartbeatTime\": \"2020-06-22T19:25:29Z\",\"type\":\"PIDPressure\"},{\"lastHeartbeatTime\":\"2020-06-22T19:25:29Z\",\" type\":\"Prêt\"}]}}" pour le nœud "vm10.company.com": Patch "https://vm10.company.com:8443/api/v1/nodes/vm10.company.com/ status?timeout=10s": read tcp 16.155.199.4:41512->16.155.199.4:8443: utilisation de la connexion réseau fermée
 23 juin 03:25:49 vm10.company.com kubelet[22255]: E0623 03:25:49.553078 22255 kubelet_node_status.go:402] Erreur lors de la mise à jour de l'état du nœud, va réessayer : erreur lors de l'obtention du nœud "vm10.company.com": Get "https://vm10.company.com:8443/api/v1/nodes/vm10.company.com?timeout=10s" : lire tcp 16.155.199.4:41718->16.155.199.4:8443 : utilisation de la connexion réseau fermée
 23 juin 03:25:49 vm10.company.com kubelet[22255]: E0623 03:25:49.560723 22255 desire_state_of_world_populator.go:320] Erreur de traitement du volume "log-location" pour le pod "fluentd-h76lr_core(e95c9200-3a0c-4fea) -bd7f-99ac1cc6ae7a)" : erreur de traitement du noyau PVC/itom-logging-vol : échec de la récupération du PVC à partir du serveur API : obtenez "https://vm10.company.com:8443/api/v1/namespaces/core/persistentvolumeclaims/ itom-logging-vol": read tcp 16.155.199.4:41718->16.155.199.4:8443: utilisation de la connexion réseau fermée
 23 juin 03:27:29 vm10.company.com kubelet[22255]: I0623 03:27:29.961600 22255 log.go:181] effectuant http2 healthCheck
 23 juin 03:31:32 vm10.company.com kubelet[22255]: I0623 03:31:31.829860 22255 log.go:181] effectuant http2 healthCheck
 23 juin 03:31:44 vm10.company.com kubelet[22255]: I0623 03:31:44.570224 22255 log.go:181] effectuant http2 healthCheck
 23 juin 03:32:13 vm10.company.com kubelet[22255]: I0623 03:32:12.961728 22255 log.go:181] effectuant http2 healthCheck
 23 juin 03:33:16 vm10.company.com kubelet[22255]: I0623 03:33:15.441808 22255 log.go:181] effectuant http2 healthCheck
 23 juin 03:33:28 vm10.company.com kubelet[22255]: I0623 03:33:28.233121 22255 log.go:181] effectuant http2 healthCheck

plus de use of closed network connection signalé et kubelet revient à l'état Prêt

Nous avons obtenu de nouvelles informations potentielles sur le problème dans nos piles. Avec une certaine confiance, nous supposons une baisse de connexion rare au niveau du réseau/de l'infrastructure en raison d'une charge élevée par rapport aux numéros de connexion dans des situations spécifiques, donc dans notre cas, il ne s'agissait pas d'un basculement des interfaces réseau. Nous avons particulièrement eu de gros problèmes avec la fédération Prometheus à cause de cela depuis qu'ils sont passés à http2 côté client . L'activation du moniteur de santé http2 en définissant http2.Transport.ReadIdleTimeout comme implémenté avec golang/net#55 entièrement résolu les problèmes de fédération pour nous.

Les valeurs ne sont actuellement pas exposées car apimachinery/pkg/util/net/http.go instancie http.Transport et le met à niveau vers http2 en interne, ce qui n'expose pas l'option tant que golang/net#74 n'est pas fusionné.

Existe-t-il d'autres solutions de contournement que la tâche cron de redémarrage de kubelet ? Nous avons une tâche cron en place depuis une semaine et cela n'a pas empêché le problème de se produire.

J'ai le même problème dans la v1.17.3.

Ce que j'ai trouvé, c'est que la version k8s utilisant une version spécifique de golang.org/x/net est en difficulté, et ce paquet semble être corrigé.
https://go-review.googlesource.com/c/net/+/198040

Version avec ce problème (v1.16.5 ~ dernière version)
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9

Correction de la version (branche principale)
golang.org/x/net v0.0.0-20200707034311-ab3426394381

La mise golang.org/x/net jour du package

Existe-t-il une version prévue pour la version k8s maintenue (v1,16, 1.17, v1,18..) pour résoudre ce problème ?

Ce que j'ai trouvé, c'est que la version k8s utilisant une version spécifique de golang.org/x/net est en difficulté, et ce paquet semble être corrigé.
https://go-review.googlesource.com/c/net/+/198040

Le changement mentionné uniquement _offre_ la possibilité d'activer le moniteur de santé HTTP2, mais il doit être activé par les développeurs (la valeur par défaut est désactivée). De plus, il ne peut pas être vraiment défini, mais il existe une demande d'extraction pour donner aux développeurs l'accès au moniteur de santé .

J'intègre actuellement un correctif basé sur la réflexion qui active le moniteur de santé pour notre propre distribution Kubernetes, dans l'espoir que cela aide à résoudre le problème.

--
Jens Erat \ Imprimer

@JensErat merci pour la réponse.
Si tel est le cas, ce problème peut-il également se produire dans les anciennes versions de k8s (1.13, 1.15, ..) ?

J'ai changé la distribution de nœuds de RancherOS (noyau 4.14.138) à Ubuntu 18.04 (noyau 5.3.0) il y a plus d'un mois, le problème n'est pas apparu depuis lors.
L'un de mes clusters est resté sur RancherOS, ce problème s'est déjà reproduit 3 fois.

Pas sûr à 100%, mais la version du noyau compte probablement.

Dur à dire. Nous avons certainement observé (d) le problème avec les versions 1.16 à 1.18, mais nous avons rencontré de rares "occurrences bloquées de kubelet" auparavant. Nous avons déjà creusé ces problèmes depuis au moins un an, mais nous n'avons jamais rien pu corréler (incidents uniques toutes les quelques semaines, et nous avons un nombre à quatre chiffres de kubelets en cours d'exécution). C'est devenu bien pire depuis que nous avons installé la version 1.16, mais actuellement, nous préférons supposer que les problèmes de réseau sous-jacents (également très rares et difficiles à retracer...) se produisent plus souvent. Nous utilisons Ubuntu 19.10 avec Kernel 5.3.0-46-generic mais sommes affectés (il est donc possible que vous ayez en fait un niveau de correctif plus récent). Pouvez-vous donner un indice sur la version exacte du noyau/le niveau de correctif que vous utilisez ?

--
Jens Erat \ Imprimer

C'est 5.3.0-59-generic . Mais nous n'avons qu'environ 40 kubletes, donc cela pourrait encore être une coïncidence.

Comme je l'ai dit plus haut. Ce problème se produit plus fréquemment sur les clusters fortement chargés. Nous avons observé le même problème presque toutes les nuits avant d'activer h2 transport healthCheck.
Selon le problème signalé au responsable du golang . Le problème se produit dans la boucle de lecture du socket, qui devrait renvoyer une erreur lors de la lecture du socket fermé, mais ce n'est jamais le cas. En outre, je suggère d'ajouter une logique de gestion d'erreur lors de l'écriture du socket pour détecter activement le problème de connexion. Mais plusieurs jours plus tard, il semble qu'ils ne se soucient pas de ces problèmes rares.

Un peu loin du sujet, je veux dire, puisque le problème est causé par le socket réseau qui est très proche du noyau. La mise à jour du noyau peut aider, ou non. (PS: nous utilisons centos 7 avec le noyau 3.10, cela arrive presque tous les jours avant d'activer healthCheck)
J'ai passé environ 3 jours à lire le code source de net/http, d'après ce que j'ai vu, permettant à h2 transport healthCheck devrait aider à récupérer d'un tel problème, et nous avons vraiment échappé à cette situation étrange en le faisant.
@JensErat Avez-vous des preuves concrètes que l'activation de HealthCheck aide à résoudre ce problème ?

@JensErat Avez-vous des preuves concrètes que l'activation de HealthCheck aide à résoudre ce problème ?

Nous exécutons la fédération Prometheus pour chacun de nos clusters Kubernetes. Prometheus 2.19.0 a introduit http2 (ils oublient de le mentionner dans le journal des modifications et l'ont bien caché dans un corps de message de validation, j'ai dû git bisecter, déployer et attendre quelques heures pour chaque exécution...) et nous avons observé environ une dizaine d'incidents avec fédération bloquée par jour. J'ai d'abord corrigé le support http2 (et le problème a disparu), puis j'ai défini le délai de lecture directement dans golang/net/x/http2. Depuis lors, nous n'avons plus eu un seul incident de panne de fédération.

Je me prépare actuellement à déployer une version corrigée de Kubernetes sur certains clusters, nous devrions donc avoir des données dans quelques jours. Nous partagerons certainement nos résultats dès que nous aurons des données appropriées.

--
Jens Erat \ Imprimer

Je me prépare actuellement à déployer une version corrigée de Kubernetes sur certains clusters, nous devrions donc avoir des données dans quelques jours. Nous partagerons certainement nos résultats dès que nous aurons des données appropriées.

Merci pour vos commentaires. C'est un message très agréable.
Bien que la cause première ne soit pas très claire, nous trouvons au moins un moyen de récupérer après un sinistre. :RÉ

Nous avons le même problème avec k8s v1.14.3, et redémarrer kubelet peut résoudre le problème.

Je sais que c'est idiot, mais cela doit fonctionner comme une solution de contournement temporaire :

Développer yaml

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: kubelet-face-slapper
  namespace: kube-system
spec:
  selector:
    matchLabels:
      app: kubelet-face-slapper
  template:
    metadata:
      labels:
        app: kubelet-face-slapper
    spec:
      # this toleration is to have the daemonset runnable on master nodes
      # remove it if your masters can't run pods    
      tolerations:
      - effect: NoSchedule
        key: node-role.kubernetes.io/controlplane
        operator: Equal
        value: "true"
      - effect: NoExecute
        key: node-role.kubernetes.io/etcd
        operator: Equal
        value: "true"
      containers:
      - command:
        - /bin/sh
        - -c
        - while true; do sleep 40; docker logs kubelet --since 1m 2>&1 | grep -q "use
          of closed network connection" && (docker restart kubelet ; echo "kubelet
          has been restarted due to connection error") || echo "kubelet connection
          is ok" ;done
        image: docker:stable
        name: kubelet-face-slapper
        volumeMounts:
        - mountPath: /var/run/docker.sock
          name: docker-sock
      volumes:
      - hostPath:
          path: /var/run/docker.sock
          type: File
        name: docker-sock


(Ceci est spécifique au rancher, mais peut être facilement adapté à d'autres distributions en utilisant un conteneur privilégié et journalctl/systemctl)

Le temps pour sleep et --since doit être inférieur au pod-eviction-timeout du cluster (5m par défaut)

BTW - docker pause nginx-proxy sur le nœud de travail de rancher fait que kubelet produit le même message d'erreur.

Contournement temporaire pour ceux qui exécutent K8S sur VMWare vSphere - désactivez le DRS pour les machines virtuelles K8S, cela empêchera vSphere de déplacer les machines virtuelles entre les hyperviseurs, éliminant ainsi toute déconnexion réseau qui cause des problèmes aux Kubelets

Nous avons de très bonnes nouvelles concernant l'atténuation du problème à l'aide de la nouvelle fonctionnalité de vérification de l'état http2 de golang : plus aucun problème. À ce jour, nous avons implémenté le "correctif" (réglage codé en dur de la valeur dans le code x/net ) dans Prometheus, l'ensemble de Kubernetes et plusieurs composants internes, en observant :

  • plus de problème avec la fédération Prometheus
  • kubelet signale parfois encore des événements uniques d'"utilisation d'une connexion fermée" mais récupère en quelques secondes (nous définissons une fenêtre de vérification de l'état http2 d'environ 30 secondes)
  • parfois nous avons eu des problèmes avec les montres kubectl - également disparu si vous utilisiez kubectl patché
  • nous exécutons une suite de tests E2E étendue pour vérifier notre intégration régulièrement et avons observé des délais d'attente et des flocons de test sporadiques. Devinez quoi? Parti maintenant.

De plus, nous avons pu obtenir de nouvelles informations sur la façon de déclencher les problèmes. Je peux confirmer l' observation de @vi7 concernant la migration en direct avec une certaine confiance (nous pourrions cependant la retracer), et au moins avec la version NSX que nous utilisons, les modifications de l'équilibreur de charge peuvent également déclencher de tels problèmes (nous avons un ticket avec VMware pour assurez-vous qu'ils envoient des paquets de réinitialisation à l'avenir). Et très probablement de nombreuses autres raisons pour lesquelles les connexions sont interrompues, comme les débordements de la table de connexion.

C'est un problème très ennuyeux et quelque peu massif pour certains utilisateurs de Kubernetes (en fonction d'une sorte de "rupture" de la couche/du réseau IaaS, je suppose). Bien qu'il y ait des discussions de golang sur l'exposition d'une interface pour définir correctement les valeurs - pensez-vous qu'il y a une chance d'obtenir un PR fusionné en amont définissant ces valeurs par réflexion (encore mieux que de forker x/net je suppose comme nous le faisons en ce moment) ? Nous pouvons fournir le code (et valider le correctif, nous ne pouvons pas réellement le reproduire, mais l'observons assez souvent pour pouvoir confirmer si le correctif fonctionne).

cc @liggitt

problème à long terme (note à moi-même)

@JensErat merci pour la réponse.
Si tel est le cas, ce problème peut-il également se produire dans les anciennes versions de k8s (1.13, 1.15, ..) ?

Je peux confirmer pour voir le problème avec Kubernetes v1.16.13
Nous n'avons pas vu le problème avec Kubernetes v1.15.9

quand je restroe un cluster kubenetes v1.16.14 partir de la sauvegarde d'instantané etcd. cette erreur apparaît dans le journal kubelet.
merci à @ik9999 . Je redémarre le kubelet puis les erreurs disparaissent

[root@dev-k8s-master ~]# journalctl -u kubelet -n 1 | grep "use of closed network connection"
Aug 22 11:31:10 dev-k8s-master kubelet[95075]: E0822 11:31:10.565237   95075 reflector.go:123] k8s.io/client-go/informers/factory.go:134: Failed to list *v1beta1.CSIDriver: Get https://apiserver.cluster.local:6443/apis/storage.k8s.io/v1beta1/csidrivers?limit=500&resourceVersion=0: write tcp 192.168.160.243:58374->192.168.160.243:6443: use of closed network connection
[root@dev-k8s-master ~]# systemctl restart kubelet
[root@dev-k8s-master ssh]# journalctl -u kubelet -n 1 | grep "use of closed network connection"

Nous avons rencontré le même problème sur 1.17.3, le redémarrage de kubelet devrait le résoudre. Une solution de contournement stable pour cela ou quand cela sera-t-il corrigé?

v1.18.6 même

@rxwang662001
Ceci est causé par un problème de golang en amont. Une chose est sûre, c'est que cela ne sera PAS corrigé dans la version 1.15.
Pendant ce temps, la communauté Kubernetes a toujours du mal à migrer pour passer à 1.14 LOL.

En règle générale, allez aux versions tous les 6 mois. Si tout fonctionne bien, nous pourrions peut-être voir ce problème résolu en amont l'année prochaine, et peut-être une autre année jusqu'à ce que kubernetes adapte le correctif 🥇 !
(Juste pour plaisanter. Si vous voulez vraiment que cela soit corrigé dans votre pile en ce moment. Piratez le h2Transport pour activer healthCheck s'est avéré fonctionner.

Pendant ce temps, la communauté Kubernetes a toujours du mal à migrer pour passer à 1.14 LOL.

En fait, en raison de l'excellent travail réalisé par sig-scalability et sig-release pour se qualifier sur les pré-versions de go1.15, Kubernetes 1.19 vient de sortir sur go1.15. Il semble que des travaux soient en cours pour exposer les options http/2 dans go1.16, et je pense que nous les utiliserons dès qu'elles seront disponibles.

En fait, en raison de l'excellent travail réalisé par sig-scalability et sig-release pour se qualifier sur les pré-versions de go1.15, Kubernetes 1.19 vient de sortir sur go1.15.

Ops. Désolé pour la blague maladroite. Je n'ai pas prêté beaucoup d'attention à la version v1.19.
Il semble que nous ayons entièrement ignoré go1.14 sur K8S ? Wow. c'est un grand saut

@povsister

Merci d'avoir partagé votre solution. Pourriez-vous ajouter plus de détails sur la façon dont vous l'avez fait fonctionner?

Pour l'instant, j'ai modifié le code pour que le http2: perform connection health check introduit par golang/ net@0ba52f6 soit activé par défaut.
Il s'avère être une aide sur ce problème. Mais une réponse un peu lente.

Quels changements de code avez-vous mis en place ? Et où, dans quel fichier ?

@KarthikRangaraju
Référez - vous à
ou vous pouvez faire un hack de réflexion/offset dangereux pour accéder au champ non exporté au moment de l'exécution.

Et n'oubliez pas de mettre à jour golang/x/net avant de faire ce genre de choses.

Nous n'avons pas été en mesure de reproduire ce problème bien que nous y soyons confrontés de temps en temps.

Étant donné que nous ne sommes pas en mesure d'identifier la cause première du symptôme, nous corrigeons le symptôme malgré tout.

Notre solution :

  • Le script suivant s'exécute toutes les 1 heure. Il parle au serveur kube-api via kubectl via le fichier de configuration kube
    kubelet utilise (de cette façon, il n'y a pas d'élévation de privilèges).
  • Demande si le nœud maître thinks son propre nœud est NotReady. Si oui, déclenche un redémarrage de kubelet en exécutant la commande touch sur un fichier
    c'est watched par un kubelet-watcher.service pour les modifications du système de fichiers et redémarre kubelet en conséquence.
#!/bin/bash

while true; do
  node_status=$(KUBECONFIG=/etc/kubernetes/kubelet.conf kubectl get nodes | grep $HOSTNAME | awk '{print $2}')
  date=$(date)
  echo "${date} Node status for ${HOSTNAME}: ${node_status}"
  if [ ${node_status} == "NotReady" ]; then
    echo "${date} Triggering kubelet restart ..."
    # Running touch command on /var/lib/kubelet/config.yaml. This will trigger a kubelet restart.
    # /usr/lib/systemd/system/kubelet-watcher.path & /usr/lib/systemd/system/kubelet-watcher.service
    # are responsible for watching changes in this file
    # and will restart the kubelet process managed by systemd accordingly.
    touch /var/lib/kubelet/config.yaml
  fi

  # Runs ever 1 hour
  sleep 3600
done
# cat  /usr/lib/systemd/system/kubelet-watcher.path
[Path]
PathModified=/var/lib/kubelet/config.yaml

[Install]
WantedBy=multi-user.target

# cat /usr/lib/systemd/system/kubelet-watcher.service
[Unit]
Description=kubelet restarter

[Service]
Type=oneshot
ExecStart=/usr/bin/systemctl restart kubelet.service

[Install]
WantedBy=multi-user.target[root@den-iac-opstest-kube-node02 karthik]#

Avec Kubernetes 1.19.0, le problème existe toujours, mais le message est légèrement différent.
Sep 11 18:19:39 k8s-node3 kubelet[17382]: E0911 18:19:38.745482 17382 event.go:273] Unable to write event: 'Patch "https://192.168.1.150:6443/api/v1/namespaces/fhem/events/fhem-7c99f5f947-z48zk.1633c689ec861314": read tcp 192.168.1.153:34758->192.168.1.150:6443: use of closed network connection' (may retry after sleeping)
Il contient maintenant un "(peut réessayer après avoir dormi)" dans le message d'erreur.

Est-il possible d'atténuer cela entièrement dans kubernetes sans attendre un golang de mise à niveau ? Par exemple, peut-on demander à client-go d'échanger le transport s'il rencontre une "utilisation d'une connexion réseau fermée" ou quelque chose du genre ?

Sinon, ce problème se produira-t-il toujours si vous utilisez HTTP 1.1, ou est-ce purement lié à HTTP 2 ? Si HTTP 1.1 était immunisé et n'avait pas d'énormes inconvénients, ce serait une solution de contournement très simple de simplement définir GODEBUG=http2client=0 sur kubelet, kube-proxy et divers processus du plan de contrôle, ou même définir GODEBUG=http2server=0 sur le processus apiserver pour rendre le changement universel.

Pensons-nous que cela atténuerait réellement ce problème et ne causerait pas d'autres pièges majeurs autres que certains problèmes de performances dus à l'augmentation du nombre de connexions lorsqu'il n'y a pas de multiplexage sur HTTP2 ?

client-go peut-il être obligé d'échanger le transport s'il rencontre une "utilisation d'une connexion réseau fermée" ou quelque chose du genre ?

pas très chirurgicalement... les transports sont actuellement mutualisés afin d'éviter l'épuisement éphémère des ports face aux appelants qui construisent à plusieurs reprises de nouveaux clients

ce problème se produira-t-il toujours si vous utilisez HTTP 1.1, ou est-ce purement lié à HTTP 2 ?

pour autant que je sache, HTTP 1.1 peut rencontrer le même problème car les connexions inactives retournent dans un pool keep-alive (et ont moins d'options pour le détecter / l'atténuer car le mécanisme de vérification de l'état de ping n'est pas disponible)

Existe-t-il une bonne solution de contournement pour les projets qui utilisent le client ? Comment pouvons-nous identifier quand le client est mort et quel est le minimum que nous devons faire pour le réparer (on dirait que redémarrer notre processus pourrait être la seule option) ?

Comment pouvons-nous identifier quand le client est mort

Lorsque vous avez à plusieurs reprises write tcp xxx use of closed network connection erreur host:port demandé.

Existe-t-il une bonne solution de contournement pour les projets qui utilisent le client ?

Pour autant que je sache, reconstruire un http.Client peut résoudre ce problème sans redémarrer l'ensemble de l'application.

quel est le minimum que nous devons faire pour le réparer

Il nécessite un accès au niveau du code source au projet. Vous pouvez peut-être utiliser le mécanisme mentionné ci-dessus pour détecter le client mort et reconstruire un nouveau client si nécessaire. Si personne n'utilise l'ancien client, il sera ramassé.

J'ai accès au code source de mon projet, mais nous utilisons le client kubernetes. Lorsque nous faisons des veilles, il semble qu'il ne détecte jamais si la connexion TCP est coupée comme ça (et puisque la montre gère les transactions HTTP, aucune erreur n'apparaît dans notre code à gérer).

Oui. vous avez raison, le http.Client n'est pas exposé par le client kubernetes.
Actuellement, il est impossible pour une application de haut niveau de faire une telle solution à peu de frais.
Si le client kubernetes n'utilise pas http.DefaultClient , cela peut être corrigé en reconstruisant l'ensemble du client kubernetes.

Pour la demande de montre, c'est de pire en pire. Le client kubernetes semble continuer à réessayer la demande et aucune erreur n'est signalée à l'application supérieure. Je n'ai aucune bonne idée sur une telle situation maintenant.

La solution de contournement proposée ici fonctionne pour nous depuis plusieurs semaines. Nous l'avons transformé en un script python qui s'exécute comme un démon dans tous nos clusters. Nous le voyons généralement agir une à deux fois par semaine (redémarrer automatiquement kubelet) et nous n'avons donc eu aucun impact négatif sur le fonctionnement de notre cluster. Nous l'avons rendu variable afin qu'il ne redémarre kubelet que s'il voit plus de 2 messages sur une période de 5 minutes. Nous avons vu que parfois nous pouvions voir un message, et ce n'était pas un problème. Lorsque le problème se produit, vous verrez l'erreur use of closed network connection constamment dans les journaux de kubelet.

Veuillez créer une pullrequest et nous étudierons ce sujet.

Sur un seul cluster baremetal, je vois cela se produire environ 2 à 4 fois toutes les 24 heures. 1.17.12

cela se produit lorsque le pod du serveur api redémarre, même sur un seul cluster de nœuds. Les connexions à l'apiserver ont été perdues, donc la méthode de minimisation du nombre d'erreurs résout le problème du redémarrage d'apiserver.

J'utilise haproxy devant le nœud maître, pensez-vous qu'il existe de toute façon pour empêcher cela avec une configuration LB ?

@shubb30, ça vous dérange de partager avec moi votre solution ?

Je peux confirmer que mes apiservers ne redémarrent

Voici une version modifiée de ce qui a bien fonctionné pour nous comme solution de contournement.

Hey tout le monde!

Pensons-nous potentiellement que ce rétroportage pourrait aider ?
https://github.com/golang/go/issues/40423

Bonne nouvelle : golang/net master prend en charge la configuration des transports http2, ce qui permet désormais de régler les timeouts ! https://github.com/golang/net/commit/08b38378de702b893ee869b94b32f833e2933bd2

Terminé.
PR ouvert pour examen.

Autre bonne nouvelle : Kubernetes n'utilise pas le package http2 fourni dans le package net/http standard, nous n'avons donc pas besoin d'attendre la prochaine version de Go. Nous pouvons directement utiliser https://github.com/golang/net/commit/08b38378de702b893ee869b94b32f833e2933bd2 pour résoudre ce problème.

A proposé un correctif ici. https://github.com/kubernetes/kubernetes/pull/95898
Il met à jour la dépendance vers la version requise et active la vérification de l'état du transport http2 par défaut.
Cela devrait aider les applications qui utilisent client-go pour communiquer avec apiserver (par exemple: kubelet) à se débarrasser du problème "app hang at write tcp xxx: use of closed connection".

N'hésitez pas à laisser des commentaires.

Il semble que le n° 95898 mentionné ait été fermé pour des raisons dont nous n'avons pas besoin de discuter.

Y a-t-il une autre mise à jour concernant ce problème?

https://github.com/kubernetes/kubernetes/pull/95981 (lien ci-dessus) est en cours pour extraire le correctif http/2

Ce problème est-il spécifique aux versions 1.17.X de kubernetes ?

@kmayankk Pas tout à fait sûr quand cela a commencé exactement. Mais au moins 1.17-1.19 ont ce problème. #95980 aurait dû le corriger (fait partie de la prochaine version 1.20, n'est pas entré dans la version bêta hier)

@krmayankk Nous avons également vu ce problème avec la v1.18.9, mais il a été déclenché par une version boguée de Rancher qui a entraîné une utilisation très élevée du réseau. Après le retour à une autre version, aucun problème n'a été observé.

J'ai eu ce problème mais je l'ai maintenant "réparé" dans mon petit cluster de passe-temps en utilisant la solution de contournement dans un commentaire ci-dessus

J'ai écrit un petit livre de jeu ansible pour déployer la solution de contournement sur les nœuds en tant qu'unité systemd et minuterie, cela pourrait en sauver d'autres avec une configuration similaire un certain temps

Existe-t-il un plan pour cherry-pick/backport https://github.com/kubernetes/kubernetes/pull/95981 et https://github.com/kubernetes/kubernetes/issues/87615 vers la version 1.18 ?

Existe-t-il un plan pour sélectionner la branche de version #95981 à 1.17 ?

Ce commentaire traite des rétroportages vers les anciennes versions : https://github.com/kubernetes/kubernetes/pull/95981#issuecomment -730561539

Je pense que la réponse est "c'est dur et ça pourrait casser des choses donc probablement pas". Un peu la même réponse que j'attendrais de la part des personnes exécutant la version 1.17, alors pourquoi ne pas passer à la version 1.20 pour obtenir le correctif ? :en riant:

Le rétroporter à au moins 1.19 serait formidable car cela rendra le correctif disponible assez rapidement. Je soupçonne que certaines personnes retiendront la version 1.20 en raison de la dépréciation de Docker.

Le rétroporter à au moins 1.19 serait formidable car cela rendra le correctif disponible assez rapidement.

Cela a déjà été fait.

Je soupçonne que certaines personnes retiendront la version 1.20 en raison de la dépréciation de Docker.

Rien n'a changé dans 1.20 en ce qui concerne docker autre qu'un avertissement de dépréciation. À la fin de la période de dépréciation, la prise en charge de dockershim sera supprimée.

obtenir ces erreurs sur 1.20 sur un raspbian 10. où commence-t-on même par obtenir un correctif pour tout cela? il semble que le coût d'exécution d'un cluster géré dans le cloud soit bien plus rentable que d'essayer de l'exécuter sur votre propre cluster

Pour ma propre clarté, il semble que cela devrait être résolu par # 95981, et cela a été transformé en 1.20 et a été rétroporté en 1.19 ?

95981 a été fusionné à 1,20 et a été sélectionné à 1,19 dans # 96770.

/proche

@caesarxuchao : Clôture de ce problème.

En réponse à cela :

95981 a été fusionné à 1,20 et a été sélectionné à 1,19 dans # 96770.

/proche

Les instructions pour interagir avec moi à l'aide des commentaires de relations publiques sont disponibles ici . Si vous avez des questions ou des suggestions concernant mon comportement, veuillez signaler un problème dans le

Y aura-t-il un backport/cherry pick pour v1.16, v1.17 ou v1.18 ?

@chilicat voir https://github.com/kubernetes/kubernetes/pull/95981#issuecomment -730561539. Je n'ai pas l'intention de choisir une version 1.18 ou antérieure.

Cette page vous a été utile?
0 / 5 - 0 notes