Kubernetes: (1.17) Kubelet no se volverá a conectar a Apiserver después de una falla en la NIC (uso de una conexión de red cerrada)

Creado en 28 ene. 2020  ·  123Comentarios  ·  Fuente: kubernetes/kubernetes

Acabamos de actualizar nuestro clúster de producción a 1.17.2.

Desde la actualización del sábado, hemos tenido esta extraña interrupción: Kubelet, después de una falla en el enlace NIC (que se recupera poco después), tendrá todas sus conexiones rotas y no volverá a intentar restablecerlas a menos que se reinicie manualmente.

Aquí está la línea de tiempo de la última vez que ocurrió:

01:31:16: Kernel reconoce una falla en la interfaz de enlace. Dura un rato. Eventualmente se recupera.

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

Como era de esperar, todos los relojes están cerrados. El mensaje es el mismo para todos ellos:

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

Entonces estos mensajes comienzan:

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

Lo cual supongo que no debería ser un problema por un tiempo. Pero nunca se recupera. Nuestro evento se produjo a las 01:31 a.m. y tuvo que reiniciar Kubelet manualmente alrededor de las 9 h para normalizar las cosas.

# 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

Los Apiservers estaban en funcionamiento, todos los demás nodos estaban en funcionamiento, todo lo demás transcurría sin incidentes. Este fue el único afectado (hoy) por este problema.

¿Existe alguna forma de mitigar este tipo de eventos?

¿Sería esto un error?

kinsupport siapi-machinery sinode

Comentario más útil

Lo solucioné ejecutando este script bash cada 5 minutos:

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

Todos 123 comentarios

/ sig nodo
/ sig api-maquinaria

Echando un vistazo al código, el error ocurre aquí.

La explicación del código es que asume su probablemente EOF (IsProbableEOF) mientras que en este caso no parece serlo.

/ asignar @caesarxuchao

@rikatz, ¿puedes explicar cómo rastreaste el código que pegaste?

Mi pensamiento es que el reflector habría reiniciado el reloj sin importar cómo manejara el error ( código ), por lo que no explica la falla en la recuperación.

Exactamente @caesarxuchao así que esta es nuestra pregunta.

Básicamente, rastreé el error a través del Código y crucé con lo que Kubelet estaba haciendo en ese momento (viendo secretos) para entrar en esa parte.

No es una forma avanzada, a través de esto parece ser el punto exacto del código de error.

La pregunta es, debido a que la conexión está cerrada, ¿hay algún lugar que indique que este es el reloj EOF en lugar de entender que se trata de un error?

No tengo nada más inteligente que agregar aparte de que tuvimos otro nodo fallando de la misma manera, aumentando las ocurrencias de los últimos 4 días a 4.

Intentará mapear si los eventos de desconexión de enlace están sucediendo en otros nodos y si kubelet se está recuperando; podría ser mala suerte en algunas recuperaciones, y no un evento del 100%.

Creo que también estamos viendo esto, pero no tenemos bonos, solo vemos estos mensajes de "operador perdido" en red para las interfaces Calico cali* , y son dispositivos veth locales.

También me he encontrado con esto, sin vínculos involucrados. Reiniciar el nodo soluciona el problema, pero el simple hecho de reiniciar el servicio de Kubelet no lo hace (todas las llamadas a la API fallan con "No autorizado").

También me he encontrado con esto, sin vínculos involucrados. Reiniciar el nodo soluciona el problema, pero el simple hecho de reiniciar el servicio de Kubelet no lo hace (todas las llamadas a la API fallan con "No autorizado").

Actualización: reiniciar Kubelet solucionó el problema después de que pasara el tiempo suficiente (¿1 hora?).

Veo este mismo comportamiento. Instalaciones limpias de Ubuntu 18.04.3 LTS. Clúster construido con rancher 2.3.4. He visto que esto sucede periódicamente últimamente y el simple hecho de reiniciar Kubelet tiende a solucionarlo por mí. Anoche, los 3 de mis nodos trabajadores exhibieron este mismo comportamiento. Corrigí 2 para activar mi clúster. El tercero todavía está en este estado mientras estoy investigando.

estamos viendo el mismo problema en CentOS 7, clúster recién construido con rancher (1.17.2). Estamos usando tejido. Los 3 nodos trabajadores muestran este problema. Reiniciar kubelet no nos funciona tenemos que reiniciar todo el nodo

/ sig nodo
/ sig api-maquinaria

Echando un vistazo al código, el error ocurre aquí.

La explicación del código es que asume su probablemente EOF (IsProbableEOF) mientras que en este caso no parece serlo.

También estamos viendo el mismo problema. A partir del registro, descubrimos que después de que se produjo el problema, todas las solicitudes posteriores se enviaron en la misma conexión. Parece que, aunque el cliente volverá a enviar la solicitud a apiserver, la biblioteca http2 subyacente aún mantiene la conexión anterior, por lo que todas las solicitudes posteriores aún se envían en esta conexión y reciben el mismo error use of closed connection .

Entonces, la pregunta es ¿por qué http2 todavía mantiene una conexión ya cerrada? ¿Quizás la conexión que mantuvo está realmente viva, pero algunas conexiones intermedias se cierran inesperadamente?

Tengo el mismo problema con un clúster Raspberry Pi con k8s 1.17.3 muy a menudo. Basándome en algunos problemas anteriores, establecí el límite de conexión http del servidor API de kube en 1000 "- --http2-max-streams-per-connection = 1000", estuvo bien durante más de 2 semanas después de eso, comienza ahora de nuevo.

¿Es posible reconstruir kube-apiserver https://github.com/kubernetes/apiserver/blob/b214a49983bcd70ced138bd2717f78c0cff351b2/pkg/server/secure_serving.go#L50
estableciendo s.DisableHTTP2 en true por defecto?
¿Existe un archivo docker para una imagen oficial ( k8s.gcr.io/kube-apiserver:v1.17.3 )?

lo mismo aquí. (ubuntu 18.04, kubernetes 1.17.3)

También observamos esto en dos de nuestros grupos. No estoy completamente seguro de la causa raíz, pero al menos pudimos ver que esto sucedió en un clúster con conteos de relojes muy altos. Sin embargo, no pude reproducir al forzar una gran cantidad de relojes por kubelet (iniciamos pods con 300 secretos por pod, lo que también resultó en 300 relojes por pod en las métricas de Prometheus). Además, establecer valores muy bajos de http2-max-streams-per-connection no desencadenó el problema, pero al menos pude observar un comportamiento inesperado del programador y del controlador-administrador (podría haber sido solo una sobrecarga después de bucles de repetición interminables o algo como esto, aunque).

