Kubernetes: (1.17) Kubelet verbindet sich nach einem NIC-Fehler nicht wieder mit dem Apiserver (Verwendung einer geschlossenen Netzwerkverbindung)

Erstellt am 28. Jan. 2020  ·  123Kommentare  ·  Quelle: kubernetes/kubernetes

Wir haben gerade unseren Produktionscluster auf 1.17.2 aktualisiert.

Seit dem Update am Samstag hatten wir diesen seltsamen Ausfall: Kubelet wird nach einem NIC-Bond-Fehler (der sich nicht lange danach erholt) alle Verbindungen unterbrochen und versucht nicht erneut, sie wiederherzustellen, es sei denn, es wird manuell neu gestartet.

Hier ist die Zeitleiste des letzten Auftretens:

01:31:16: Kernel erkennt einen Fehler auf der Bond-Schnittstelle. Es geht eine Weile. Schließlich erholt es sich.

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

Wie erwartet sind alle Uhren geschlossen. Die Botschaft ist für alle gleich:

...
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
...

Diese Nachrichten beginnen also:

`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`

Was meiner Meinung nach für eine Weile kein Problem sein sollte. Aber es erholt sich nie. Unser Event fand um 01:31 Uhr statt und musste Kubelet gegen 9 Uhr manuell neu starten, um die Dinge zu normalisieren.

# 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

Apiserver waren in Betrieb, alle anderen Knoten waren in Betrieb, alles andere war ziemlich ereignislos. Dieser war (heute) der einzige, der von diesem Problem betroffen war.

Gibt es eine Möglichkeit, solche Ereignisse zu mildern?

Wäre dies ein Fehler?

kinsupport siapi-machinery sinode

Hilfreichster Kommentar

Ich habe es behoben, indem ich dieses Bash-Skript alle 5 Minuten ausgeführt habe:

#!/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

Alle 123 Kommentare

/sig-Knoten
/sig-API-Maschinen

Bei einem Blick in den Code tritt der Fehler hier auf

Die Erklärung des Codes ist, dass er wahrscheinlich seinen EOF (IsProbableEOF) annimmt, während dies in diesem Fall nicht der Fall zu sein scheint.

/ assign @caesarxuchao

@rikatz können Sie erläutern, wie Sie den eingefügten Code gefunden haben?

Mein Gedanke ist, dass der Reflektor die Uhr neu gestartet hätte, egal wie er mit dem Fehler ( Code )

Genau @caesarxuchao , das ist also unsere Frage.

Ich habe den Fehler verfolgt, indem ich ihn im Grunde durch den Code gegriffen und mit dem gekreuzt habe, was Kubelet zu dieser Zeit getan hat (Geheimnisse beobachtet), um in diesen Teil zu gelangen.

Kein fortgeschrittener Weg, durch dies scheint der genaue Punkt des Fehlercodes zu sein.

Die Frage ist, weil die Verbindung geschlossen ist, gibt es irgendwo einen Hinweis darauf, dass dies der EOF der Uhr ist, anstatt zu verstehen, dass dies ein Fehler ist?

Ich habe nichts Klügeres hinzuzufügen, als dass ein weiterer Knoten auf die gleiche Weise ausgefallen ist und die Vorkommen von den letzten 4 Tagen auf 4 erhöht wurden.

Wird versuchen zu kartieren, wenn Bonddisconnect-Ereignisse auf anderen Knoten auftreten und wenn Kubelet sich erholt - es könnte bei einigen Wiederherstellungen Pech haben und kein 100%-Ereignis.

Ich denke, wir sehen dies auch, aber wir haben keine Bindungen, wir sehen nur diese vernetzten "Träger verloren"-Nachrichten für Calico cali* Schnittstellen, und es handelt sich um lokale Vet-Geräte.

Ich habe dies auch ohne Bindungen erlebt. Ein Neustart des Knotens behebt das Problem, ein einfacher Neustart des Kubelet-Dienstes jedoch nicht (alle API-Aufrufe schlagen mit "Unauthorized" fehl).

Ich habe dies auch ohne Bindungen erlebt. Ein Neustart des Knotens behebt das Problem, ein einfacher Neustart des Kubelet-Dienstes jedoch nicht (alle API-Aufrufe schlagen mit "Unauthorized" fehl).

Update: Der Neustart von Kubelet hat das Problem behoben, nachdem genügend Zeit (1 Stunde?) verstrichen war.

Ich sehe das gleiche Verhalten. Ubuntu 18.04.3 LTS saubere Installationen. Cluster erstellt mit Rancher 2.3.4. Ich habe gesehen, dass dies in letzter Zeit regelmäßig passiert, und ein Neustart von Kubelet neigt dazu, es für mich zu beheben. Letzte Nacht zeigten alle 3 meiner Worker-Knoten dasselbe Verhalten. Ich habe 2 korrigiert, um meinen Cluster nach oben zu bringen. Third ist immer noch in diesem Zustand, während ich herum grabe.

Wir sehen das gleiche Problem auf CentOS 7, Cluster neu erstellt mit Rancher (1.17.2). Wir verwenden Gewebe. Alle 3 Worker-Knoten zeigen dieses Problem. Der Neustart von Kubelet funktioniert bei uns nicht, wir müssen den gesamten Knoten neu starten

/sig-Knoten
/sig-API-Maschinen

Bei einem Blick in den Code tritt der Fehler hier auf

Die Erklärung des Codes ist, dass er wahrscheinlich seinen EOF (IsProbableEOF) annimmt, während dies in diesem Fall nicht der Fall zu sein scheint.

Wir sehen auch das gleiche Problem. Aus dem Protokoll haben wir herausgefunden, dass nach Auftreten des Problems alle nachfolgenden Anfragen immer noch über dieselbe Verbindung gesendet wurden. Es scheint, dass der Client die Anfrage zwar erneut an apiserver sendet, aber die zugrunde liegende http2-Bibliothek weiterhin die alte Verbindung beibehält, sodass alle nachfolgenden Anfragen weiterhin über diese Verbindung gesendet werden und denselben Fehler erhalten use of closed connection .

Die Frage ist also, warum http2 immer noch eine bereits geschlossene Verbindung aufrechterhält? Vielleicht ist die aufrechterhaltene Verbindung tatsächlich aktiv, aber einige Zwischenverbindungen werden unerwartet geschlossen?

Ich habe das gleiche Problem mit einem Raspberry Pi Cluster mit k8s 1.17.3 sehr oft. Aufgrund einiger älterer Probleme habe ich das HTTP-Verbindungslimit des Kube-API-Servers auf 1000 "- --http2-max-streams-per-connection=1000" gesetzt, es war für mehr als 2 Wochen in Ordnung, danach startet es jetzt wieder.

Ist es möglich, den Kube-Apiserver https://github.com/kubernetes/apiserver/blob/b214a49983bcd70ced138bd2717f78c0cff351b2/pkg/server/secure_serving.go#L50 neu zu erstellen?
s.DisableHTTP2 standardmäßig auf true ?
Gibt es ein Dockerfile für ein offizielles Image ( k8s.gcr.io/kube-apiserver:v1.17.3 )?

das gleiche hier (ubuntu 18.04, kubernetes 1.17.3)

Dies haben wir auch in zwei unserer Cluster beobachtet. Nicht ganz sicher über die Ursache, aber zumindest konnten wir sehen, dass dies in Clustern mit sehr hohen Watchcounts geschah. Ich konnte jedoch nicht reproduzieren, indem ich eine hohe Anzahl von Uhren pro Kubelet erzwang (startete Pods mit 300 Geheimnissen pro Pod, was auch zu 300 Uhren pro Pod in Prometheus-Metriken führte). Auch das Setzen sehr niedriger http2-max-streams-per-connection Werte hat das Problem nicht ausgelöst, aber zumindest konnte ich ein unerwartetes Verhalten von Scheduler und Controller-Manager beobachten (möglicherweise nur überlastet nach endlosen Wiederholungsschleifen oder ähnlichem, obwohl).

Als Workaround werden alle meine Nodes jede Nacht über einen lokalen Cronjob neu gestartet. Jetzt nach 10 Tagen kann ich sagen, dass es für mich funktioniert, ich habe keine "Verwendung einer geschlossenen Netzwerkverbindung" mehr auf meinen Knoten.

@sbiermann
Vielen Dank, dass Sie das gepostet haben. Welches Zeitintervall verwendest du für Cronjob?

24 Stunden

Ich kann dieses Problem auch bestätigen, wir sind noch nicht auf 1.17.3, derzeit läuft 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

Ich kann dies auch für Kubernetes 1.17.4 bestätigen, das über Rancher 2.3.5 auf RancherOS 1.5.5-Knoten bereitgestellt wird. Der Neustart des Kubelet scheint für mich zu funktionieren, ich muss nicht den gesamten Knoten neu starten.

Die zugrunde liegende Ursache für mich scheint zu sein, dass der RAM fast ausgeht und kswapd0 dadurch bis zu 100% CPU-Auslastung erreicht, da ich vergessen habe, die Swappiness für meine Kubernetes-Knoten auf 0 zu setzen. Nachdem ich die Swappiness auf 0 gesetzt und den Maschinen etwas RAM hinzugefügt habe, ist das Problem bei mir noch nicht aufgetreten.

Wenn das zugrunde liegende Problem "http2 mit toten Verbindungen" war, sollte ein Neustart von Kubelet das Problem beheben. https://github.com/kubernetes/kubernetes/pull/48670 schlug vor, TCP_USER_TIMEOUT zu reduzieren, um das Problem zu mildern. Ich habe https://github.com/golang/net/pull/55 geöffnet, um der http2-Bibliothek eine clientseitige Verbindungsintegritätsprüfung hinzuzufügen, aber es wird länger dauern, bis sie landet.

Wenn das Problem durch den Neustart von Kubelet nicht behoben wurde, liegt es wahrscheinlich an einer anderen Ursache.

Ich habe das gleiche Problem mit v1.17.2 beim Neustart des Netzwerks, aber nur einer der Knoten hat dieses Problem (mein Cluster hat fünf Knoten), ich kann es nicht reproduzieren. Kubelet neu starten hat dieses Problem behoben.

Wie kann ich dieses Problem vermeiden? Aktualisieren Sie die neueste Version oder haben Sie eine andere Möglichkeit, das Problem zu beheben?

Ich habe es behoben, indem ich dieses Bash-Skript alle 5 Minuten ausgeführt habe:

#!/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

Ich habe einen Patch ohne Neustart von Kubelet erstellt und es scheint, dass das Problem behoben ist.
Frist-Patch

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 Können Sie bitte erklären, wie Sie den Client-Go neu

@mYmNeo Können Sie bitte erklären, wie Sie den Client-Go neu

@ik9999 Wenden Sie diesen Patch an,

@mYmNeo Wie kann ich dieses Problem reproduzieren und testen?

Ich habe es behoben, indem ich dieses Bash-Skript alle 5 Minuten ausgeführt habe

@ik9999 Danke, es funktioniert.

cc @liggitt

Bedeutet die Einstellung von SetReadDeadline, dass alle Uhren alle 30 Sekunden geschlossen werden?

Bedeutet die Einstellung von SetReadDeadline, dass alle Uhren alle 30 Sekunden geschlossen werden?

Jawohl. Es ist eine hässliche Möglichkeit, dieses Problem zu lösen (das Schließen einer Verbindung erzwingen).

Nur ein anderer Fall:

Wir sehen dies auch in Kube 1.16.8-Clustern. Ein Neustart der VM kann verwendet werden, um den Knoten wieder in einen guten Zustand zu versetzen (ich vermute, dass ein Kubelet-Neustart auch funktioniert hätte).

Unser Setup-Kubelet kommuniziert über localhost mit einer lokalen Haproxy-Instanz, die als TCP-Load-Balancer für die mehreren Back-End-Master-Instanzen fungiert. Wir werden untersuchen, ob das Hinzufügen

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

Unsere Load-Balancer-Instanzen helfen dabei, die Notwendigkeit des expliziten Neustarts zu verringern und können zu einer vollständigen Wiederherstellung führen. Beispiel für wiederholte Protokolle

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

Werde ein Update posten, wenn das unser spezifisches Problem löst, falls das hier in der Zwischenzeit jemandem hilft.

Neugierig, ob es einen Konfigurationsparameter gibt, um eine absolute Obergrenze für eine Wiedergabezeit festzulegen? Ich habe --streaming-idle-connection-timeout gefunden, aber nichts Besonderes für Uhren.

Wir sehen dies in kube 1.17.4, nachdem der API-Server aufgrund von "etcd failed: Reason zurückgehalten" fehlerhaft war.

Hallo Leute. Ich habe die Kubernetes-Binärdatei mit Golang 1.14 neu kompiliert. Das Problem scheint verschwunden zu sein

@mYmNeo golang 1.14 + Kubernetes v1.17?

@mYmNeo golang 1.14 + kubernetes v1.17 ?

@pytimer Wir verwenden 1.16.6, ohne den Code zu ändern, sondern nur neu zu kompilieren. Ich denke, die Ursache kann Golang sein.

Hey! Habe das gleiche Problem hier, k8s 1.17.4. Glauben wir, wir könnten eine 1.17.5 mit go 1.14 neu kompilieren, wenn das das Problem löst?

Leider erfordert das Update auf go1.14 Updates für mehrere Schlüsselkomponenten, daher ist es unwahrscheinlich, dass es auf Kube 1.17 zurückgenommen wird. Sie können die Probleme und den Fortschritt unter https://github.com/kubernetes/kubernetes/pull/88638 verfolgen

Gut zu wissen, thx

@callicles wurde bestätigt, dass die Neukompilierung mit go 1.14 das Problem behoben hat?

Ich sehe ein identisches Problem bei 1.16.8 - von Zeit zu Zeit (manchmal alle paar Tage, manchmal alle paar Wochen) wird der Knoten NotReady, mit dem Grund, warum Kubelet den Knotenstatus nicht mehr veröffentlicht, und "Verwendung einer geschlossenen Netzwerkverbindung". Füllen der Protokolle

go kann Probleme mit dem H2-Upgrade haben.
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
        }

Hallo Leute. Ich habe die Kubernetes-Binärdatei mit Golang 1.14 neu kompiliert. Das Problem scheint verschwunden zu sein

@mYmNeo haben Sie das Problem nach der Neukompilierung mit go 1.14 jemals reproduziert

Hallo Leute. Ich habe die Kubernetes-Binärdatei mit Golang 1.14 neu kompiliert. Das Problem scheint verschwunden zu sein

@mYmNeo haben Sie das Problem nach der Neukompilierung mit go 1.14 jemals reproduziert

AFAIN, das Problem besteht nicht mehr.

Leider erfordert das Update auf go1.14 Updates für mehrere Schlüsselkomponenten, daher ist es unwahrscheinlich, dass es auf Kube 1.17 zurückgenommen wird. Sie können die Probleme und den Fortschritt in #88638 verfolgen

Wissen Sie schon, ob go1.14 auf 1.18 zurückportiert wird?