Como solución provisional, todos mis nodos se reinician todas las noches kublet a través de cronjob local. Ahora, después de hace 10 días, puedo decir que funciona para mí, no tengo más "uso de conexión de red cerrada" en mis nodos.

@sbiermann
Gracias por publicar esto. ¿Qué intervalo de tiempo usas para cronjob?

24 horas

También puedo confirmar este problema, todavía no estamos en 1.17.3, actualmente ejecutando 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

También puedo confirmar esto en Kubernetes 1.17.4 implementado a través de Rancher 2.3.5 en los nodos de RancherOS 1.5.5. Reiniciar el kubelet parece funcionar para mí, no tengo que reiniciar todo el nodo.

La causa subyacente para mí parece ser que la RAM está a punto de agotarse y kswapd0 obtiene hasta el 100% de uso de la CPU debido a eso, ya que olvidé establecer el intercambio en 0 para mis nodos de Kubernetes. Después de configurar el intercambio en 0 y agregar algo de RAM a las máquinas, el problema no me ha vuelto a ocurrir todavía.

Si el problema subyacente era "http2 usando conexiones muertas", reiniciar kubelet debería solucionar el problema. https://github.com/kubernetes/kubernetes/pull/48670 sugirió que reducir TCP_USER_TIMEOUT puede mitigar el problema. Abrí https://github.com/golang/net/pull/55 para agregar la verificación del estado de la conexión del lado del cliente a la biblioteca http2, pero me llevará más tiempo aterrizar.

Si reiniciar kubelet no resolvió el problema, probablemente sea una causa raíz diferente.

Tengo el mismo problema con v1.17.2 cuando reinicio la red, pero solo uno de los nodos tiene este problema (mi clúster tiene cinco nodos), no puedo reproducirlo. Reiniciar kubelet resolvió este problema.

¿Cómo puedo evitar este problema? ¿Actualizar la última versión o tiene otra forma de solucionarlo?

Lo solucioné ejecutando este script bash cada 5 minutos:

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

He creado un parche sin reiniciar kubelet y parece que el problema está resuelto.
parche de fecha límite

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 ¿Puede explicar cómo reconstruir el cliente-go?

@mYmNeo ¿Puede explicar cómo reconstruir el cliente-go?

@ ik9999 Aplicar este parche, luego reconstruir kubelet y reemplazar el binario

@mYmNeo ¿Cómo puedo reproducir este problema y probarlo?

Lo solucioné ejecutando este script bash cada 5 minutos

@ ik9999 Gracias, funciona.

cc @liggitt

¿Establecer SetReadDeadline significa que todos los relojes se cerrarán cada 30 segundos?

¿Establecer SetReadDeadline significa que todos los relojes se cerrarán cada 30 segundos?

Si. Es una forma fea de resolver este problema (forzar el cierre de una conexión).

Solo otro caso:

También estamos viendo esto en los clústeres de Kube 1.16.8. El reinicio de la máquina virtual se puede utilizar para devolver el nodo a un buen estado (sospecho que un reinicio de Kubelet también habría funcionado).

Nuestro kubelet de configuración habla con una instancia de haproxy local a través de localhost que actúa como un balanceador de carga tcp para las múltiples instancias maestras de backend. Vamos a investigar si agrega

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

Para nuestras instancias de equilibrador de carga, ayuda a aliviar la necesidad del reinicio explícito y puede conducir a una recuperación completa. Ejemplo de registros repetidos

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

Publicaremos una actualización si eso resuelve nuestro problema específico en caso de que ayude a alguien aquí en el ínterin.

¿Tiene curiosidad si hay un parámetro de configuración para establecer un límite superior absoluto en un tiempo de visualización? Encontré --streaming-idle-connection-timeout pero nada específico para los relojes.

Estamos viendo esto en kube 1.17.4 después de que el servidor de la API no funcionara debido a "etcd falló: motivo oculto".

Hola tios. He recompilado el binario de kubernetes con golang 1.14. Parece que el problema desapareció

@mYmNeo golang 1.14 + kubernetes v1.17?

@mYmNeo golang 1.14 + kubernetes v1.17?

@pytimer Estamos usando 1.16.6 sin cambiar ningún código, solo recompilando. Creo que la causa principal puede ser golang.

¡Oye! Tengo el mismo problema aquí, k8s 1.17.4 ¿creemos que podríamos obtener un 1.17.5 recompilado con go 1.14 si eso resuelve el problema?

Desafortunadamente, la actualización a go1.14 requiere actualizaciones de varios componentes clave, por lo que es poco probable que vuelva a Kube 1.17. Puede realizar un seguimiento de los problemas y el progreso en https://github.com/kubernetes/kubernetes/pull/88638

Es bueno saberlo, gracias

@callicles ¿ se ha confirmado que la recompilación con go 1.14 resolvió el problema?

Veo un problema idéntico en 1.16.8: de vez en cuando (a veces una vez cada dos días, a veces cada dos semanas) el nodo se vuelve NotReady, por lo que Kubelet dejó de publicar el estado del nodo y el "uso de una conexión de red cerrada". llenando los troncos

ir puede tener problemas para tratar con la actualización de 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
        }

Hola tios. He recompilado el binario de kubernetes con golang 1.14. Parece que el problema desapareció

@mYmNeo, ¿alguna vez ha reproducido el problema después de volver a compilar con go 1.14?

Hola tios. He recompilado el binario de kubernetes con golang 1.14. Parece que el problema desapareció

@mYmNeo, ¿alguna vez ha reproducido el problema después de volver a compilar con go 1.14?

AFAIN, el problema ya no existe.

Desafortunadamente, la actualización a go1.14 requiere actualizaciones de varios componentes clave, por lo que es poco probable que vuelva a Kube 1.17. Puede realizar un seguimiento de los problemas y el progreso en # 88638

¿Ya sabe si go1.14 se volverá a exportar a 1.18?

¿Ya sabe si go1.14 se volverá a exportar a 1.18?

No lo esperaba. Parece que se requieren cambios en etcd y bbolt para admitir go1.14, que es un cambio mayor que el que se realiza normalmente en las ramas de lanzamiento.

@liggitt Está bien gracias. Parece que nosotros (al menos para nuestros clústeres) necesitamos una estrategia de mitigación mientras tanto :)

¿Este problema solo ocurre después de una falla de NIC? Estamos viendo el mismo mensaje de error en nuestros clústeres v1.16.8, pero no hay ninguna falla NIC asociada.