Wissen Sie schon, ob go1.14 auf 1.18 zurückportiert wird?

Das würde ich nicht erwarten. Änderungen an etcd und bbolt scheinen erforderlich zu sein, um go1.14 zu unterstützen, was eine größere Änderung ist, als normalerweise in Release-Zweigen vorgenommen wird.

@liggitt Okay thx. Sieht so aus, als ob wir (zumindest für unsere Cluster) in der Zwischenzeit eine Minderungsstrategie brauchen :)

Tritt dieses Problem nur nach einem NIC-Fehler auf? Wir sehen dieselbe Fehlermeldung in unseren v1.16.8-Clustern, aber es liegt kein zugehöriger NIC-Fehler vor.

Wir hatten mindestens eine Instanz, bei der die zugrunde liegende VM beim Herstellen einer Verbindung mit einem SAN einen SCSI-Fehler aufwies. Das SCSI-Problem hat sich von selbst gelöst, aber das kubelet nie wieder behoben.

Die Option --goaway-chance wurde in 1.18 (#88567) hinzugefügt. Wird diese Option dieses Problem lindern?

Nein. Das hat nur dann einen Effekt, wenn das Kubelet den API-Server tatsächlich erreichen und eine Antwort zurückbekommen.

Bei einem NIC-Bond-Fehler (der sich nicht lange danach erholt), werden alle Verbindungen unterbrochen und es wird nicht erneut versucht, sie wiederherzustellen, es sei denn, es wird manuell neu gestartet.

Kannst du bitte sagen, welchen Bond-Modus du verwendest? Ich kann dies auf meinem Cluster mit Active-Backup-Anleihen nicht reproduzieren.

Nach dem Upgrade auf Kubernetes 1.16 sahen wir auch den Fehler use of closed network connection und das Kubelet konnte sich nicht wieder mit dem Apiserver verbinden, wodurch die Knoten in NotReady stecken blieben. Wir konnten das Problem nicht reproduzieren, indem wir NICs herunternahmen (indem wir die Links nach unten/oben setzen), aber wir haben festgestellt, dass dieses Verhalten nur bei stärker belasteten Clustern auftrat.

Wir haben weiter gegraben und festgestellt, dass der serverseitige Standard in Golang 250 http2-Streams pro Client beträgt , während der clientseitige Standard 1000 ist. es hat nie versucht, sich wieder zu verbinden. Nachdem wir --http2-max-streams-per-connection=1000 , sahen wir das Problem, dass Knoten in NotReady stecken blieben, nicht mehr so ​​​​sehr wie ursprünglich beim Testen. Dadurch wurde das Problem, dass Kubelet nicht wieder verbunden wurde, nicht behoben, aber es hat uns geholfen, das aufgetretene Problem zu beheben.

Nach dem Upgrade auf Kubernetes 1.16 sahen wir auch den Fehler use of closed network connection und das Kubelet konnte sich nicht wieder mit dem Apiserver verbinden, wodurch die Knoten in NotReady stecken blieben. Wir konnten das Problem nicht reproduzieren, indem wir NICs herunternahmen (indem wir die Links nach unten/oben setzen), aber wir haben festgestellt, dass dieses Verhalten nur bei stärker belasteten Clustern auftrat.

Wir haben weiter gegraben und festgestellt, dass der serverseitige Standard in Golang 250 http2-Streams pro Client beträgt , während der clientseitige Standard 1000 ist. es hat nie versucht, sich wieder zu verbinden. Nachdem wir --http2-max-streams-per-connection=1000 , sahen wir das Problem, dass Knoten in NotReady stecken blieben, nicht mehr so ​​​​sehr wie ursprünglich beim Testen. Dadurch wurde das Problem, dass Kubelet nicht wieder verbunden wurde, nicht behoben, aber es hat uns geholfen, das aufgetretene Problem zu beheben.

Hallo, die standardmäßigen serverseitigen https-Streams in kube-apiserver sind 1000, dies entspricht dem Wert des Clients.
https://github.com/kubernetes/kubernetes/blob/ae1103726f9aea1f9bbad1b215edfa47e0747dce/staging/src/k8s.io/apiserver/pkg/server/options/recommended.go#L62

@warmchang Ich denke, dies gilt für apiextensions-Apiserver und den Beispiel-Apiserver:
https://github.com/kubernetes/kubernetes/blob/ae1103726f9aea1f9bbad1b215edfa47e0747dce/staging/src/k8s.io/apiserver/pkg/server/options/recommended.go#L62

Ein Test mit curl test ohne Einstellung von --http2-max-streams-per-connection hat dies in unseren Apiserver-Logs (mit v1.16):
I0603 10:18:08.038531 1 flags.go:33] FLAG: --http2-max-streams-per-connection="0"

Und eine curl-Anfrage zeigt dies in der Antwort:
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!

Wenn ich --http2-max-streams-per-connection=1000 die curl-Anfrage dann angezeigt
* Connection state changed (MAX_CONCURRENT_STREAMS == 1000)!

@jmcmeek @treytabner , du hast recht. Ich habe den Code falsch gelesen. :+1:

Verwenden von Kubernetes 1.17.6 und dasselbe hier. Es sieht so aus, als würde Kubelet eine tote http2-Verbindung verwenden.
Mir ist aufgefallen, dass der inkonsistente Standardwert von MAX_CONCURRENT_STREAMS zwischen kube-apiserver und kubelet.

Setzen Sie einfach den serverseitigen Wert auf 1000. Werde später berichten.

Rancher/RKE

Zur Clusterdefinition hinzufügen:

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

Auf Master-Knoten prüfen:

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

Das Setzen von MAX_CONCURRENT_STREAMS auf 1000 auf dem APIserver hat keine Auswirkung auf dieses Problem.
Ich glaubte, dass dies durch einen Fehler in golang http2 Transport . Siehe oben

Hatte dieses Problem heute Nacht wieder.
Anscheinend hat die Einstellung 'MAX_CONCURRENT_STREAMS' nicht geholfen☹️

Hallo Leute. Ich glaube, endlich habe ich dieses Problem aufgespürt. Wir haben das gleiche Problem gestern Abend passiert. Aber erfolgreich mit einem modifizierten Kubelet wiederhergestellt.

Es ist kein Kubernetes-Bug, es geht um das Standardpaket net/http von Golang, das auch client-go verwendet.
Ich glaube, es gibt einen Fehler in golang.org/x/net/http2/transport.go

Habe dies bereits dem Golang-Beamten gemeldet. Warten auf eine Diskussion.
https://github.com/golang/go/issues/39750

Im Moment habe ich den Code so geändert, dass das von https://github.com/golang/net/commit/0ba52f642ac2f9371a88bfdde41f4b4e195a37c0 eingeführte http2: perform connection health check standardmäßig aktiviert ist.
Es erweist sich als eine Hilfe bei diesem Problem. Aber ein wenig langsam reagiert.

kubelet v1.17.6-Protokolle (erfüllt mit selbstmodifiziertem golang.org/x/net Paket)

Es hat sich von dem Problem des Schreibens toter Verbindungen erholt, kostete jedoch etwas mehr Zeit als erwartet.