Tuvimos al menos una instancia en la que la VM subyacente tuvo un error SCSI al conectarse a una SAN. El problema de SCSI se resolvió solo, pero el kubelet nunca se recuperó.

La opción --goaway-chance se agregó en 1.18 (# 88567). ¿Esta opción aliviará este problema?

No. Eso solo tiene efecto si el kubelet puede llegar al servidor API y obtener una respuesta.

un enlace NIC falla (que se recupera poco después), se romperán todas sus conexiones y no volverá a intentar restablecerlas a menos que se reinicie manualmente.

¿Puede decirnos qué modo de enlace está utilizando? No puedo reproducir esto en mi clúster con enlaces de respaldo activo.

Después de actualizar a Kubernetes 1.16, también comenzamos a ver el error use of closed network connection y kubelet no se volvía a conectar al apiserver, lo que dejaba a los nodos bloqueados en NotReady. No pudimos reproducir el problema eliminando las NIC (configurando los enlaces hacia abajo / hacia arriba), pero notamos que este comportamiento solo sucedía en clústeres que estaban más cargados.

Investigamos más y descubrimos que el en golang es 250 secuencias http2 por cliente , mientras que el valor predeterminado del lado del --http2-max-streams-per-connection=1000 , no vimos el problema de que los nodos se atasquen en NotReady tanto como se encontró originalmente durante las pruebas. Esto no resolvió el problema de que kubelet no se volviera a conectar, pero nos ayudó a mitigar el problema que estábamos viendo.

Después de actualizar a Kubernetes 1.16, también comenzamos a ver el error use of closed network connection y kubelet no se volvía a conectar al apiserver, lo que dejaba a los nodos bloqueados en NotReady. No pudimos reproducir el problema eliminando las NIC (configurando los enlaces hacia abajo / hacia arriba), pero notamos que este comportamiento solo sucedía en clústeres que estaban más cargados.

Investigamos más y descubrimos que el en golang es 250 secuencias http2 por cliente , mientras que el valor predeterminado del lado del --http2-max-streams-per-connection=1000 , no vimos el problema de que los nodos se atasquen en NotReady tanto como se encontró originalmente durante las pruebas. Esto no resolvió el problema de que kubelet no se volviera a conectar, pero nos ayudó a mitigar el problema que estábamos viendo.

Hola, los flujos https predeterminados del lado del servidor son 1000 en kube-apiserver, esto es igual al valor del cliente.
https://github.com/kubernetes/kubernetes/blob/ae1103726f9aea1f9bbad1b215edfa47e0747dce/staging/src/k8s.io/apiserver/pkg/server/options/recommended.go#L62

@warmchang Creo que esto se aplica a apiextensions apiservers y apiserver de muestra:
https://github.com/kubernetes/kubernetes/blob/ae1103726f9aea1f9bbad1b215edfa47e0747dce/staging/src/k8s.io/apiserver/pkg/server/options/recommended.go#L62

Una prueba con prueba de curl sin configurar --http2-max-streams-per-connection tiene esto en nuestros registros de apiserver (usando v1.16):
I0603 10:18:08.038531 1 flags.go:33] FLAG: --http2-max-streams-per-connection="0"

Y una solicitud de curl muestra esto en la respuesta:
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!

Cuando uso --http2-max-streams-per-connection=1000 la solicitud de curl se muestra
* Connection state changed (MAX_CONCURRENT_STREAMS == 1000)!

@jmcmeek @treytabner , tienes razón. Leí mal el código. : +1:

Usando kubernetes 1.17.6 y lo mismo aquí. Parece que kubelet está usando una conexión http2 muerta.
Me di cuenta de que el valor predeterminado inconsistente de MAX_CONCURRENT_STREAMS entre kube-apiserver y kubelet.

Simplemente establezca el valor del lado del servidor en 1000. Se informará más tarde.

Ganadero / RKE

Agregar a la definición de clúster:

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

Verifique el nodo maestro:

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

Establecer MAX_CONCURRENT_STREAMS en 1000 en APIserver no tiene ningún efecto en este problema.
Creo que esto se debe a una falla en golang http2 Transport . Véase más arriba

Tuve este problema nuevamente esta noche.
Parece que configurar 'MAX_CONCURRENT_STREAMS' no ayudó☹️

Hola tios. Creo que finalmente he localizado este problema. Tenemos el mismo problema que sucedió anoche. Pero se recuperó con éxito con un kubelet modificado.

No es un error de Kubernetes, se trata del paquete net/http estándar de golang que también está usando client-go .
Creo que hay una falla en golang.org/x/net/http2/transport.go

Ya he informado de esto al funcionario de golang. Esperando alguna discusión.
https://github.com/golang/go/issues/39750

Por ahora modifiqué el código para tener el http2: perform connection health check introducido por https://github.com/golang/net/commit/0ba52f642ac2f9371a88bfdde41f4b4e195a37c0 habilitado de forma predeterminada.
Demuestra ser de alguna ayuda en este problema. Pero respondió un poco lento.

registros de kubelet v1.17.6 (cumplidos con el paquete golang.org/x/net auto-modificado)

Se recuperó del problema de escribir conexiones muertas, pero costó un poco más de tiempo de lo esperado.