Beachten Sie, dass performing http2 healthCheck eine Protokollnachricht ist, die ich dort belassen wollte, um zu beweisen, dass healthCheck func von readIdleTimer aufgerufen wird

 23. Juni 03:14:45 vm10.company.com kubelet[22255]: E0623 03:14:45.912484 22255 kubelet_node_status.go:402] Fehler beim Aktualisieren des Knotenstatus, wird erneut versuchen: Fehler beim Abrufen des Knotens "vm10.company.com": Get "https://vm10.company.com:8443/api/v1/nodes/vm10.company.com?timeout=10s": tcp schreiben 16.155.199.4:39668->16.155.199.4:8443: Nutzung einer geschlossenen Netzwerkverbindung
 23. Juni 03:14:45 vm10.company.com kubelet[22255]: E0623 03:14:45.912604 22255 kubelet_node_status.go:402] Fehler beim Aktualisieren des Knotenstatus, wird erneut versuchen: Fehler beim Abrufen des Knotens "vm10.company.com": Get "https://vm10.company.com:8443/api/v1/nodes/vm10.company.com?timeout=10s": tcp schreiben 16.155.199.4:39668->16.155.199.4:8443: Nutzung einer geschlossenen Netzwerkverbindung
 23. Juni 03:14:45 vm10.company.com kubelet[22255]: E0623 03:14:45.912741 22255 kubelet_node_status.go:402] Fehler beim Aktualisieren des Knotenstatus, wird erneut versuchen: Fehler beim Abrufen des Knotens "vm10.company.com": Get "https://vm10.company.com:8443/api/v1/nodes/vm10.company.com?timeout=10s": tcp schreiben 16.155.199.4:39668->16.155.199.4:8443: Nutzung einer geschlossenen Netzwerkverbindung
 23. Juni 03:14:46 vm10.company.com kubelet[22255]: E0623 03:14:46.367046 22255 controller.go:135 konnte nicht sicherstellen, dass die Node-Lease vorhanden ist, wird in 400 ms erneut versucht, Fehler: Hole "https:// vm10.company.com:8443/apis/coordination.k8s.io/v1/namespaces/kube-node-lease/leases/vm10.company.com?timeout=10s": tcp 16.155.199.4:39668->16.155 schreiben. 199.4:8443: Nutzung einer geschlossenen Netzwerkverbindung
 23. Juni 03:14:48 vm10.company.com kubelet[22255]: E0623 03:14:47.737579 22255 controller.go:135 konnte nicht sicherstellen, dass die Node-Lease vorhanden ist, wird in 800 ms erneut versucht, Fehler: Hole "https:// vm10.company.com:8443/apis/coordination.k8s.io/v1/namespaces/kube-node-lease/leases/vm10.company.com?timeout=10s": tcp 16.155.199.4:39668->16.155 schreiben. 199.4:8443: Nutzung einer geschlossenen Netzwerkverbindung
 23. Juni 03:14:49 vm10.company.com kubelet[22255]: E0623 03:14:49.113920 22255 reflect.go:153] k8s.io/kubernetes/pkg/kubelet/kubelet.go:458: Fehler beim Auflisten * v1.Node: Hole "https://vm10.company.com:8443/api/v1/nodes?fieldSelector=metadata.name%3Dvm10.company.com&limit=500&resourceVersion=0": schreibe tcp 16.155.199.4:39668-> 16.155.199.4:8443: Nutzung einer geschlossenen Netzwerkverbindung
 23. Juni 03:14:49 vm10.company.com kubelet[22255]: E0623 03:14:48.744770 22255 reflect.go:153] object-"kube-system"/"flannel-token-zvfwn": Fehler beim Auflisten * v1.Secret: Holen Sie sich "https://vm10.company.com:8443/api/v1/namespaces/kube-system/secrets?fieldSelector=metadata.name%3Dflannel-token-zvfwn&limit=500&resourceVersion=0": schreiben Sie tcp 16.155 .199.4:39668->16.155.199.4:8443: Nutzung einer geschlossenen Netzwerkverbindung
 23. Juni 03:14:49 vm10.company.com kubelet[22255]: E0623 03:14:49.599631 22255 reflect.go:153] object-"kube-system"/"coredns": Fehler beim Auflisten von *v1.ConfigMap: Holen Sie sich "https://vm10.company.com:8443/api/v1/namespaces/kube-system/configmaps?fieldSelector=metadata.name%3Dcoredns&limit=500&resourceVersion=0": schreiben Sie tcp 16.155.199.4:39668->16.155. 199.4:8443: Nutzung einer geschlossenen Netzwerkverbindung
 23. Juni 03:14:49 vm10.company.com kubelet[22255]: E0623 03:14:49.599992 22255 controller.go:135 konnte nicht sicherstellen, dass die Node-Lease vorhanden ist, wird es in 1,6s erneut versuchen, Fehler: Hole "https:/ /vm10.company.com:8443/apis/coordination.k8s.io/v1/namespaces/kube-node-lease/leases/vm10.company.com?timeout=10s": tcp schreiben 16.155.199.4:39668->16.155 .199.4:8443: Nutzung einer geschlossenen Netzwerkverbindung
 23. Juni 03:14:49 vm10.company.com kubelet[22255]: E0623 03:14:49.600182 22255 reflect.go:153] k8s.io/kubernetes/pkg/kubelet/kubelet.go:449: Fehler beim Auflisten * v1.Service: Hole "https://vm10.company.com:8443/api/v1/services?limit=500&resourceVersion=0": Schreibe tcp 16.155.199.4:39668->16.155.199.4:8443: Nutzung des geschlossenen Netzwerks Verbindung
 23. Juni 03:14:49 vm10.company.com kubelet[22255]: E0623 03:14:49.600323 22255 reflect.go:153] object-"kube-system"/"kube-flannel-cfg": Fehler beim Auflisten * v1.ConfigMap: Holen Sie sich "https://vm10.company.com:8443/api/v1/namespaces/kube-system/configmaps?fieldSelector=metadata.name%3Dkube-flannel-cfg&limit=500&resourceVersion=0": schreiben Sie tcp 16.155 .199.4:39668->16.155.199.4:8443: Nutzung einer geschlossenen Netzwerkverbindung
 23. Juni 03:14:49 vm10.company.com kubelet[22255]: E0623 03:14:49.600463 22255 reflect.go:153] object-"core"/"registrypullsecret": Fehler beim Auflisten von *v1.Secret: Get " https://vm10.company.com:8443/api/v1/namespaces/core/secrets?fieldSelector=metadata.name%3Dregistrypullsecret&limit=500&resourceVersion=0": tcp schreiben 16.155.199.4:39668->16.155.199.4:8443: Nutzung einer geschlossenen Netzwerkverbindung
 23. Juni 03:14:49 vm10.company.com kubelet[22255]: E0623 03:14:49.369097 22255 reflect.go:153] object-"kube-system"/"registrypullsecret": Fehler beim Auflisten von *v1.Secret: Holen Sie sich "https://vm10.company.com:8443/api/v1/namespaces/kube-system/secrets?fieldSelector=metadata.name%3Dregistrypullsecret&limit=500&resourceVersion=0": schreiben Sie tcp 16.155.199.4:39668->16.155. 199.4:8443: Nutzung einer geschlossenen Netzwerkverbindung
 23. Juni 03:25:39 vm10.company.com kubelet[22255]: E0623 03:25:39.543880 22255 wish_state_of_world_populator.go:320] Fehler beim Verarbeiten des Volumes "deployment-log-dir" für Pod "fluentd-h76lr_core(e95c9200-3a0c .) -4fea-bd7f-99ac1cc6ae7a)": Fehler bei der Verarbeitung von PVC core/itom-vol-claim: PVC konnte nicht vom API-Server abgerufen werden: Hole "https://vm10.company.com:8443/api/v1/namespaces/core/ persistentvolumeclaims/itom-vol-claim": tcp lesen 16.155.199.4:41512->16.155.199.4:8443: Verwendung einer geschlossenen Netzwerkverbindung
 23. Juni 03:25:39 vm10.company.com kubelet[22255]: E0623 03:25:39.666303 22255 kubelet_node_status.go:402] Fehler beim Aktualisieren des Knotenstatus, wird erneut versucht: Fehler beim Patchen des Status "{\"status\": {\"$setElementOrder/conditions\":[{\"type\":\"MemoryPressure\"},{\"type\":\"DiskPressure\"},{\"type\":\"PIDPressure\ "},{\"type\":\"Ready\"}],\"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\:\"Ready\"}]}}" für Knoten "vm10.company.com": Patch "https://vm10.company.com:8443/api/v1/nodes/vm10.company.com/ status?timeout=10s": tcp lesen 16.155.199.4:41512->16.155.199.4:8443: Verwendung einer geschlossenen Netzwerkverbindung
 23. Juni 03:25:49 vm10.company.com kubelet[22255]: E0623 03:25:49.553078 22255 kubelet_node_status.go:402] Fehler beim Aktualisieren des Knotenstatus, wird erneut versuchen: Fehler beim Abrufen des Knotens "vm10.company.com": Get "https://vm10.company.com:8443/api/v1/nodes/vm10.company.com?timeout=10s": tcp lesen 16.155.199.4:41718->16.155.199.4:8443: Nutzung einer geschlossenen Netzwerkverbindung
 23. Juni 03:25:49 vm10.company.com kubelet[22255]: E0623 03:25:49.560723 22255 wish_state_of_world_populator.go:320] Fehler beim Verarbeiten des Volumes "log-location" für Pod "fluentd-h76lr_core(e95c9200-3a0c-4fea .) -bd7f-99ac1cc6ae7a)": Fehler bei der Verarbeitung von PVC core/itom-logging-vol: PVC konnte nicht vom API-Server abgerufen werden: Hole "https://vm10.company.com:8443/api/v1/namespaces/core/persistentvolumeclaims/ itom-logging-vol": tcp lesen 16.155.199.4:41718->16.155.199.4:8443: Nutzung einer geschlossenen Netzwerkverbindung
 23. Juni 03:27:29 vm10.company.com kubelet[22255]: I0623 03:27:29.961600 22255 log.go:181] führt http2 healthCheck durch
 23. Juni 03:31:32 vm10.company.com kubelet[22255]: I0623 03:31:31.829860 22255 log.go:181] führt http2 healthCheck durch
 23. Juni 03:31:44 vm10.company.com kubelet[22255]: I0623 03:31:44.570224 22255 log.go:181] führt http2 healthCheck durch
 23. Juni 03:32:13 vm10.company.com kubelet[22255]: I0623 03:32:12.961728 22255 log.go:181] führt http2 healthCheck durch
 23. Juni 03:33:16 vm10.company.com kubelet[22255]: I0623 03:33:15.441808 22255 log.go:181] führt http2 healthCheck durch
 23. Juni 03:33:28 vm10.company.com kubelet[22255]: I0623 03:33:28.233121 22255 log.go:181] führt http2 healthCheck durch