Tenga en cuenta que performing http2 healthCheck es un mensaje de registro que tenía la intención de dejar allí para probar healthCheck func es llamado por readIdleTimer

 23 de junio 03:14:45 vm10.company.com kubelet [22255]: E0623 03: 14: 45.912484 22255 kubelet_node_status.go: 402] Error al actualizar el estado del nodo, volverá a intentarlo: error al obtener el nodo "vm10.company.com": Obtener "https://vm10.company.com:8443/api/v1/nodes/vm10.company.com?timeout=10s": escriba tcp 16.155.199.4:39668->16.155.199.4:8443: uso de una conexión de red cerrada
 23 de junio 03:14:45 vm10.company.com kubelet [22255]: E0623 03: 14: 45.912604 22255 kubelet_node_status.go: 402] Error al actualizar el estado del nodo, volverá a intentarlo: error al obtener el nodo "vm10.company.com": Obtener "https://vm10.company.com:8443/api/v1/nodes/vm10.company.com?timeout=10s": escriba tcp 16.155.199.4:39668->16.155.199.4:8443: uso de una conexión de red cerrada
 23 de junio 03:14:45 vm10.company.com kubelet [22255]: E0623 03: 14: 45.912741 22255 kubelet_node_status.go: 402] Error al actualizar el estado del nodo, volverá a intentarlo: error al obtener el nodo "vm10.company.com": Obtener "https://vm10.company.com:8443/api/v1/nodes/vm10.company.com?timeout=10s": escriba tcp 16.155.199.4:39668->16.155.199.4:8443: uso de una conexión de red cerrada
 23 de junio 03:14:46 vm10.company.com kubelet [22255]: E0623 03: 14: 46.367046 22255 controller.go: 135] no pudo garantizar que exista la concesión del nodo, se reintentará en 400ms, error: Get "https: // vm10.company.com:8443/apis/coordination.k8s.io/v1/namespaces/kube-node-lease/leases/vm10.company.com?timeout=10s ": escriba tcp 16.155.199.4:39668->16.155. 199.4: 8443: uso de una conexión de red cerrada
 23 de junio 03:14:48 vm10.company.com kubelet [22255]: E0623 03: 14: 47.737579 22255 controller.go: 135] no pudo garantizar que exista la concesión del nodo, se reintentará en 800ms, error: Get "https: // vm10.company.com:8443/apis/coordination.k8s.io/v1/namespaces/kube-node-lease/leases/vm10.company.com?timeout=10s ": escriba tcp 16.155.199.4:39668->16.155. 199.4: 8443: uso de una conexión de red cerrada
 23 de junio 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: No se pudo incluir en la lista * v1.Node: Obtenga "https://vm10.company.com:8443/api/v1/nodes?fieldSelector=metadata.name%3Dvm10.company.com&limit=500&resourceVersion=0": escriba tcp 16.155.199.4:39668-> 16.155.199.4:8443: uso de conexión de red cerrada
 23 de junio 03:14:49 vm10.company.com kubelet [22255]: E0623 03: 14: 48.744770 22255 reflector.go: 153] object- "kube-system" / "flannel-token-zvfwn": No se pudo enumerar * v1.Secret: Obtenga "https://vm10.company.com:8443/api/v1/namespaces/kube-system/secrets?fieldSelector=metadata.name%3Dflannel-token-zvfwn&limit=500&resourceVersion=0": escriba tcp 16.155 .199.4: 39668-> 16.155.199.4:8443: uso de conexión de red cerrada
 23 de junio 03:14:49 vm10.company.com kubelet [22255]: E0623 03: 14: 49.599631 22255 reflector.go: 153] object- "kube-system" / "coredns": No se pudo enumerar * v1.ConfigMap: Obtenga "https://vm10.company.com:8443/api/v1/namespaces/kube-system/configmaps?fieldSelector=metadata.name%3Dcoredns&limit=500&resourceVersion=0": escriba tcp 16.155.199.4:39668->16.155. 199.4: 8443: uso de una conexión de red cerrada
 23 de junio 03:14:49 vm10.company.com kubelet [22255]: E0623 03: 14: 49.599992 22255 controller.go: 135] no pudo garantizar que exista la concesión del nodo, se reintentará en 1.6 s, error: Get "https: / /vm10.company.com:8443/apis/coordination.k8s.io/v1/namespaces/kube-node-lease/leases/vm10.company.com?timeout=10s ": escriba tcp 16.155.199.4:39668->16.155 .199.4: 8443: uso de conexión de red cerrada
 23 de junio 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: No se pudo incluir en la lista * v1.Service: Obtenga "https://vm10.company.com:8443/api/v1/services?limit=500&resourceVersion=0": escriba tcp 16.155.199.4:39668->16.155.199.4:8443: uso de red cerrada conexión
 23 de junio 03:14:49 vm10.company.com kubelet [22255]: E0623 03: 14: 49.600323 22255 reflector.go: 153] objeto- "kube-system" / "kube-flannel-cfg": No se pudo enumerar * v1.ConfigMap: Obtenga "https://vm10.company.com:8443/api/v1/namespaces/kube-system/configmaps?fieldSelector=metadata.name%3Dkube-flannel-cfg&limit=500&resourceVersion=0": escriba tcp 16.155 .199.4: 39668-> 16.155.199.4:8443: uso de conexión de red cerrada
 23 de junio 03:14:49 vm10.company.com kubelet [22255]: E0623 03: 14: 49.600463 22255 reflector.go: 153] object- "core" / "registrypullsecret": No se pudo enumerar * v1.Secret: Get " https://vm10.company.com:8443/api/v1/namespaces/core/secrets?fieldSelector=metadata.name%3Dregistrypullsecret&limit=500&resourceVersion=0 ": escriba tcp 16.155.199.4:39668->16.155.199.4:8443: uso de conexión de red cerrada
 23 de junio 03:14:49 vm10.company.com kubelet [22255]: E0623 03: 14: 49.369097 22255 reflector.go: 153] objeto- "kube-system" / "registrypullsecret": No se pudo enumerar * v1.Secret: Obtenga "https://vm10.company.com:8443/api/v1/namespaces/kube-system/secrets?fieldSelector=metadata.name%3Dregistrypullsecret&limit=500&resourceVersion=0": escriba tcp 16.155.199.4:39668->16.155. 199.4: 8443: uso de una conexión de red cerrada
 23 de junio 03:25:39 vm10.company.com kubelet [22255]: E0623 03: 25: 39.543880 22255 desire_state_of_world_populator.go: 320] Error al procesar el volumen "deployment-log-dir" para el pod "fluentd-h76lr_core (e95c9200-3a0c -4fea-bd7f-99ac1cc6ae7a) ": error al procesar el núcleo de PVC / itom-vol-Claim: no se pudo recuperar el PVC del servidor API: Obtenga" https://vm10.company.com:8443/api/v1/namespaces/core/ persistentvolumeclaims / itom-vol-Claim ": lea tcp 16.155.199.4:41512->16.155.199.4:8443: uso de una conexión de red cerrada
 23 de junio 03:25:39 vm10.company.com kubelet [22255]: E0623 03: 25: 39.666303 22255 kubelet_node_status.go: 402] Error al actualizar el estado del nodo, volverá a intentarlo: no se pudo parchear el estado "{\" status \ ": {\ "$ setElementOrder / conditions \": [{\ "type \": \ "MemoryPressure \"}, {\ "type \": \ "DiskPressure \"}, {\ "type \": \ "PIDPressure \ "}, {\" tipo \ ": \" Listo \ "}], \" condiciones \ ": [{\" lastHeartbeatTime \ ": \" 2020-06-22T19: 25: 29Z \ ", \" tipo \ ": \" MemoryPressure \ "}, {\" lastHeartbeatTime \ ": \" 2020-06-22T19: 25: 29Z \ ", \" tipo \ ": \" DiskPressure \ "}, {\" lastHeartbeatTime \ ": \ "2020-06-22T19: 25: 29Z \", \ "tipo \": \ "PIDPressure \"}, {\ "lastHeartbeatTime \": \ "2020-06-22T19: 25: 29Z \", \ " escriba \ ": \" Ready \ "}]}}" para el nodo "vm10.company.com": Parche "https://vm10.company.com:8443/api/v1/nodes/vm10.company.com/ status? timeout = 10s ": leer tcp 16.155.199.4:41512->16.155.199.4:8443: uso de una conexión de red cerrada
 23 de junio 03:25:49 vm10.company.com kubelet [22255]: E0623 03: 25: 49.553078 22255 kubelet_node_status.go: 402] Error al actualizar el estado del nodo, volverá a intentarlo: error al obtener el nodo "vm10.company.com": Obtener "https://vm10.company.com:8443/api/v1/nodes/vm10.company.com?timeout=10s": lea tcp 16.155.199.4:41718->16.155.199.4:8443: uso de una conexión de red cerrada
 23 de junio 03:25:49 vm10.company.com kubelet [22255]: E0623 03: 25: 49.560723 22255 desire_state_of_world_populator.go: 320] Error al procesar el volumen "log-location" para el pod "fluentd-h76lr_core (e95c9200-3a0c-4fea -bd7f-99ac1cc6ae7a) ": error al procesar el núcleo de PVC / itom-logging-vol: no se pudo recuperar el PVC del servidor API: Obtenga" https://vm10.company.com:8443/api/v1/namespaces/core/persistentvolumeclaims/ itom-logging-vol ": lea tcp 16.155.199.4:41718->16.155.199.4:8443: uso de una conexión de red cerrada
 23 de junio 03:27:29 vm10.company.com kubelet [22255]: I0623 03: 27: 29.961600 22255 log.go: 181] realizando http2 healthCheck
 23 de junio 03:31:32 vm10.company.com kubelet [22255]: I0623 03: 31: 31.829860 22255 log.go: 181] realizando http2 healthCheck
 23 de junio 03:31:44 vm10.company.com kubelet [22255]: I0623 03: 31: 44.570224 22255 log.go: 181] realizando http2 healthCheck
 23 de junio 03:32:13 vm10.company.com kubelet [22255]: I0623 03: 32: 12.961728 22255 log.go: 181] realizando http2 healthCheck
 23 de junio 03:33:16 vm10.company.com kubelet [22255]: I0623 03: 33: 15.441808 22255 log.go: 181] realizando http2 healthCheck
 23 de junio 03:33:28 vm10.company.com kubelet [22255]: I0623 03: 33: 28.233121 22255 log.go: 181] realizando http2 healthCheck

no más use of closed network connection reportados y kubelet regresa al estado Listo

Tenemos algunos nuevos conocimientos potenciales sobre el problema en nuestras pilas. Con cierta confianza, asumimos una caída de conexión poco común en el nivel de red / infraestructura debido a la alta carga con respecto a los números de conexión en situaciones específicas, por lo que en nuestro caso no se trataba de cambios en las interfaces de red. Especialmente tuvimos problemas graves con la federación de Prometheus debido a esto, ya que cambiaron a http2 en el lado del cliente . Habilitar el monitor de salud http2 configurando http2.Transport.ReadIdleTimeout como se implementó con golang/net#55 resolvió por completo los problemas de federación para nosotros.

Actualmente, los valores no están expuestos, ya que apimachinery/pkg/util/net/http.go crea http.Transport y actualiza esto a http2 internamente, que no expone la opción hasta que se fusiona golang / net # 74.

¿Existen otras soluciones además del trabajo cron de reinicio de kubelet? Hemos tenido un trabajo cron en su lugar durante una semana y no ha impedido que ocurra el problema.

Tengo el mismo problema en v1.17.3.

Lo que encontré es que la versión k8s que usa una versión específica golang.org/x/net está en problemas, y este paquete parece estar arreglado.
https://go-review.googlesource.com/c/net/+/198040

Versión con este problema (v1.16.5 ~ última versión)
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9

Versión fija (rama maestra)
golang.org/x/net v0.0.0-20200707034311-ab3426394381

¿La actualización del paquete golang.org/x/net solucionará este problema?

¿Hay un lanzamiento previsto para la versión mantenida de k8s (v1,16, 1.17, v1,18 ..) para solucionar este problema?

Lo que encontré es que la versión k8s que usa una versión específica golang.org/x/net está en problemas, y este paquete parece estar arreglado.
https://go-review.googlesource.com/c/net/+/198040

El cambio mencionado solo _ofrece_ la posibilidad de habilitar el monitor de salud HTTP2, pero los desarrolladores deben habilitarlo (el valor predeterminado está desactivado). Además, no se puede configurar realmente, pero hay una solicitud de extracción para dar acceso a los desarrolladores al monitor de salud .

Actualmente estoy integrando una revisión basada en la reflexión que habilita el monitor de estado para nuestra propia distribución de Kubernetes, con la esperanza de que esto ayude a resolver el problema.

-
Jens Erat \ Imprimir

@JensErat gracias por la respuesta.
Si es así, ¿este problema también puede ocurrir en versiones anteriores de k8s (1.13, 1.15, ..)?

Cambié la distribución de nodos de RancherOS (kernel 4.14.138) a Ubuntu 18.04 (kernel 5.3.0) hace más de un mes, el problema no ha aparecido desde entonces.
Uno de mis clústeres quedó en RancherOS, ya se ha reproducido este problema 3 veces.

No es 100% seguro, pero probablemente la versión del kernel sea importante.

Difícil de decir. Definitivamente observamos (d) el problema con 1.16 a 1.18, pero antes había raras ocasiones raras "kubelet atascadas". Ya hemos investigado estos problemas desde hace al menos un año, pero nunca pudimos correlacionar nada (incidentes únicos todas las pocas semanas, y tenemos una cantidad de cuatro dígitos de kubelets en ejecución). Sin embargo, empeoró mucho desde que instalamos 1.16, pero actualmente estamos más interesados ​​en asumir que los problemas de red subyacentes (también muy raros y difíciles de rastrear ...) ocurren con más frecuencia. Estamos ejecutando Ubuntu 19.10 con Kernel 5.3.0-46-generic, pero estamos afectados (es muy posible que tengas un nivel de parche más nuevo). ¿Puede darnos una pista de qué versión de kernel / nivel de parche exacto está ejecutando?

-
Jens Erat \ Imprimir