Es werden keine use of closed network connection gemeldet und Kubelet kehrt in den Status Bereit zurück

Wir haben einige neue potenzielle Einblicke in das Thema in unseren Stacks. Mit einiger Sicherheit gehen wir von einem seltenen Verbindungsabbruch auf Netzwerk-/Infrastrukturebene aufgrund hoher Last in Bezug auf die Verbindungsnummern in bestimmten Situationen aus. In unserem Fall war es also kein Flipping der Netzwerkschnittstellen. Aus diesem Grund hatten wir insbesondere http2.Transport.ReadIdleTimeout wie mit golang/net#55 implementiert, hat die Föderationsprobleme für uns vollständig gelöst.

Die Werte werden derzeit nicht verfügbar gemacht, da apimachinery/pkg/util/net/http.go http.Transport apimachinery/pkg/util/net/http.go instanziiert und dies intern auf http2 aktualisiert, wodurch die Option erst verfügbar gemacht wird, wenn golang/net#74 zusammengeführt wird.

Gibt es neben dem kubelet-Neustart-Cronjob noch andere Problemumgehungen? Wir haben seit einer Woche einen Cron-Job und das hat das Problem nicht verhindert.

Ich habe das gleiche Problem in v1.17.3.

Was ich festgestellt habe, ist, dass die k8s-Version, die eine bestimmte golang.org/x/net Version verwendet, in Schwierigkeiten ist und dieses Paket anscheinend behoben ist.
https://go-review.googlesource.com/c/net/+/198040

Version mit diesem Problem (v1.16.5 ~ neueste Version)
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9

Fix Version (Master-Zweig)
golang.org/x/net v0.0.0-20200707034311-ab3426394381

Wird dieses Problem durch die Aktualisierung des golang.org/x/net Pakets behoben?

Ist eine Veröffentlichung für die gepflegte k8s-Version (v1,16, 1.17, v1,18..) geplant, um dies zu beheben?

Was ich festgestellt habe, ist, dass die k8s-Version, die eine bestimmte golang.org/x/net Version verwendet, in Schwierigkeiten ist und dieses Paket anscheinend behoben ist.
https://go-review.googlesource.com/c/net/+/198040

Die erwähnte Änderung _bietet_ nur die Möglichkeit, den HTTP2-Gesundheitsmonitor zu aktivieren, muss jedoch von Entwicklern aktiviert werden (Standard ist deaktiviert). Außerdem kann es nicht wirklich eingestellt werden, aber es gibt einen Pull-Request, um Entwicklern Zugriff auf den Health Monitor zu geben .

Ich integriere derzeit einen reflexionsbasierten Hotfix, der den Zustandsmonitor für unsere eigene Kubernetes-Distribution aktiviert, in der Hoffnung, dass dies zur Lösung des Problems beiträgt.

--
Jens Erat \ Impressum

@JensErat danke für die Antwort.
Wenn ja, kann dieses Problem auch in älteren Versionen von k8s(1.13, 1.15, ..) auftreten?

Ich habe vor mehr als einem Monat die Nodes-Distribution von RancherOS (Kernel 4.14.138) auf Ubuntu 18.04 (Kernel 5.3.0) geändert, das Problem ist seitdem nicht aufgetreten.
Einer meiner Cluster, der auf RancherOS übrig geblieben ist, hat dieses Problem bereits dreimal reproduziert.

Nicht 100% sicher, aber wahrscheinlich spielt die Kernel-Version eine Rolle.

Schwer zu sagen. Wir beobachten (d) definitiv das Problem mit 1.16 bis 1.18, aber es gab vorher seltene seltsame "Kubelet-Steck-Ereignisse". Wir haben uns bereits seit mindestens einem Jahr mit solchen Problemen beschäftigt, konnten aber nie etwas in Beziehung setzen (einzelne Vorfälle alle paar Wochen, und wir haben eine vierstellige Anzahl von Kubelets am Laufen). Ist zwar viel schlimmer geworden, seit wir 1.16 installiert haben, aber derzeit gehen wir eher davon aus, dass die zugrunde liegenden (auch sehr seltenen und schwer aufzuspürenden...) Netzwerkprobleme häufiger auftreten. Wir verwenden Ubuntu 19.10 mit Kernel 5.3.0-46-generic, sind aber betroffen (so gut möglich, dass Sie tatsächlich einen neueren Patchlevel haben). Können Sie einen Hinweis geben, welche genaue Kernel-Version/Patch-Level Sie ausführen?

--
Jens Erat \ Impressum

Es ist 5.3.0-59-generic . Aber wir haben nur ~ 40 Kubletes, also könnte es immer noch ein Zufall sein.