Es 5.3.0-59-generic . Pero solo tenemos ~ 40 kubletes, por lo que aún podría ser una coincidencia.

Como dije anteriormente. Este problema ocurre con más frecuencia en clústeres con mucha carga. Observamos el mismo problema casi todas las noches antes de habilitar el HealthCheck de transporte de H2.
De acuerdo con el problema informado al funcionario de golang . El problema ocurre en el bucle de lectura del socket, que debería devolver un error al leer el socket cerrado, pero nunca lo hace. Además, sugiero agregar lógica de manejo de errores en el socket de escritura para detectar activamente el problema de conexión. Pero varios días después, parece que no les importan cuestiones tan raras.

Un poco lejos del tema, quiero decir, ya que el problema es causado por un conector de red que se acerca mucho al kernel. Actualizar el kernel puede ayudar, o no. (PD: estamos usando centos 7 con kernel 3.10, sucede casi todos los días antes de habilitar HealthCheck)
Pasé alrededor de 3 días leyendo el código fuente de net / http, por lo que vi, habilitar h2 transport healthCheck debería ayudar a recuperarme de tal problema, y ​​realmente escapamos de esta extraña situación al hacerlo.
@JensErat ¿Tiene alguna prueba concreta de que la habilitación de HealthCheck ayude a resolver este problema?

@JensErat ¿Tiene alguna prueba concreta de que la habilitación de HealthCheck ayude a resolver este problema?

Ejecutamos la federación de Prometheus para cada uno de nuestros clústeres de Kubernetes. Prometheus 2.19.0 introdujo http2 (sin embargo, se olvidan de mencionar esto en el registro de cambios y lo tenían bien oculto en el cuerpo de un mensaje de confirmación, tuve que bisecar, implementar y esperar algunas horas para cada ejecución ...) y observamos acerca de una docena de incidentes con federación estancados por día. Primero parcheé el soporte de http2 nuevamente (y el problema desapareció), y luego configuré el tiempo de espera de lectura directamente en golang / net / x / http2. Desde entonces, ya no hemos tenido un solo incidente de caída de federación.

Actualmente me estoy preparando para implementar una versión de Kubernetes parcheada en algunos clústeres, por lo que deberíamos tener datos en unos días. Definitivamente compartiremos nuestros resultados tan pronto como tengamos los datos adecuados.

-
Jens Erat \ Imprimir

Actualmente me estoy preparando para implementar una versión de Kubernetes parcheada en algunos clústeres, por lo que deberíamos tener datos en unos días. Definitivamente compartiremos nuestros resultados tan pronto como tengamos los datos adecuados.

Gracias por tus comentarios. Ese es un mensaje muy delicioso.
Aunque la causa raíz no está muy clara, al menos encontramos una manera de recuperarnos de un desastre. :D

Tenemos el mismo problema con k8s v1.14.3, y reiniciar kubelet puede solucionar el problema.

Sé que esto es una tontería, pero debe funcionar como una solución temporal:

Expandir 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


(Esto es específico del ganadero, pero se puede adaptar fácilmente a otras distribuciones mediante el uso de contenedor privilegiado y journalctl / systemctl)

La cantidad de tiempo para sleep y --since debe ser menor que el pod-eviction-timeout del clúster (5 millones de forma predeterminada)

Por cierto, docker pause nginx-proxy en el nodo trabajador del ranchero hace que kubelet produzca el mismo mensaje de error.

Solución temporal para aquellos que ejecutan K8S en VMWare vSphere: deshabilite DRS para las máquinas virtuales K8S, que evitará que vSphere mueva las máquinas virtuales entre hipervisores, eliminando así cualquier desconexión de red que esté causando problemas a los Kubelet.

Tenemos muy buenas noticias con respecto a la mitigación del problema con la nueva función de verificación de estado http2 de golang: ya no hay problemas. A estas alturas, implementamos la "corrección" (configuración codificada del valor en el código vendido x/net ) en Prometheus, Kubernetes completo y varios componentes internos, observando:

  • ya no hay problemas de la federación de Prometheus
  • kubelet a veces todavía informa eventos únicos de "uso de conexión cerrada", pero se recupera en segundos (establecemos una ventana de verificación de salud http2 de ~ 30 segundos)
  • a veces tuvimos problemas con los relojes kubectl; también desaparecieron si usábamos kubectl parcheado
  • estamos ejecutando un conjunto de pruebas E2E extendido para verificar nuestra integración con regularidad, y observamos tiempos de espera de prueba esporádicos y escasez. ¿Adivina qué? Se ha ido ahora.

Además, hemos podido obtener nuevos conocimientos sobre cómo desencadenar los problemas. Puedo confirmar la observación de @ vi7 con respecto a la migración en vivo con cierta confianza (aunque podríamos rastrearla), y al menos con la versión de NSX que estamos ejecutando, los cambios en el balanceador de carga pueden desencadenar tales problemas (tenemos un ticket con VMware para asegúrese de que están enviando paquetes de reinicio en el futuro). Y es muy probable que haya muchas otras razones por las que se caigan las conexiones intermedias, como los desbordamientos de la tabla de conexiones.

Este es un problema muy molesto y algo masivo para algunos usuarios de Kubernetes (dependiendo de algún tipo de "ruptura" de la capa / red de IaaS, supongo). Aunque hay discusiones de golang sobre la exposición de una interfaz para establecer correctamente los valores, ¿cree que hay alguna posibilidad de que un PR fusionado en sentido ascendente establezca esos valores a través de la reflexión (aún mejor que bifurcar x / net, supongo que como lo hacemos ahora) ? Estamos de acuerdo con proporcionar el código (y validar la corrección, no podemos reproducirlo, pero obsérvelo con la suficiente frecuencia para poder confirmar si la corrección funciona).

cc @liggitt

problema a largo plazo (nota personal)

@JensErat gracias por la respuesta.
Si es así, ¿este problema también puede ocurrir en versiones anteriores de k8s (1.13, 1.15, ..)?

Puedo confirmar para ver el problema con Kubernetes v1.16.13
No vimos el problema con Kubernetes v1.15.9

cuando restauro un clúster de kubenetes v1.16.14 de la copia de seguridad de la instantánea de etcd. este error aparece en el registro de kubelet.
gracias a @ ik9999 . Reinicio el kubelet y luego los errores desaparecen

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

Encontramos el mismo problema en 1.17.3, reiniciar Kubelet se resolverá. ¿Alguna solución alternativa estable o cuándo se solucionará?

v1.18.6 mismo

@ rxwang662001
Esto se debe a un problema de golang ascendente. Una cosa para estar seguro es que esto NO se solucionará en la versión 1.15.
Mientras tanto, la comunidad de Kubernetes todavía está luchando para migrar a 1.14 LOL.

Por lo general, realice lanzamientos cada 6 meses. Si todo funciona bien, tal vez podríamos ver este problema resuelto en el proceso ascendente el próximo año, y tal vez otro año hasta que Kubernetes adpate la solución 🥇.
(Solo para bromear. Si realmente quieres que esto se arregle en tu pila ahora mismo. Hackear h2Transport para habilitar healthCheck demostró estar funcionando.

Mientras tanto, la comunidad de Kubernetes todavía está luchando para migrar a 1.14 LOL.

En realidad, debido al gran trabajo de sig-scalability y sig-release para calificar en las versiones preliminares de go1.15, Kubernetes 1.19 acaba de lanzarse en go1.15. Parece que hay trabajo en progreso para exponer las opciones http / 2 en go1.16, y espero que hagamos uso de eso tan pronto como esté disponible.

En realidad, debido al gran trabajo de sig-scalability y sig-release para calificar en las versiones preliminares de go1.15, Kubernetes 1.19 acaba de lanzarse en go1.15.

Opps. Perdón por la broma incómoda. No presté mucha atención a la versión v1.19.
¿Parece que nos saltamos go1.14 por completo en K8S? Guau. eso es un gran salto 👍

@povsister

Gracias por compartir su solución. ¿Podrías agregar más detalles sobre cómo lo hiciste funcionar?

Por ahora modifiqué el código para tener el http2: perform connection health check introducido por golang / net @ 0ba52f6 habilitado de forma predeterminada.
Demuestra ser de alguna ayuda en este problema. Pero respondió un poco lento.

¿Qué cambios de código pusiste en práctica? ¿Y dónde, en qué archivo?

@KarthikRangaraju
Consulte este PR para habilitar HealthCheck al inicializar h2Transport,
o puede hacer algún truco de reflexión / compensación insegura para acceder a un campo no exportado en tiempo de ejecución.

Y no olvide actualizar golang / x / net antes de hacer esas cosas.

No hemos podido reproducir este problema, aunque lo enfrentamos de vez en cuando.

Dado que no podemos identificar la causa raíz del síntoma, lo estamos arreglando independientemente.

Nuestra solución:

  • El siguiente script se ejecuta cada 1 hora. Habla con el servidor kube-api a través de kubectl a través del archivo de configuración de kube
    kubelet usa (de esta manera no hay escalada de privilegios).
  • Pregunta si el nodo principal thinks su propio nodo es NotReady. Si es así, activa un reinicio de kubelet ejecutando el comando touch en un archivo
    eso es watched por un servicio de kubelet-watcher para cambios en el sistema de archivos y reinicia kubelet en consecuencia.
#!/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]#

Con Kubernetes 1.19.0, el problema aún existe, pero el mensaje es ligeramente diferente.
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)
Ahora contiene un "(puede volver a intentarlo después de dormir)" en el mensaje de error.

¿Es posible mitigar esto por completo en kubernetes sin esperar una actualización de golang? Por ejemplo, ¿se puede hacer que client-go cambie el transporte si llega a un "uso de una conexión de red cerrada" o algo así?

Alternativamente, ¿seguiría ocurriendo este problema si usa HTTP 1.1, o está puramente relacionado con HTTP 2? Si HTTP 1.1 fuera inmune y no tuviera grandes inconvenientes, sería una solución realmente simple establecer GODEBUG=http2client=0 en kubelet, kube-proxy y varios procesos del plano de control, o incluso establecer GODEBUG=http2server=0 en el proceso de apiserver para que el cambio sea universal.

¿Creemos que esto realmente mitigaría este problema y no causaría otros errores importantes además de algunos problemas de rendimiento debido al aumento en el recuento de conexiones cuando no se multiplexa a través de HTTP2?

¿Se puede hacer que client-go cambie el transporte si llega a un "uso de una conexión de red cerrada" o algo así?

no muy quirúrgicamente ... los transportes se comparten actualmente con el fin de evitar el agotamiento efímero de los puertos frente a las personas que llaman que constantemente construyen nuevos clientes

¿Seguiría ocurriendo este problema si usa HTTP 1.1, o está puramente relacionado con HTTP 2?

Hasta donde yo sé, HTTP 1.1 puede encontrar el mismo problema ya que las conexiones inactivas vuelven a un grupo de mantenimiento vivo (y tiene menos opciones para detectarlo / mitigarlo ya que el mecanismo de verificación de estado del ping no está disponible)

¿Existe una buena solución para los proyectos que utilizan el cliente? ¿Cómo podemos identificar cuándo el cliente está muerto y qué es lo mínimo que debemos hacer para solucionarlo (parece que reiniciar nuestro proceso podría ser la única opción)?

¿Cómo podemos identificar cuando el cliente está muerto?

Cuando tienes el error write tcp xxx use of closed network connection repetidamente para una URL idéntica. Eso indica que el cliente está muerto. El grupo de conexiones dentro de Transporte ha almacenado en caché una conexión tcp inactiva para el host solicitado

¿Existe una buena solución para los proyectos que utilizan el cliente?

Hasta donde yo sé, reconstruir un http.Client puede solucionar este problema sin reiniciar toda la aplicación.

¿Qué es lo mínimo que tenemos que hacer para solucionarlo?

Requiere acceso a nivel de código fuente al proyecto. Tal vez pueda usar el mecanismo mencionado anteriormente para detectar clientes muertos y reconstruir un nuevo cliente cuando sea necesario. Si nadie está usando el cliente anterior, se recolectará la basura.

Tengo acceso al código fuente de mi proyecto, pero usamos el cliente de kubernetes. Cuando hacemos relojes, parece que nunca detecta si la conexión TCP se corta de esta manera (y dado que el reloj está manejando las transacciones HTTP, no aparecen errores en nuestro código para manejar).

Sí. tiene razón, el cliente de kubernetes no expone el http.Client .
Actualmente, es inútil que la aplicación de nivel superior haga una solución de este tipo con poco costo.
Si el cliente de kubernetes no usa http.DefaultClient , podría solucionarse reconstruyendo todo el cliente de kubernetes.

Para la solicitud de reloj, está empeorando. El cliente de kubernetes parece seguir intentando volver a intentar la solicitud y no aparece ningún error en la aplicación superior. No tengo una buena idea sobre tal situación ahora.

La solución alternativa propuesta aquí nos ha funcionado durante varias semanas. Lo convertimos en un script de Python que se ejecuta como un daemonset en todos nuestros clústeres. Por lo general, lo vemos actuar una o dos veces por semana (reinicia kubelet automáticamente) y no hemos tenido ningún impacto negativo en el funcionamiento de nuestro clúster como resultado. Lo hicimos variable para que solo reinicie kubelet si ve más de 2 mensajes en un período de 5 minutos. Vimos que de vez en cuando podíamos ver un mensaje y no era un problema. Cuando ocurra el problema, verá el error use of closed network connection constantemente en los registros de kubelet.

Cree una solicitud de extracción e investigaremos este tema.

En un solo clúster de metal desnudo, veo que esto sucede entre 2 y 4 veces cada 24 horas. 1.17.12

sucede cuando se reinicia el pod de api-server, incluso en un solo clúster de nodos. Las conexiones al apiserver se perdieron, por lo que el método de minimización del número de error está resolviendo el problema por el que se reinicia un servidor.

Estoy usando haproxy frente al nodo maestro, ¿crees que hay alguna forma de evitar esto con alguna configuración de LB?

@ shubb30 ¿te importaría compartir conmigo tu solución?

Puedo confirmar que mis apiservers NO se reiniciarán cuando experimente el problema. Estoy usando el truco de daemonset y shell para monitorear la entrada del registro y luego reiniciar kubelet, esto ha funcionado bastante bien, pero lo veo solo como una solución temporal.

Aquí hay una versión modificada de lo que nos ha funcionado bien como solución alternativa.

¡Hola a todos!

¿Creemos potencialmente que este backport podría ayudar?
https://github.com/golang/go/issues/40423

Buenas noticias: golang / net master tiene soporte para configurar transportes http2, lo que ahora permite configurar los tiempos de espera. https://github.com/golang/net/commit/08b38378de702b893ee869b94b32f833e2933bd2

Hecho.
PR abierto para revisión.

Otra buena noticia: Kubernetes no usa el http2 incluido en el paquete net / http estándar, por lo que no es necesario esperar a la próxima versión de Go. Podemos usar directamente https://github.com/golang/net/commit/08b38378de702b893ee869b94b32f833e2933bd2 para solucionar este problema.

Propuesta una solución aquí. https://github.com/kubernetes/kubernetes/pull/95898
Actualiza la dependencia a la versión requerida y habilita la verificación de estado de transporte http2 de forma predeterminada.
Debería ayudar a las aplicaciones que usan client-go a comunicarse con apiserver (por ejemplo: kubelet) a deshacerse del problema "la aplicación se cuelga al escribir tcp xxx: uso de conexión cerrada".

Siéntete libre de dejar cualquier comentario.

Parece que el mencionado # 95898 se cerró por razones que no necesitamos discutir.

¿Hay alguna otra actualización con respecto a este problema?

https://github.com/kubernetes/kubernetes/pull/95981 (vinculado arriba) está en progreso para obtener la corrección http / 2

¿Este problema es específico de las versiones 1.17.X de kubernetes?

@krmayankk No estoy del todo seguro de cuándo comenzó exactamente. Pero al menos 1.17-1.19 tienen este problema. Sin embargo, # 95980 debería haberlo solucionado (será parte de la próxima versión 1.20, no ha llegado a la versión beta ayer)

@krmayankk También vimos este problema con v1.18.9, pero fue provocado por una versión defectuosa de Rancher que causó un uso muy alto de la red. Después de volver a otra versión, no se observaron problemas.

Tuve este problema, pero ahora lo "solucioné" en mi pequeño grupo de pasatiempos usando la solución en un comentario anterior

Escribí un pequeño libro de jugadas ansible para implementar la solución alternativa en los nodos como una unidad y un temporizador de systemd, podría ahorrar a otros con una configuración similar en algún momento

¿Hay un plan para seleccionar / retroceder https://github.com/kubernetes/kubernetes/pull/95981 y https://github.com/kubernetes/kubernetes/issues/87615 a la rama de lanzamiento 1.18?

¿Hay un plan para seleccionar la rama de lanzamiento # 95981 a 1.17?

Este comentario analiza las versiones anteriores de versiones anteriores: https://github.com/kubernetes/kubernetes/pull/95981#issuecomment -730561539

Creo que la respuesta es "es difícil y podría romper cosas, así que probablemente no". Es la misma respuesta que esperaría de las personas que ejecutan la versión 1.17 cuando se les pregunta, así que ¿por qué no actualizar a la versión 1.20 para obtener la solución? :risa:

Backportar esto a al menos 1,19 sería genial, ya que hará que la solución esté disponible relativamente pronto. Sospecho que algunas personas retrasarán la versión 1.20 debido a la desaprobación de Docker.

Backportar esto a al menos 1,19 sería genial, ya que hará que la solución esté disponible relativamente pronto.

Eso ya se ha hecho.

Sospecho que algunas personas retrasarán la versión 1.20 debido a la desaprobación de Docker.

Nada ha cambiado en 1.20 con respecto a la ventana acoplable más que una advertencia de obsolescencia. Al final del período de desactivación, se eliminará el soporte de Dockershim.

obtener estos errores en 1.20 en un raspbian 10. ¿dónde se puede empezar a solucionar este problema? Parece que el costo de ejecutar un clúster administrado en la nube es mucho más rentable que intentar ejecutarlo en su propio clúster.

Para mi propia claridad, esto parece que debería ser resuelto por # 95981, y eso lo convirtió en 1.20 y se volvió a portar a 1.19.

95981 se fusionó con 1,20 y se seleccionó con precisión a 1,19 en # 96770.

/cerrar

@caesarxuchao : Cerrando este tema.

En respuesta a esto :

95981 se fusionó con 1,20 y se seleccionó con precisión a 1,19 en # 96770.

/cerrar

Las instrucciones para interactuar conmigo usando comentarios de relaciones públicas están disponibles aquí . Si tiene preguntas o sugerencias relacionadas con mi comportamiento, presente un problema en el repositorio de kubernetes / test-infra .

¿Habrá alguna selección de backport / cherry para v1.16, v1.17 o v1.18?

@chilicat ver https://github.com/kubernetes/kubernetes/pull/95981#issuecomment -730561539. No planeo seleccionarlo a 1.18 o versiones anteriores.

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

chowyu08 picture chowyu08  ·  3Comentarios

ttripp picture ttripp  ·  3Comentarios

arun-gupta picture arun-gupta  ·  3Comentarios

montanaflynn picture montanaflynn  ·  3Comentarios

rhohubbuild picture rhohubbuild  ·  3Comentarios