Wie ich oben sagte. Dieses Problem tritt häufiger bei stark belasteten Clustern auf. Wir haben das gleiche Problem fast jede Nacht beobachtet, bevor wir h2 transport healthCheck aktiviert haben.
Laut dem Problem, das dem Golang-Beamten gemeldet wurde . Das Problem tritt in einer Socket-Leseschleife auf, die beim Lesen eines geschlossenen Sockets einen Fehler zurückgeben sollte, dies jedoch nie tut. Außerdem schlage ich vor, beim Schreiben von Sockets eine Fehlerbehandlungslogik hinzuzufügen, um Verbindungsprobleme aktiv zu erkennen. Aber einige Tage später scheint es, dass sie sich nicht um solche seltenen Probleme kümmern.

Ein bisschen weit zum Thema, meine ich, da das Problem durch den Netzwerk-Socket verursacht wird, der dem Kernel sehr nahe kommt. Das Aktualisieren des Kernels kann helfen oder nicht. (PS: Wir verwenden centos 7 mit Kernel 3.10, es passiert fast jeden Tag, bevor HealthCheck aktiviert wird)
Ich habe ungefähr 3 Tage damit verbracht, den Quellcode von net/http zu lesen, soweit ich das gesehen habe, um h2 transport healthCheck zu aktivieren, um sich von einem solchen Problem zu erholen, und wir sind dadurch wirklich aus dieser seltsamen Situation entkommen.
@JensErat Haben Sie konkrete Beweise dafür, dass die Aktivierung von healthCheck hilft, dieses Problem zu lösen?

@JensErat Haben Sie konkrete Beweise dafür, dass die Aktivierung von healthCheck hilft, dieses Problem zu lösen?

Wir führen die Prometheus-Föderation für jeden unserer Kubernetes-Cluster aus. Prometheus 2.19.0 führte http2 ein (sie vergessen jedoch, dies im Changelog zu erwähnen und hatten es in einem Commit-Nachrichtentext gut versteckt, ich musste git halbieren, bereitstellen und einige Stunden für jeden Lauf warten ...) und wir beobachteten ungefähr ein Dutzend Vorfälle mit einem festsitzenden Verband pro Tag. Ich habe zuerst die http2-Unterstützung wieder ausgepatcht (und das Problem war weg) und dann das Lese-Timeout direkt in golang/net/x/http2 eingestellt. Seitdem hatten wir keinen einzigen Vorfall mehr mit einem Föderationsausfall.

Ich bereite derzeit die Bereitstellung einer gepatchten Kubernetes-Version auf einigen Clustern vor, sodass wir in wenigen Tagen über Daten verfügen sollten. Wir werden unsere Ergebnisse auf jeden Fall mitteilen, sobald wir die richtigen Daten haben.

--
Jens Erat \ Impressum

Ich bereite derzeit die Bereitstellung einer gepatchten Kubernetes-Version auf einigen Clustern vor, sodass wir in wenigen Tagen über Daten verfügen sollten. Wir werden unsere Ergebnisse auf jeden Fall mitteilen, sobald wir die richtigen Daten haben.

Vielen Dank für Ihr Feedback. Das ist eine sehr erfreuliche Nachricht.
Obwohl die Ursache nicht ganz klar ist, finden wir zumindest einen Weg, um sich von einer Katastrophe zu erholen. :D

Wir haben das gleiche Problem mit k8s v1.14.3 und ein Neustart von Kubelet kann das Problem beheben.

Ich weiß, das ist albern, muss aber als vorübergehende Problemumgehung funktionieren:

Erweitern Sie 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


(Dies ist Rancher-spezifisch, kann aber leicht an andere Distributionen angepasst werden, indem privilegierte Container und journalctl/systemctl verwendet werden)

Die Zeitdauer für sleep und --since muss kürzer sein als die pod-eviction-timeout Clusters (standardmäßig 5

Übrigens - docker pause nginx-proxy auf dem Rancher-Worker-Knoten führt dazu, dass Kubelet die gleiche Fehlermeldung ausgibt.

Temporäre Problemumgehung für diejenigen, die K8S auf VMWare vSphere ausführen – deaktivieren Sie DRS für die K8S-VMs, um zu verhindern, dass vSphere VMs zwischen Hypervisoren verschiebt, wodurch alle Netzwerktrennungen beseitigt werden, die den Kubelets Probleme bereiten

Wir haben einige sehr gute Neuigkeiten bezüglich der Eindämmung des Problems mit der neuen golang http2 Health Check-Funktion: Keine Probleme mehr. Inzwischen haben wir den "Fix" (hartcodierte Einstellung des Werts im herstellereigenen x/net Code) in Prometheus, ganze Kubernetes und mehrere interne Komponenten implementiert und dabei Folgendes beobachtet:

  • keine Probleme mit der Prometheus-Föderation mehr
  • kubelet meldet manchmal immer noch einzelne "Verwendung einer geschlossenen Verbindung"-Ereignisse, erholt sich jedoch innerhalb von Sekunden (wir haben ein ~30-Sekunden-Fenster für die http2-Gesundheitsprüfung festgelegt).
  • manchmal hatten wir Probleme mit kubectl-Uhren -- auch weg, wenn gepatchtes kubectl verwendet wurde
  • Wir führen eine erweiterte E2E-Testsuite aus, um unsere Integration regelmäßig zu überprüfen, und haben sporadische Testzeitüberschreitungen und -schwankungen beobachtet. Erraten Sie, was? Jetzt weg.

Darüber hinaus konnten wir neue Erkenntnisse darüber gewinnen, wie die Probleme ausgelöst werden können. Ich kann die Beobachtung von @vi7 bezüglich der Live-Migration mit einiger

Dies ist ein sehr ärgerliches und etwas massives Problem für einige Benutzer von Kubernetes (abhängig von einer Art "Bruch" der IaaS-Schicht / des Netzwerks, denke ich). Obwohl es Golang-Diskussionen darüber gibt, eine Schnittstelle freizugeben, um die Werte richtig einzustellen - glauben Sie, dass es eine Chance gibt, dass ein PR-Upstream diese Werte durch Reflexion zusammenführt (immer noch besser als x / net zu verzweigen, denke ich, wie wir es jetzt tun) ? Wir sind damit einverstanden, den Code bereitzustellen (und den Fix zu validieren, wir können ihn nicht wirklich reproduzieren, aber beobachten ihn oft genug, um bestätigen zu können, ob der Fix funktioniert).

cc @liggitt

Langzeit-Problem (Notiz an sich selbst)

@JensErat danke für die Antwort.
Wenn ja, kann dieses Problem auch in älteren Versionen von k8s(1.13, 1.15, ..) auftreten?

Ich kann bestätigen, dass das Problem mit Kubernetes v1.16.13 angezeigt wird
Wir haben das Problem mit Kubernetes v1.15.9 nicht gesehen

Wenn ich einen Kubenetes-Cluster v1.16.14 aus der etcd-Snapshot-Sicherung wiederherstelle. Dieser Fehler wird im Kubelet-Protokoll angezeigt.
danke an @ik9999 . Ich starte das Kubelet neu, dann verschwinden die Fehler

[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"

Wir sind auf das gleiche Problem bei 1.17.3 gestoßen, ein Neustart von Kubelet sollte behoben sein. Irgendein stabiler Workaround dafür oder wann das behoben werden soll?

v1.18.6 gleich

@rxwang662001
Dies wird durch ein Upstream-Golang-Problem verursacht. Sicher ist, dass dies in go 1.15 NICHT behoben wird.
Unterdessen kämpft die Kubernetes-Community immer noch mit der Migration auf 1.14 LOL.

Go-Releases werden in der Regel alle 6 Monate veröffentlicht. Wenn alles gut funktioniert, könnten wir vielleicht sehen, dass dieses Problem im nächsten Jahr von Upstream behoben wird, und vielleicht noch ein Jahr, bis Kubernetes den Fix anwendet 🥇 !
(Nur zum Scherz. Wenn Sie dies jetzt wirklich in Ihrem Stack beheben möchten. Hacken Sie den h2Transport, um HealthCheck zu aktivieren.

Unterdessen kämpft die Kubernetes-Community immer noch mit der Migration auf 1.14 LOL.

Tatsächlich wurde Kubernetes 1.19 aufgrund der großartigen Arbeit von sig-scalability und sig-release, um sich für go1.15-Prereleases zu qualifizieren, gerade auf go1.15 veröffentlicht. Es sieht so aus, als ob an der Bereitstellung der http/2-Optionen in go1.16 gearbeitet wird, und ich gehe davon aus, dass wir davon Gebrauch machen werden, sobald es verfügbar ist.

Tatsächlich wurde Kubernetes 1.19 aufgrund der großartigen Arbeit von sig-scalability und sig-release, um sich für go1.15-Prereleases zu qualifizieren, gerade auf go1.15 veröffentlicht.

Opps. Sorry für den komischen Witz. Habe der Version 1.19 nicht viel Aufmerksamkeit geschenkt.
Scheint, dass wir go1.14 bei K8S komplett übersprungen haben? Beeindruckend. das ist ein großer sprung 👍

@povsister

Danke, dass du deine Lösung teilst. Könnten Sie weitere Details dazu hinzufügen, wie es funktioniert hat?

Im Moment habe ich den Code so geändert, dass das von net@0ba52f6 eingeführte http2: perform connection health check standardmäßig aktiviert ist.
Es erweist sich als eine Hilfe bei diesem Problem. Aber ein wenig langsam reagiert.

Welche Codeänderungen haben Sie vorgenommen? Und wo, in welcher Datei?

@KarthikRangaraju
Verweisen Sie auf diesen PR , um healthCheck beim Initialisieren von h2Transport zu aktivieren.
oder Sie können einen Reflexions- / unsicheren Offset-Hack ausführen, um zur Laufzeit auf nicht exportierte Felder zuzugreifen.

Und vergessen Sie nicht, golang/x/net zu aktualisieren, bevor Sie solche Dinge tun.

Wir konnten dieses Problem nicht reproduzieren, obwohl wir von Zeit zu Zeit damit konfrontiert sind.

Da wir die Ursache des Symptoms nicht identifizieren können, beheben wir das Symptom trotzdem.

Unsere Lösung:

  • Das folgende Skript wird alle 1 Stunde ausgeführt. Es kommuniziert mit dem kube-api-Server über kubectl über die kube-Konfigurationsdatei
    kubelet verwendet(Auf diese Weise gibt es keine Privilegieneskalation).
  • Fragt, ob der Master-Knoten thinks sein eigener Knoten ist NotReady. Wenn ja, wird ein Kubelet-Neustart ausgelöst, indem der Befehl touch für eine Datei ausgeführt wird
    das ist watched von einem kubelet-watcher.service für Dateisystemänderungen und startet kubelet entsprechend neu.
#!/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]#

Bei Kubernetes 1.19.0 besteht das Problem immer noch, aber die Meldung ist etwas anders.
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)
Es enthält jetzt ein "(kann nach dem Schlafen erneut versuchen)" in der Fehlermeldung.

Ist es möglich, dies in Kubernetes vollständig zu mildern, ohne auf einen Upgrade-Golang zu warten? Kann beispielsweise client-go veranlasst werden, den Transport auszulagern, wenn er auf eine "Nutzung einer geschlossenen Netzwerkverbindung" oder so trifft?

Würde dieses Problem alternativ auch weiterhin auftreten, wenn HTTP 1.1 verwendet wird, oder hängt es nur mit HTTP 2 zusammen? Wenn HTTP 1.1 immun wäre und keine großen Nachteile hätte, wäre es ein wirklich einfacher Workaround, einfach GODEBUG=http2client=0 für Kubelet, Kube-Proxy und verschiedene Prozesse auf der Steuerungsebene festzulegen oder sogar GODEBUG=http2server=0 festzulegen

Glauben wir, dass diese dieses Problem tatsächlich abschwächen und keine anderen schwerwiegenden Fallstricke verursachen würden, abgesehen von einigen Leistungsproblemen aufgrund der Erhöhung der Verbindungsanzahl, wenn nicht über HTTP2 gemultiplext wird?

kann client-go veranlasst werden, den Transport auszulagern, wenn er auf eine "Verwendung einer geschlossenen Netzwerkverbindung" oder so etwas trifft?

nicht sehr chirurgisch... Transporte werden derzeit geteilt, um eine kurzlebige Porterschöpfung angesichts von Anrufern zu vermeiden, die immer wieder neue Kunden aufbauen

würde dieses Problem weiterhin auftreten, wenn HTTP 1.1 verwendet wird, oder ist es rein mit HTTP 2 verbunden?

Soweit ich weiß, kann HTTP 1.1 auf das gleiche Problem stoßen, da inaktive Verbindungen in einen Keep-Alive-Pool zurückkehren (und weniger Optionen zum Erkennen / Abschwächen hat, da der Ping-Zustandsprüfungsmechanismus nicht verfügbar ist).

Gibt es einen guten Workaround für Projekte, die den Client verwenden? Wie können wir feststellen, wann der Client tot ist und was müssen wir mindestens tun, um ihn zu beheben (klingt, als wäre ein Neustart unseres Prozesses die einzige Option)?

Wie können wir erkennen, wann der Kunde tot ist?

Wenn Sie wiederholt einen write tcp xxx use of closed network connection Fehler für eine identische URL erhalten haben. Das zeigt an, dass der Client tot ist. Der Verbindungspool innerhalb von Transport hat eine tote TCP-Verbindung für den angeforderten host:port zwischengespeichert .

Gibt es einen guten Workaround für Projekte, die den Client verwenden?

Soweit ich weiß, kann das Rekonstruieren eines http.Client dieses Problem beheben, ohne die gesamte Anwendung neu zu starten.

Was müssen wir mindestens tun, um es zu beheben?

Es erfordert Zugriff auf Quellcodeebene für das Projekt. Vielleicht können Sie den oben erwähnten Mechanismus verwenden, um tote Clients zu erkennen und bei Bedarf einen neuen Client zu rekonstruieren. Wenn niemand den alten Client verwendet, wird er Garbage Collected.

Ich habe Quellcodezugriff auf mein Projekt, aber wir verwenden den Kubernetes-Client. Wenn wir Watches durchführen, scheint es nie zu erkennen, ob die TCP-Verbindung auf diese Weise getrennt wird (und da die Watch die HTTP-Transaktionen verarbeitet, werden keine Fehler in unserem Code angezeigt).

Ja. Sie haben Recht, http.Client wird vom Kubernetes-Client nicht angezeigt.
Derzeit ist es für Top-Level-Anwendungen hoffnungslos, eine solche Problemumgehung mit geringen Kosten durchzuführen.
Wenn der Kubernetes-Client http.DefaultClient , könnte dies behoben werden, indem der gesamte Kubernetes-Client neu erstellt wird.

Bei Watch-Anfrage wird es immer schlimmer. Der Kubernetes-Client scheint die Anfrage immer wieder zu versuchen und es wird kein Fehler in der oberen Anwendung angezeigt. Ich habe jetzt keine gute Vorstellung von einer solchen Situation.

Der hier vorgeschlagene Workaround funktioniert bei uns seit mehreren Wochen. Wir haben es in ein Python-Skript umgewandelt, das in allen unseren Clustern als Daemonset ausgeführt wird. Normalerweise werden ein- oder zweimal pro Woche Maßnahmen ergriffen (Kubelet automatisch neu gestartet) und wir haben dadurch keinen negativen Einfluss auf unseren Clusterbetrieb. Wir haben es variabel gemacht, damit es Kubelet nur neu startet, wenn es 2+ Nachrichten in einem Zeitraum von 5 Minuten sieht. Wir haben gesehen, dass wir gelegentlich eine Nachricht sehen konnten, und das war kein Problem. Wenn das Problem auftritt, sehen Sie ständig den Fehler use of closed network connection in den Kubelet-Protokollen.

Bitte erstellen Sie eine Pull-Anfrage und wir werden dieses Thema untersuchen.

Auf einem einzelnen Baremetal-Cluster beobachte ich, dass dies etwa 2-4 Mal alle 24 Stunden passiert. 1.17.12

Es passiert, wenn der API-Server-Pod neu gestartet wird, sogar auf einem Single-Node-Cluster. Die Verbindungen zum Apiserver gingen verloren, daher löst die Methode zur Minimierung der Fehlernummer das Problem, warum der Apiserver neu gestartet wird.

Ich verwende Haproxy vor dem Master-Knoten, glauben Sie, dass dies mit einer LB-Konfiguration irgendwie verhindert werden kann?

@shubb30 kannst du mir deine Lösung

Ich kann bestätigen, dass meine Apiserver NICHT neu gestartet werden, wenn das Problem auftritt. Ich verwende den Daemonset- und Shell-Trick, um den Log-Eintrag zu überwachen und dann Kubelet neu zu starten. Dies hat ziemlich gut funktioniert, aber ich sehe es nur als vorübergehende Problemumgehung.

Hier ist eine modifizierte Version von dem, was für uns als Workaround gut funktioniert hat.

Hallo alle!

Glauben wir möglicherweise, dass dieser Backport helfen könnte?
https://github.com/golang/go/issues/40423

Gute Nachrichten: golang/net master unterstützt die Konfiguration von http2-Transporten, was es nun ermöglicht, die Timeouts einzustellen! https://github.com/golang/net/commit/08b38378de702b893ee869b94b32f833e2933bd2

Fertig.
PR zur Überprüfung geöffnet.

Eine weitere gute Nachricht: Kubernetes verwendet das gebündelte http2 im Standardpaket net/http nicht, sodass wir nicht auf die nächste Go-Version warten müssen. Wir können https://github.com/golang/net/commit/08b38378de702b893ee869b94b32f833e2933bd2 direkt verwenden, um dieses Problem zu beheben.

Habe hier Abhilfe vorgeschlagen. https://github.com/kubernetes/kubernetes/pull/95898
Es aktualisiert die Abhängigkeit auf die erforderliche Version und aktiviert standardmäßig die http2-Transportzustandsprüfung.
Es sollte Anwendungen, die client-go verwenden, um mit einem apiserver zu kommunizieren (zB: kubelet), helfen, das Problem "app hang at write tcp xxx: use of closed connection" zu beseitigen.

Fühlen Sie sich frei, Kommentare zu hinterlassen.

Es scheint, dass die erwähnte Nr. 95898 aus Gründen geschlossen wurde, die wir nicht diskutieren müssen.

Gibt es ein anderes Update zu diesem Problem?

https://github.com/kubernetes/kubernetes/pull/95981 (oben verlinkt) ist im Gange, um den http/2-Fix einzufügen

Ist dieses Problem spezifisch für 1.17.X-Versionen von Kubernetes?

@krmayankk Nicht ganz sicher, wann es genau angefangen hat. Aber mindestens 1.17-1.19 haben dieses Problem. #95980 hätte es jedoch beheben sollen (wird Teil der nächsten Version 1.20 sein, hat es gestern nicht in die Beta geschafft)

@krmayankk Wir haben dieses Problem auch mit v1.18.9 gesehen, aber es wurde durch eine fehlerhafte Version von Rancher ausgelöst, die eine sehr hohe Netzwerkauslastung verursachte. Nach dem Zurücksetzen auf eine andere Version wurden keine Probleme festgestellt.

Ich hatte dieses Problem, aber ich habe es jetzt in meinem kleinen Hobby-Cluster mit der Problemumgehung in einem Kommentar oben "behoben".

Ich habe ein kleines ansible-Playbook geschrieben , um die Problemumgehung auf Knoten als Systemd-Einheit und Timer

Gibt es einen Plan, https://github.com/kubernetes/kubernetes/pull/95981 und https://github.com/kubernetes/kubernetes/issues/87615 auf den Release-Zweig 1.18 zurück zu portieren?

Gibt es einen Plan, den Release-Zweig #95981 bis 1.17 herauszupicken?

In diesem Kommentar werden Backports zu den älteren Versionen diskutiert: https://github.com/kubernetes/kubernetes/pull/95981#issuecomment -730561539

Ich denke, die Antwort ist "es ist hart und könnte Dinge kaputt machen, also wahrscheinlich nicht". Irgendwie die gleiche Antwort, die ich von Leuten erwarten würde, die v1.17 ausführen, wenn ich gefragt werde. Warum also nicht auf v1.20 aktualisieren, um den Fix zu erhalten? :Lachen:

Es wäre großartig, dies auf mindestens 1.19 zurückzuportieren, da dies die Korrektur relativ bald zur Verfügung stellen wird. Ich vermute, dass einige Leute wegen der Einstellung von Docker mit 1.20 warten werden.

Es wäre großartig, dies auf mindestens 1.19 zurückzuportieren, da dies die Korrektur relativ bald zur Verfügung stellen wird.

Das ist bereits geschehen.

Ich vermute, dass einige Leute wegen der Einstellung von Docker mit 1.20 warten werden.

In 1.20 hat sich in Bezug auf Docker nichts geändert, außer einer Veraltungswarnung. Am Ende des Einstellungszeitraums wird die Dockershim-Unterstützung entfernt.

bekomme diese Fehler auf 1.20 auf einem Raspbian 10. Wo fängt man überhaupt damit an, eine Lösung für all das zu finden? Es scheint, dass die Kosten für den Betrieb eines Cloud-verwalteten Clusters viel kostengünstiger sind als der Versuch, ihn auf Ihrem eigenen Cluster auszuführen

Für meine eigene Klarheit sieht dies so aus, als ob es von #95981 gelöst werden sollte, und das hat es in 1.20 geschafft und wurde auf 1.19 zurückportiert?

95981 wurde zu 1.20 zusammengeführt und in #96770 auf 1.19 hochgepflückt.

/nah dran

@caesarxuchao : Schließe dieses Problem.

Als Antwort darauf :

95981 wurde zu 1.20 zusammengeführt und in #96770 auf 1.19 hochgepflückt.

/nah dran

Anleitungen zur Interaktion mit mir über PR-Kommentare finden Sie hier . Wenn Sie Fragen oder Vorschläge zu meinem Verhalten haben, reichen Sie bitte ein Problem beim

Wird es einen Backport/Cherry Pick für v1.16, v1.17 oder oder v1.18 geben?

@chilicat siehe https://github.com/kubernetes/kubernetes/pull/95981#issuecomment -730561539. Ich habe nicht vor, es auf 1.18 oder ältere Versionen herauszupicken.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen