Kubernetes: (1.17) Kubelet não se reconecta ao Apiserver após a falha do NIC (uso de conexão de rede fechada)

Criado em 28 jan. 2020  ·  123Comentários  ·  Fonte: kubernetes/kubernetes

Acabamos de atualizar nosso cluster de produção para 1.17.2.

Desde a atualização no sábado, tivemos esta estranha interrupção: Kubelet, após uma falha de ligação da NIC (que se recupera não muito tempo depois), terá todas as suas conexões quebradas e não tentará restabelecê-las a menos que seja reiniciado manualmente.

Aqui está a linha do tempo da última vez em que ocorreu:

01:31:16: Kernel reconhece uma falha na interface de ligação. Isso dura um pouco. Eventualmente, ele 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 esperado, todos os relógios estão fechados. A mensagem é a mesma para todos eles:

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

Então, essas mensagens começam:

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

O que acho que não deve ser um problema por enquanto. Mas nunca se recupera. Nosso evento aconteceu às 01:31 AM, e tivemos que reiniciar manualmente o Kubelet por volta das 9h para normalizar o material.

# 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

Os Apiservers estavam funcionando, todos os outros nós estavam funcionando, todo o resto sem intercorrências. Este foi o único afetado (hoje) por este problema.

Existe alguma forma de mitigar esse tipo de evento?

Isso seria um bug?

kinsupport siapi-machinery sinode

Comentários muito úteis

Eu corrigi isso executando este script bash a 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 comentários

nó / sig
/ sig api-maquinários

Dando uma olhada no código, o erro acontece aqui

A explicação do código é que ele assume que é provavelmente EOF (IsProbableEOF), enquanto neste caso isso não parece ser.

/ assign @caesarxuchao

@rikatz você pode explicar como rastreou o código que colou?

Meu pensamento é que o refletor teria reiniciado o relógio independentemente de como ele lida com o erro ( código ), por isso não explica a falha na recuperação.

Exatamente @caesarxuchao, então essa é a nossa pergunta.

Eu rastreei o erro basicamente examinando-o através do Código e cruzando com o que kubelet estava fazendo naquele momento (observando os segredos) para entrar nessa parte.

Não de uma forma avançada, por meio dela parece ser o ponto exato do código de erro.

A questão é, porque a conexão está fechada, há algum lugar sinalizando que este é o EOF do relógio em vez de entender que isso é um erro?

Não tenho nada mais inteligente para adicionar, exceto que tivemos outro nó com falha da mesma maneira, aumentando as ocorrências dos últimos 4 dias para 4.

Tentaremos mapear se os eventos de desconexão de ligação estão acontecendo em outros nós e se o kubelet está se recuperando - pode ser má sorte em algumas recuperações, e não um evento 100%.

Acho que estamos vendo isso também, mas não temos títulos, só vemos essas mensagens de "transportadora perdida" de rede para interfaces Calico cali* e são dispositivos veth locais.

Eu encontrei isso também, sem vínculos envolvidos. Reiniciar o nó corrige o problema, mas apenas reiniciar o serviço Kubelet não (todas as chamadas de API falham com "Não autorizado").

Eu encontrei isso também, sem vínculos envolvidos. Reiniciar o nó corrige o problema, mas apenas reiniciar o serviço Kubelet não (todas as chamadas de API falham com "Não autorizado").

Atualização: reiniciar o Kubelet corrigiu o problema após o tempo suficiente (1 hora?) Passar.

Estou vendo esse mesmo comportamento. Instalações limpas do Ubuntu 18.04.3 LTS. Cluster construído com fazendeiro 2.3.4. Tenho visto isso acontecer periodicamente e apenas reiniciar o kubelet tende a consertar para mim. Ontem à noite, todos os meus 3 nós de trabalho exibiram o mesmo comportamento. Corrigi 2 para trazer meu cluster. O terceiro ainda está neste estado enquanto estou vasculhando.

estamos vendo o mesmo problema no CentOS 7, cluster recém-construído com rancher (1.17.2). Estamos usando tecido. Todos os 3 nós de trabalho estão apresentando esse problema. Reiniciar o kubelet não funciona para nós, temos que reiniciar todo o nó

nó / sig
/ sig api-maquinários

Dando uma olhada no código, o erro acontece aqui

A explicação do código é que ele assume que é provavelmente EOF (IsProbableEOF), enquanto neste caso isso não parece ser.

Também estamos vendo o mesmo problema. A partir do registro, descobrimos que, após a ocorrência do problema, todas as solicitações subsequentes ainda eram enviadas na mesma conexão. Parece que embora o cliente reenvie a solicitação para apiserver, a biblioteca underlay http2 ainda mantém a conexão antiga, então todas as solicitações subsequentes ainda são enviadas nesta conexão e recebem o mesmo erro use of closed connection .

Portanto, a questão é por que o http2 ainda mantém uma conexão já fechada? Talvez a conexão mantida esteja realmente viva, mas algumas conexões intermediárias são fechadas inesperadamente?

Tenho o mesmo problema com um cluster Raspberry Pi com k8s 1.17.3 com muita frequência. Com base em alguns problemas mais antigos, eu defini o limite de conexão http do servidor API do kube para 1000 "- --http2-max-streams-per-connection = 1000", estava tudo bem por mais de 2 semanas depois disso, ele começa agora novamente.

É possível reconstruir kube-apiserver https://github.com/kubernetes/apiserver/blob/b214a49983bcd70ced138bd2717f78c0cff351b2/pkg/server/secure_serving.go#L50
definir s.DisableHTTP2 para true por padrão?
Existe um dockerfile para uma imagem oficial ( k8s.gcr.io/kube-apiserver:v1.17.3 )?

o mesmo aqui. (ubuntu 18.04, kubernetes 1.17.3)

Também observamos isso em dois de nossos clusters. Não tenho certeza absoluta sobre a causa raiz, mas pelo menos fomos capazes de ver isso aconteceu em cluster com contagens de observação muito altas. Não consegui reproduzir forçando um grande número de relógios por kubelet (pods iniciados com 300 segredos por pod, o que também resultou em 300 relógios por pod nas métricas do Prometheus). Além disso, definir valores http2-max-streams-per-connection baixos não acionou o problema, mas pelo menos eu fui capaz de observar algum comportamento inesperado do planejador e do gerenciador de controlador (pode ter sido apenas sobrecarga após intermináveis ​​loops de revisão ou algo assim, no entanto).

Como solução alternativa, todos os meus nós reiniciam todas as noites Kublet via cronjob local. Agora, depois de 10 dias atrás, posso dizer que funciona para mim, não tenho mais "uso de conexão de rede fechada" em meus nós.

@sbiermann
Obrigado por postar isso. Que intervalo de tempo você usa para cronjob?

24 horas

Também posso confirmar esse problema, ainda não estamos no 1.17.3, executando atualmente o 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

Também posso confirmar isso no Kubernetes 1.17.4 implantado por meio do Rancher 2.3.5 nos nós do RancherOS 1.5.5. Reiniciar o kubelet parece funcionar para mim, não preciso reiniciar o nó inteiro.

A causa subjacente para mim parece ser a RAM quase esgotada e o kswapd0 atingindo 100% de uso da CPU devido a isso, já que esqueci de definir a troca como 0 para meus nós do Kubernetes. Depois de definir a troca para 0 e adicionar um pouco de RAM às máquinas, o problema não voltou a ocorrer para mim ainda.

Se o problema subjacente era "http2 usando conexões inativas", reiniciar o kubelet deve corrigir o problema. https://github.com/kubernetes/kubernetes/pull/48670 sugeriu que a redução de TCP_USER_TIMEOUT pode atenuar o problema. Abri https://github.com/golang/net/pull/55 para adicionar a verificação de integridade da conexão do lado do cliente à biblioteca http2, mas vai demorar mais tempo para pousar.

Se reiniciar o kubelet não resolveu o problema, provavelmente a causa raiz é diferente.

Eu tenho o mesmo problema com a v1.17.2 ao reiniciar a rede, mas apenas um dos nós tem esse problema (meu cluster tem cinco nós), não consigo reproduzi-lo. Reiniciar o kubelet resolveu este problema.

Como posso evitar esse problema? Atualizar a versão mais recente ou tem outra maneira de consertar?

Eu corrigi isso executando este script bash a 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

Eu criei um patch sem reiniciar o kubelet e parece que o problema foi resolvido.
patch de prazo

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 Você pode explicar como reconstruir o client-go?

@mYmNeo Você pode explicar como reconstruir o client-go?

@ ik9999 Aplique este patch, reconstrua o kubelet e substitua o binário

@mYmNeo Como posso reproduzir este problema e testá-lo?

Corrigi-o executando este script bash a cada 5 minutos

@ ik9999 Obrigado, funciona.

cc @liggitt

definir SetReadDeadline significa que todos os relógios serão fechados a cada 30 segundos?

definir SetReadDeadline significa que todos os relógios serão fechados a cada 30 segundos?

sim. É uma maneira feia de resolver esse problema (forçar o fechamento de uma conexão).

Apenas outro caso:

Também estamos vendo isso nos clusters do Kube 1.16.8. A reinicialização da VM pode ser usada para trazer o nó de volta a um bom estado (suspeito que uma reinicialização do kubelet também teria funcionado).

Nosso kubelet de configuração se comunica com uma instância haproxy local sobre localhost, que atua como um balanceador de carga tcp para as várias instâncias mestre de back-end. Vamos investigar se adicionar

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

Para nossas instâncias do balanceador de carga, ajude a aliviar a necessidade de reinicialização explícita e pode levar a uma recuperação completa. Exemplo 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

Postarei uma atualização se isso resolver nosso problema específico caso ajude alguém aqui nesse ínterim.

Curioso para saber se há um parâmetro de configuração para definir um limite superior absoluto em um tempo de exibição? Eu encontrei --streaming-idle-connection-timeout, mas nada específico para relógios.

Estamos vendo isso no kube 1.17.4 depois que o servidor API não está íntegro devido a "falha no etcd: motivo retido".

Oi, pessoal. Recompilei o binário do kubernetes com golang 1.14. Parece que o problema desapareceu

@mYmNeo golang 1.14 + kubernetes v1.17?

@mYmNeo golang 1.14 + kubernetes v1.17?

@pytimer Estamos usando 1.16.6 sem alterar nenhum código, apenas recompilando. Acho que a causa raiz pode ser golang.

Ei! Tenho o mesmo problema aqui, k8s 1.17.4, achamos que poderíamos ter um 1.17.5 recompilado com go 1.14 se isso resolver o problema?

Infelizmente, a atualização para go1.14 requer atualizações de vários componentes principais, portanto, é improvável que volte para o Kube 1.17. Você pode acompanhar os problemas e o progresso em https://github.com/kubernetes/kubernetes/pull/88638

Bom saber obrigado

@callicles foi confirmado que recompilar com go 1.14 resolveu o problema?

Estou vendo um problema idêntico no 1.16.8 - de vez em quando (às vezes uma vez a cada dois dias, às vezes a cada duas semanas) o nó se torna NotReady, com o motivo pelo qual Kubelet parou de postar o status do nó e "uso de conexão de rede fechada" enchendo os logs

go pode ter problema lidar com a atualização 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
        }

Oi, pessoal. Recompilei o binário do kubernetes com golang 1.14. Parece que o problema desapareceu

@mYmNeo você já reproduziu o problema depois de recompilar com go 1.14

Oi, pessoal. Recompilei o binário do kubernetes com golang 1.14. Parece que o problema desapareceu

@mYmNeo você já reproduziu o problema depois de recompilar com go 1.14

AFAIN, o problema não existe mais.

Infelizmente, a atualização para go1.14 requer atualizações de vários componentes principais, portanto, é improvável que volte para o Kube 1.17. Você pode acompanhar os problemas e o progresso em # 88638

Você já sabe se go1.14 será retransmitido para 1.18?

Você já sabe se go1.14 será retransmitido para 1.18?

Eu não esperava isso. As alterações no etcd e bbolt parecem ser necessárias para suportar go1.14, que é uma alteração maior do que normalmente é feita nos ramos de lançamento.

@liggitt Ok thx. Parece que nós (pelo menos para nossos clusters) precisamos de uma estratégia de mitigação enquanto isso :)

Esse problema só ocorre após uma falha da placa de rede? Estamos vendo a mesma mensagem de erro em nossos clusters v1.16.8, mas não há falha de NIC associada.

Tivemos pelo menos uma instância em que a VM subjacente apresentou um erro SCSI ao se conectar a uma SAN. O problema SCSI se resolveu, mas kubelet nunca se recuperou.

A opção --goaway-chance foi adicionada em 1.18 (# 88567). Essa opção vai aliviar esse problema?

Não. Isso só tem efeito se o kubelet for realmente capaz de alcançar o servidor da API e obter uma resposta.

uma falha de ligação NIC (que se recupera não muito tempo depois), terá todas as suas conexões quebradas e não tentará restabelecê-las, a menos que seja reiniciado manualmente.

você pode dizer qual modo de ligação você está usando? Não consigo reproduzir isso no meu cluster com títulos de backup ativo.

Depois de fazer upgrade para o Kubernetes 1.16, também começamos a ver o erro use of closed network connection e o kubelet não se reconectava ao apiserver, deixando os nós presos em NotReady. Não foi possível reproduzir o problema derrubando NICs (configurando os links para baixo / para cima), mas percebemos que esse comportamento só acontecia em clusters que estavam mais carregados.

Fizemos mais pesquisas e descobrimos que o padrão do lado do servidor padrão do lado do --http2-max-streams-per-connection=1000 , não vimos o problema com os nós travando no NotReady tanto quanto originalmente encontrado durante o teste. Isso não resolveu o problema de kubelet não reconectar, mas nos ajudou a mitigar o problema que estávamos vendo.

Depois de fazer upgrade para o Kubernetes 1.16, também começamos a ver o erro use of closed network connection e o kubelet não se reconectava ao apiserver, deixando os nós presos em NotReady. Não foi possível reproduzir o problema derrubando NICs (configurando os links para baixo / para cima), mas percebemos que esse comportamento só acontecia em clusters que estavam mais carregados.

Fizemos mais pesquisas e descobrimos que o padrão do lado do servidor padrão do lado do --http2-max-streams-per-connection=1000 , não vimos o problema com os nós travando no NotReady tanto quanto originalmente encontrado durante o teste. Isso não resolveu o problema de kubelet não reconectar, mas nos ajudou a mitigar o problema que estávamos vendo.

Olá, os streams https do lado do servidor padrão é 1000 no kube-apiserver, isso é igual ao valor do cliente.
https://github.com/kubernetes/kubernetes/blob/ae1103726f9aea1f9bbad1b215edfa47e0747dce/staging/src/k8s.io/apiserver/pkg/server/options/recommended.go#L62

@warmchang Acho que isso se aplica a apiservers de apiextensões e ao apiserver de amostra:
https://github.com/kubernetes/kubernetes/blob/ae1103726f9aea1f9bbad1b215edfa47e0747dce/staging/src/k8s.io/apiserver/pkg/server/options/recommended.go#L62

Um teste com teste curl sem definir --http2-max-streams-per-connection tem isso em nossos logs do apiserver (usando v1.16):
I0603 10:18:08.038531 1 flags.go:33] FLAG: --http2-max-streams-per-connection="0"

E uma solicitação curl mostra isso na resposta:
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!

Quando eu uso --http2-max-streams-per-connection=1000 a solicitação curl mostra
* Connection state changed (MAX_CONCURRENT_STREAMS == 1000)!

@jmcmeek @treytabner , você está certo. Eu interpretei mal o código. : +1:

Usando o kubernetes 1.17.6 e o ​​mesmo aqui. Parece que o kubelet está usando uma conexão http2 inativa.
Eu percebi que o valor padrão inconsistente de MAX_CONCURRENT_STREAMS entre kube-apiserver e kubelet.

Basta definir o valor do lado do servidor para 1000. Reportará mais tarde.

Rancher / RKE

Adicionar à definição de cluster:

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

Verifique no nó mestre:

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

Definir MAX_CONCURRENT_STREAMS como 1000 no APIserver não tem efeito sobre este problema.
Acredito que isso seja causado por uma falha em golang http2 Transport . Veja acima

Tive esse problema novamente esta noite.
Parece que definir 'MAX_CONCURRENT_STREAMS' não ajudou☹️

Oi, pessoal. Acho que finalmente descobri esse problema. Temos o mesmo problema que aconteceu ontem à noite. Mas se recuperou com sucesso com um kubelet modificado.

Não é um bug do Kubernetes, é sobre o pacote net/http padrão de golang que client-go está usando.
Acredito que haja uma falha em golang.org/x/net/http2/transport.go

Já relatou isso ao oficial de golang. Esperando por alguma discussão.
https://github.com/golang/go/issues/39750

Por enquanto, modifiquei o código para ter o http2: perform connection health check introduzido por https://github.com/golang/net/commit/0ba52f642ac2f9371a88bfdde41f4b4e195a37c0 ativado por padrão.
Isso prova ser de alguma ajuda neste problema. Mas uma resposta um pouco lenta.

logs do kubelet v1.17.6 (em conformidade com o pacote auto-modificado golang.org/x/net )

Ele se recuperou do problema de gravação de conexões inativas, mas custou um pouco mais de tempo do que o esperado.

Observe que performing http2 healthCheck é uma mensagem de registro que eu pretendia deixar lá para provar que healthCheck func é chamada por readIdleTimer

 23 de junho 03:14:45 vm10.company.com kubelet [22255]: E0623 03: 14: 45.912484 22255 kubelet_node_status.go: 402] Erro ao atualizar o status do nó, tentará novamente: erro ao obter o nó "vm10.company.com": Get "https://vm10.company.com:8443/api/v1/nodes/vm10.company.com?timeout=10s": escreva tcp 16.155.199.4:39668->16.155.199.4:8443: uso de conexão de rede fechada
 23 de junho 03:14:45 vm10.company.com kubelet [22255]: E0623 03: 14: 45.912604 22255 kubelet_node_status.go: 402] Erro ao atualizar o status do nó, tentará novamente: erro ao obter o nó "vm10.company.com": Get "https://vm10.company.com:8443/api/v1/nodes/vm10.company.com?timeout=10s": escreva tcp 16.155.199.4:39668->16.155.199.4:8443: uso de conexão de rede fechada
 23 de junho 03:14:45 vm10.company.com kubelet [22255]: E0623 03: 14: 45.912741 22255 kubelet_node_status.go: 402] Erro ao atualizar o status do nó, tentará novamente: erro ao obter o nó "vm10.company.com": Get "https://vm10.company.com:8443/api/v1/nodes/vm10.company.com?timeout=10s": escreva tcp 16.155.199.4:39668->16.155.199.4:8443: uso de conexão de rede fechada
 23 de junho 03:14:46 vm10.company.com kubelet [22255]: E0623 03: 14: 46.367046 22255 controller.go: 135] falhou ao garantir que existe concessão de nó, tentará novamente em 400 ms, erro: Get "https: // vm10.company.com:8443/apis/coordination.k8s.io/v1/namespaces/kube-node-lease/leases/vm10.company.com?timeout=10s ": escreva tcp 16.155.199.4:39668->16.155. 199.4: 8443: uso de conexão de rede fechada
 23 de junho 03:14:48 vm10.company.com kubelet [22255]: E0623 03: 14: 47.737579 22255 controller.go: 135] falhou ao garantir que existe concessão de nó, tentará novamente em 800 ms, erro: Get "https: // vm10.company.com:8443/apis/coordination.k8s.io/v1/namespaces/kube-node-lease/leases/vm10.company.com?timeout=10s ": escreva tcp 16.155.199.4:39668->16.155. 199.4: 8443: uso de conexão de rede fechada
 23 de junho 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: Falha ao listar * v1.Node: Get "https://vm10.company.com:8443/api/v1/nodes?fieldSelector=metadata.name%3Dvm10.company.com&limit=500&resourceVersion=0": escreva tcp 16.155.199.4:39668-> 16.155.199.4:8443: uso de conexão de rede fechada
 23 de junho 03:14:49 vm10.company.com kubelet [22255]: E0623 03: 14: 48.744770 22255 reflector.go: 153] object- "kube-system" / "flannel-token-zvfwn": Falha ao listar * v1.Secret: Get "https://vm10.company.com:8443/api/v1/namespaces/kube-system/secrets?fieldSelector=metadata.name%3Dflannel-token-zvfwn&limit=500&resourceVersion=0": escreva tcp 16.155 .199.4: 39668-> 16.155.199.4:8443: uso de conexão de rede fechada
 23 de junho 03:14:49 vm10.company.com kubelet [22255]: E0623 03: 14: 49.599631 22255 reflector.go: 153] object- "kube-system" / "coredns": Falha ao listar * v1.ConfigMap: Obtenha "https://vm10.company.com:8443/api/v1/namespaces/kube-system/configmaps?fieldSelector=metadata.name%3Dcoredns&limit=500&resourceVersion=0": escreva tcp 16.155.199.4:39668->16.155. 199.4: 8443: uso de conexão de rede fechada
 23 de junho 03:14:49 vm10.company.com kubelet [22255]: E0623 03: 14: 49.599992 22255 controller.go: 135] falhou ao garantir que existe concessão de nó, tentará novamente em 1.6s, erro: Get "https: / /vm10.company.com:8443/apis/coordination.k8s.io/v1/namespaces/kube-node-lease/leases/vm10.company.com?timeout=10s ": escreva tcp 16.155.199.4:39668->16.155 .199.4: 8443: uso de conexão de rede fechada
 23 de junho 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: Falha ao listar * v1.Service: Get "https://vm10.company.com:8443/api/v1/services?limit=500&resourceVersion=0": write tcp 16.155.199.4:39668->16.155.199.4:8443: uso de rede fechada conexão
 23 de junho 03:14:49 vm10.company.com kubelet [22255]: E0623 03: 14: 49.600323 22255 reflector.go: 153] object- "kube-system" / "kube-flannel-cfg": Falha ao listar * v1.ConfigMap: Get "https://vm10.company.com:8443/api/v1/namespaces/kube-system/configmaps?fieldSelector=metadata.name%3Dkube-flannel-cfg&limit=500&resourceVersion=0": escreva tcp 16.155 .199.4: 39668-> 16.155.199.4:8443: uso de conexão de rede fechada
 23 de junho 03:14:49 vm10.company.com kubelet [22255]: E0623 03: 14: 49.600463 22255 reflector.go: 153] object- "core" / "registrypullsecret": Falha ao listar * v1.Secret: Get " https://vm10.company.com:8443/api/v1/namespaces/core/secrets?fieldSelector=metadata.name%3Dregistrypullsecret&limit=500&resourceVersion=0 ": escreva tcp 16.155.199.4:39668->16.155.199.4:8443: uso de conexão de rede fechada
 23 de junho 03:14:49 vm10.company.com kubelet [22255]: E0623 03: 14: 49.369097 22255 reflector.go: 153] object- "kube-system" / "registrypullsecret": Falha ao listar * v1.Secret: Obtenha "https://vm10.company.com:8443/api/v1/namespaces/kube-system/secrets?fieldSelector=metadata.name%3Dregistrypullsecret&limit=500&resourceVersion=0": escreva tcp 16.155.199.4:39668->16.155. 199.4: 8443: uso de conexão de rede fechada
 23 de junho 03:25:39 vm10.company.com kubelet [22255]: E0623 03: 25: 39.543880 22255 desejado_state_of_world_populator.go: 320] Erro ao processar o volume "deployment-log-dir" para pod "fluentd-h76lr_core (e95c9200-3a0c -4fea-bd7f-99ac1cc6ae7a) ": erro ao processar PVC core / itom-vol-claim: falha ao buscar PVC do servidor API: Get" https://vm10.company.com:8443/api/v1/namespaces/core/ persistentvolumeclaims / itom-vol-claim ": leia tcp 16.155.199.4:41512->16.155.199.4:8443: uso de conexão de rede fechada
 23 de junho 03:25:39 vm10.company.com kubelet [22255]: E0623 03: 25: 39.666303 22255 kubelet_node_status.go: 402] Erro ao atualizar o status do nó, tentará novamente: falha ao corrigir o status "{\" status \ ": {\ "$ setElementOrder / conditions \": [{\ "type \": \ "MemoryPressure \"}, {\ "type \": \ "DiskPressure \"}, {\ "type \": \ "PIDPressure \ "}, {\" digite \ ": \" Pronto \ "}], \" condições \ ": [{\" lastHeartbeatTime \ ": \" 2020-06-22T19: 25: 29Z \ ", \" digite \ ": \" MemoryPressure \ "}, {\" lastHeartbeatTime \ ": \" 2020-06-22T19: 25: 29Z \ ", \" digite \ ": \" DiskPressure \ "}, {\" lastHeartbeatTime \ ": \ "2020-06-22T19: 25: 29Z \", \ "digite \": \ "PIDPressure \"}, {\ "lastHeartbeatTime \": \ "2020-06-22T19: 25: 29Z \", \ " digite \ ": \" Pronto \ "}]}}" para o nó "vm10.company.com": Patch "https://vm10.company.com:8443/api/v1/nodes/vm10.company.com/ status? timeout = 10s ": ler tcp 16.155.199.4:41512->16.155.199.4:8443: uso de conexão de rede fechada
 23 de junho 03:25:49 vm10.company.com kubelet [22255]: E0623 03: 25: 49.553078 22255 kubelet_node_status.go: 402] Erro ao atualizar o status do nó, tentará novamente: erro ao obter o nó "vm10.company.com": Get "https://vm10.company.com:8443/api/v1/nodes/vm10.company.com?timeout=10s": leia tcp 16.155.199.4:41718->16.155.199.4:8443: uso de conexão de rede fechada
 23 de junho 03:25:49 vm10.company.com kubelet [22255]: E0623 03: 25: 49.560723 22255 desejado_state_of_world_populator.go: 320] Erro ao processar volume "log-location" para pod "fluentd-h76lr_core (e95c9200-3a0c-4fea -bd7f-99ac1cc6ae7a) ": erro ao processar PVC core / itom-logging-vol: falha ao buscar PVC do servidor API: Get" https://vm10.company.com:8443/api/v1/namespaces/core/persistentvolumeclaims/ itom-logging-vol ": ler tcp 16.155.199.4:41718->16.155.199.4:8443: uso de conexão de rede fechada
 23 de junho 03:27:29 vm10.company.com kubelet [22255]: I0623 03: 27: 29.961600 22255 log.go: 181] realizando http2 healthCheck
 23 de junho 03:31:32 vm10.company.com kubelet [22255]: I0623 03: 31: 31.829860 22255 log.go: 181] executando http2 healthCheck
 23 de junho 03:31:44 vm10.company.com kubelet [22255]: I0623 03: 31: 44.570224 22255 log.go: 181] executando http2 healthCheck
 23 de junho 03:32:13 vm10.company.com kubelet [22255]: I0623 03: 32: 12.961728 22255 log.go: 181] executando verificação de integridade http2
 23 de junho 03:33:16 vm10.company.com kubelet [22255]: I0623 03: 33: 15.441808 22255 log.go: 181] realizando http2 healthCheck
 23 de junho 03:33:28 vm10.company.com kubelet [22255]: I0623 03: 33: 28.233121 22255 log.go: 181] executando http2 healthCheck

não há mais use of closed network connection relatado e o kubelet retorna ao estado Pronto

Temos alguns novos insights em potencial sobre o problema em nossas pilhas. Com alguma confiança, assumimos uma rara queda de conexão no nível de rede / infraestrutura devido à alta carga em relação aos números de conexão em situações específicas, portanto, em nosso caso, não foi a inversão das interfaces de rede. Tivemos problemas especialmente graves com a federação do Prometheus por causa disso, uma vez que eles mudaram para http2 no lado do cliente . Ativar o monitor de integridade http2 configurando http2.Transport.ReadIdleTimeout conforme implementado com golang/net#55 resolveu inteiramente os problemas de federação para nós.

Os valores atualmente não são expostos como apimachinery/pkg/util/net/http.go instancia http.Transport e atualiza para http2 internamente, o que não expõe a opção até que golang / net # 74 seja mesclado.

Há alguma outra solução alternativa além do cron job de reinicialização do kubelet? Temos um cron job em funcionamento há uma semana e ele não impediu que o problema acontecesse.

Eu tenho o mesmo problema na v1.17.3.

O que descobri é que a versão k8s que usa uma versão golang.org/x/net está com problemas e este pacote parece estar corrigido.
https://go-review.googlesource.com/c/net/+/198040

Versão com este problema (v1.16.5 ~ versão mais recente)
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9

Versão fixa (ramo mestre)
golang.org/x/net v0.0.0-20200707034311-ab3426394381

A atualização do pacote golang.org/x/net corrigirá esse problema?

Existe um lançamento planejado para a versão mantida do k8s (v1,16, 1.17, v1,18 ..) para corrigir isso?

O que descobri é que a versão k8s que usa uma versão golang.org/x/net está com problemas e este pacote parece estar corrigido.
https://go-review.googlesource.com/c/net/+/198040

A alteração mencionada apenas _oferece_ a possibilidade de habilitar o monitor de integridade HTTP2, mas ele precisa ser habilitado pelos desenvolvedores (o padrão é desligado). Além disso, não pode ser realmente definido, mas há uma solicitação pull para fornecer aos desenvolvedores acesso ao monitor de integridade .

Atualmente, estou integrando um hotfix baseado em reflexão que ativa o monitor de integridade para nossa própria distribuição do Kubernetes, na esperança de que isso ajude a resolver o problema.

-
Jens Erat \ Imprimir

@JensErat obrigado pela resposta.
Em caso afirmativo, esse problema também pode ocorrer em versões anteriores do k8s (1.13, 1.15, ..)?

Eu mudei nós distro de RancherOS (kernel 4.14.138) para Ubuntu 18.04 (kernel 5.3.0) mais de um mês atrás, o problema não apareceu desde então.
Um dos meus clusters deixou o RancherOS e já teve esse problema reproduzido três vezes.

Não é 100% certo, mas provavelmente a versão do kernel importa.

Difícil de dizer. Definitivamente observamos (d) o problema com 1.16 a 1.18, mas havia raras e estranhas "ocorrências presas de kubelet" antes. Já investigamos esses problemas há pelo menos um ano, mas nunca pudemos correlacionar nada (incidentes únicos em todas as semanas, e temos alguns kubelets em execução com quatro dígitos). No entanto, piorou muito desde que instalamos o 1.16, mas atualmente estamos mais para assumir que os problemas de rede subjacentes (também muito raros e difíceis de rastrear ...) acontecem com mais frequência. Estamos executando o Ubuntu 19.10 com Kernel 5.3.0-46-generic, mas são afetados (é possível que você tenha um patchlevel mais recente). Você pode dar uma dica de qual versão exata do kernel / nível de patch você está executando?

-
Jens Erat \ Imprimir

É 5.3.0-59-generic . Mas só temos cerca de 40 kubletes, então ainda pode ser uma coincidência.

Como eu disse acima. Esse problema ocorre com mais frequência em clusters com carga pesada. Observamos o mesmo problema quase todas as noites antes de habilitar o h2 transport healthCheck.
De acordo com o problema relatado ao oficial golang . O problema ocorre no loop de leitura de soquete, que deve retornar um erro na leitura de soquete fechado, mas nunca o faz. Além disso, sugiro adicionar lógica de tratamento de erro no socket de escrita para detectar ativamente o problema de conexão. Mas, vários dias depois, parece que eles não se importam com esses problemas raros.

Um pouco longe do assunto, quer dizer, já que o problema é causado por um soquete de rede que fecha muito o kernel. Atualizar o kernel pode ajudar ou não. (PS: estamos usando centos 7 com kernel 3.10, isso acontece quase todos os dias antes de habilitar o HealthCheck)
Passei cerca de 3 dias lendo código-fonte de net / http, até onde vi, habilitando h2 transport healthCheck deveria ajudar a recuperar de tal problema, e realmente escapamos dessa situação estranha fazendo isso.
@JensErat Você tem alguma prova concreta de que a ativação do HealthCheck ajuda a resolver esse problema?

@JensErat Você tem alguma prova concreta de que a ativação do HealthCheck ajuda a resolver esse problema?

Estamos executando a federação Prometheus para cada um dos nossos clusters Kubernetes. O Prometheus 2.19.0 introduziu http2 (eles se esquecem de mencionar isso no changelog e o tinham bem escondido em um corpo de mensagem de commit, eu tive que fazer o git dividir, implantar e esperar algumas horas para cada execução ...) e observamos sobre uma dúzia de incidentes com a federação travava por dia. Eu primeiro retifiquei o suporte http2 novamente (e o problema foi resolvido) e, em seguida, configurei o tempo limite de leitura diretamente em golang / net / x / http2. Desde então, não tivemos mais um único incidente de desativação de federação.

No momento, estou me preparando para lançar uma versão corrigida do Kubernetes em alguns clusters, portanto, devemos ter os dados em alguns dias. Definitivamente, compartilharemos nossos resultados assim que tivermos os dados adequados.

-
Jens Erat \ Imprimir

No momento, estou me preparando para lançar uma versão corrigida do Kubernetes em alguns clusters, portanto, devemos ter os dados em alguns dias. Definitivamente, compartilharemos nossos resultados assim que tivermos os dados adequados.

Obrigado pelo seu feedback! Essa é uma mensagem muito agradável.
Embora a causa raiz não seja muito clara, pelo menos descobrimos uma maneira de nos recuperar de um desastre. : D

Temos o mesmo problema com o k8s v1.14.3 e reiniciar o kubelet pode resolver o problema.

Eu sei que isso é bobagem, mas deve funcionar como uma solução temporária:

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


(Isso é específico do rancheiro, mas pode ser facilmente adaptado a outras distribuições usando contêiner privilegiado e journalctl / systemctl)

Quantidade de tempo para sleep e --since deve ser menor que pod-eviction-timeout do cluster (5 milhões por padrão)

BTW - docker pause nginx-proxy no nó do trabalhador faz com que o kubelet produza a mesma mensagem de erro.

Solução temporária para aqueles que estão executando K8S no VMWare vSphere - desative o DRS para as VMs K8S, que evitará que o vSphere mova as VMs entre os hipervisores, eliminando assim quaisquer desconexões de rede que estejam causando problemas aos Kubelets

Temos notícias muito boas sobre a mitigação do problema usando o novo recurso de verificação de integridade golang http2: sem problemas mais. Até agora, implementamos a "correção" (configuração codificada do valor no código x/net ) no Prometheus, Kubernetes inteiro e vários componentes internos, observando:

  • não há mais problemas com a federação Prometheus
  • Às vezes, o kubelet ainda relata eventos únicos de "uso de conexão fechada", mas se recupera em segundos (definimos uma janela de verificação de integridade http2 de aproximadamente 30 segundos)
  • às vezes tínhamos problemas com relógios kubectl - também desaparecia se usava kubectl com patch
  • estamos executando um conjunto de testes E2E estendido para verificar nossa integração regularmente e observamos tempos limite de teste esporádicos e instabilidade. Adivinha? Foi embora agora.

Além disso, conseguimos obter novos insights sobre como desencadear os problemas. Posso confirmar a observação de @ vi7 em relação à migração ao vivo com alguma confiança (embora pudéssemos rastreá-la), e pelo menos com a versão NSX que estamos executando também as alterações do balanceador de carga podem desencadear tais problemas (temos um tíquete com VMware para certifique-se de que eles estão enviando pacotes de redefinição no futuro). E muito provavelmente muitos outros motivos para perder conexões entre eles, como estouro de tabelas de conexão.

Este é um problema muito chato e um tanto massivo para alguns usuários do Kubernetes (dependendo de algum tipo de "falha" da camada / rede IaaS, eu acho). Embora haja discussões golang sobre expor uma interface para definir os valores adequadamente - você acha que há alguma chance de obter um PR mesclado upstream definindo esses valores por meio de reflexão (ainda melhor do que bifurcar x / net, eu acho que como fazemos agora) ? Estamos bem em fornecer o código (e validar a correção, não podemos realmente reproduzir, mas observe-o com freqüência suficiente para poder confirmar se a correção funciona).

cc @liggitt

problema de longo prazo (nota para mim)

@JensErat obrigado pela resposta.
Em caso afirmativo, esse problema também pode ocorrer em versões anteriores do k8s (1.13, 1.15, ..)?

Posso confirmar para ver o problema com o Kubernetes v1.16.13
Não encontramos o problema com o Kubernetes v1.15.9

quando eu restauro um cluster de kubenetes v1.16.14 do backup instantâneo do etcd. esse erro aparece no log do kubelet.
graças a @ ik9999 . Eu reinicio o kubelet e os erros desaparecem

[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 o mesmo problema no 1.17.3, reiniciar o kubelet deve resolver. Alguma solução alternativa estável para isso ou quando isso deve ser corrigido?

v1.18.6 mesmo

@ rxwang662001
Isso é causado pelo problema de golang upstream. Uma coisa a ter certeza é que isso NÃO será corrigido no go 1.15.
Enquanto isso, a comunidade Kubernetes ainda está lutando para migrar para o 1.14 LOL.

Normalmente, o go é lançado a cada 6 meses. Se tudo funcionar bem, talvez possamos ver esse problema resolvido pelo upstream no próximo ano, e talvez mais um ano até que o kubernetes adapte a correção 🥇!
(Só para brincar. Se você realmente deseja que isso seja corrigido em sua pilha agora. Hack the h2Transport para habilitar healthCheck provou estar funcionando.

Enquanto isso, a comunidade Kubernetes ainda está lutando para migrar para o 1.14 LOL.

Na verdade, devido ao excelente trabalho de sig-escalabilidade e sig-release para se qualificar nos pré-lançamentos go1.15, o Kubernetes 1.19 acabou de ser lançado em go1.15. Parece que há um trabalho em andamento para expor as opções de http / 2 em go1.16 e espero que façamos uso disso assim que estiver disponível.

Na verdade, devido ao excelente trabalho de sig-escalabilidade e sig-release para se qualificar nos pré-lançamentos go1.15, o Kubernetes 1.19 acabou de ser lançado em go1.15.

Ops. Desculpe pela piada estranha. Não prestei muita atenção ao lançamento v1.19.
Parece que pulamos go1.14 inteiramente no K8S? Uau. isso é um grande salto 👍

@povsister

Obrigado por compartilhar sua solução. Você poderia adicionar mais detalhes sobre como você fez isso funcionar?

Por enquanto, modifiquei o código para ter http2: perform connection health check introduzido por golang / net @ 0ba52f6 habilitado por padrão.
Isso prova ser de alguma ajuda neste problema. Mas uma resposta um pouco lenta.

Que alterações de código você implementou? E onde, em qual arquivo?

@KarthikRangaraju
Consulte este PR para habilitar o HealthCheck ao inicializar o h2Transport,
ou você pode fazer algum hack de reflexão / deslocamento inseguro para acessar o campo não exportado em tempo de execução.

E não se esqueça de atualizar golang / x / net antes de fazer essas coisas.

Não conseguimos reproduzir esse problema, embora o enfrentemos de vez em quando.

Como não somos capazes de identificar a causa raiz do sintoma, estamos corrigindo o sintoma de qualquer maneira.

Nossa solução:

  • O seguinte script é executado a cada 1 hora. Ele se comunica com o servidor kube-api via kubectl via arquivo de configuração do kube
    kubelet usa (dessa forma, não há escalonamento de privilégios).
  • Pergunta se o nó mestre thinks seu próprio nó é NotReady. Se sim, aciona uma reinicialização do kubelet executando o comando touch em um arquivo
    isto é watched por um kubelet-watcher.service para mudanças no sistema de arquivos e reinicia o kubelet de acordo.
#!/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]#

Com o Kubernetes 1.19.0, o problema ainda existe, mas a mensagem é um pouco 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)
Ele contém agora um "(pode tentar novamente após dormir)" na mensagem de erro.

É possível atenuar isso totalmente no kubernetes sem esperar por um golang de atualização? Por exemplo, o client-go pode ser feito para trocar o transporte se ele acertar um "uso de conexão de rede fechada" ou algo assim?

Como alternativa, esse problema ainda ocorreria se estivesse usando HTTP 1.1 ou é puramente relacionado ao HTTP 2? Se o HTTP 1.1 fosse imune e não tivesse grandes desvantagens, seria uma solução bem simples apenas definir GODEBUG=http2client=0 no kubelet, kube-proxy e vários processos de plano de controle, ou mesmo definir GODEBUG=http2server=0 no processo apiserver para tornar a mudança universal.

Achamos que isso atenuaria esse problema e não causaria outras armadilhas importantes além de alguns problemas de desempenho devido ao aumento na contagem de conexões quando não há multiplexação por HTTP2?

o client-go pode ser feito para trocar o transporte se ele acertar um "uso de conexão de rede fechada" ou algo assim?

não muito cirurgicamente ... os transportes são atualmente compartilhados para evitar o esgotamento efêmero da porta em face de chamadores que constroem novos clientes repetidamente

esse problema ainda ocorreria se estivesse usando HTTP 1.1 ou é puramente relacionado ao HTTP 2?

até onde eu sei, o HTTP 1.1 pode encontrar o mesmo problema, pois as conexões inativas voltam para um pool keep-alive (e tem menos opções para detectá-lo / mitigá-lo, pois o mecanismo de verificação de integridade de ping não está disponível para ele)

Existe uma boa solução alternativa para projetos que usam o cliente? Como podemos identificar quando o cliente está morto e qual é o mínimo que precisamos fazer para consertá-lo (parece que reiniciar nosso processo pode ser a única opção)?

Como podemos identificar quando o cliente está morto

Quando você recebe repetidamente o erro write tcp xxx use of closed network connection para um URL idêntico. Isso indica que o cliente está morto. O pool de conexão dentro do Transporte armazenou em cache uma conexão tcp inativa para o host: porta solicitado.

Existe uma boa solução alternativa para projetos que usam o cliente?

Pelo que eu sei, reconstruir um http.Client pode corrigir esse problema sem reiniciar o aplicativo inteiro.

o que é o mínimo que precisamos fazer para consertá-lo

Requer acesso em nível de código-fonte para o projeto. Talvez você possa usar o mecanismo mencionado acima para detectar clientes mortos e reconstruir um novo cliente quando necessário. Se ninguém estiver usando o cliente antigo, ele será coletado como lixo.

Tenho acesso ao código-fonte do meu projeto, mas usamos o cliente kubernetes. Quando fazemos relógios, parece que ele nunca detecta se a conexão TCP foi interrompida dessa forma (e como o relógio está lidando com as transações HTTP, nenhum erro chega ao nosso código para lidar com).

Sim. você está certo, o http.Client não é exposto pelo cliente kubernetes.
Atualmente, é impossível para um aplicativo de nível superior fazer essa solução alternativa com baixo custo.
Se o cliente kubernetes não usar http.DefaultClient , isso pode ser corrigido reconstruindo todo o cliente kubernetes.

Para solicitação de relógio, está piorando. O cliente Kubernetes parece continuar tentando a solicitação e nenhum erro é exibido no aplicativo superior. Não tenho uma boa ideia dessa situação agora.

A solução alternativa proposta aqui está funcionando para nós há várias semanas. Nós o transformamos em um script python que é executado como um daemonset em todos os nossos clusters. Normalmente o vemos agir uma ou duas vezes por semana (reiniciar automaticamente o kubelet) e não tivemos nenhum impacto negativo em nossa operação de cluster como resultado. Nós o tornamos variável para que ele reinicie o kubelet apenas se ele vir 2 ou mais mensagens em um período de 5 minutos. Vimos que ocasionalmente podíamos ver uma mensagem, e isso não era um problema. Quando o problema acontecer, você verá o erro use of closed network connection constantemente nos logs do kubelet.

Crie um pullrequest e investigaremos o assunto.

Em um único cluster baremetal, estou vendo isso acontecer cerca de 2 a 4 vezes a cada 24 horas. 1.17.12

isso acontece quando o pod api-server é reiniciado, mesmo em um cluster de nó único. As conexões com o apiserver foram perdidas, portanto, o método de minimização do número de erros está resolvendo o problema de reinicialização do apiserver.

Estou usando o haproxy na frente do nó mestre, você acha que há alguma maneira de evitar isso com alguma configuração de LB?

@ shubb30 você se importa em compartilhar comigo sua solução?

Posso confirmar que meus apiservers NÃO estão reiniciando quando tenho o problema. Estou usando o daemonset e o truque do shell para monitorar a entrada de log e reiniciar o kubelet. Isso tem funcionado muito bem, mas vejo isso apenas como uma solução temporária.

Aqui está uma versão modificada do que tem funcionado bem para nós como uma solução alternativa.

Olá a todos!

Será que achamos que esse backport pode ajudar?
https://github.com/golang/go/issues/40423

Boas notícias: golang / net master tem suporte para configurar transportes http2, que agora permite definir os tempos limite! https://github.com/golang/net/commit/08b38378de702b893ee869b94b32f833e2933bd2

Feito.
PR aberto para revisão.

Outra boa notícia: o Kubernetes não usa o http2 agrupado no pacote net / http padrão, portanto, não precisamos esperar pelo próximo lançamento Go. Podemos usar diretamente https://github.com/golang/net/commit/08b38378de702b893ee869b94b32f833e2933bd2 para corrigir esse problema.

Proposta de correção aqui. https://github.com/kubernetes/kubernetes/pull/95898
Ele atualiza a dependência para a versão necessária e ativa a verificação de integridade do transporte http2 por padrão.
Deve ajudar os aplicativos que usam client-go para se comunicar com apiserver (por exemplo: kubelet) a se livrar do problema "app travado ao escrever tcp xxx: uso de conexão fechada".

Sinta-se livre para deixar qualquer comentário.

Parece que o # 95898 mencionado foi fechado por motivos que não precisamos discutir.

Existe alguma outra atualização em relação a este problema?

Este problema é específico das versões 1.17.X do kubernetes?

@krmayankk Não tenho certeza de quando exatamente começou. Mas pelo menos 1.17-1.19 tem esse problema. No entanto, # 95980 deveria ter corrigido (fará parte do próximo lançamento 1.20, ainda não entrou na versão beta ontem)

@krmayankk Também vimos esse problema com a v1.18.9, mas ele foi acionado por uma versão com erros do Rancher que causava um alto uso da rede. Depois de reverter para outra versão, nenhum problema foi observado.

Eu tive esse problema, mas agora o "consertei" no meu pequeno cluster de hobby usando a solução alternativa em um comentário acima

Eu escrevi um pequeno ansible-playbook para implantar a solução alternativa em nós como uma unidade systemd e cronômetro, pode salvar outros com uma configuração semelhante algum tempo

Existe um plano para selecionar / backport https://github.com/kubernetes/kubernetes/pull/95981 e https://github.com/kubernetes/kubernetes/issues/87615 para o branch de lançamento 1.18?

Existe um plano para escolher o ramo de lançamento # 95981 para 1.17?

Este comentário discute backports para as versões mais antigas: https://github.com/kubernetes/kubernetes/pull/95981#issuecomment -730561539

Acho que a resposta é "é difícil e pode quebrar as coisas, então provavelmente não". É a mesma resposta que eu esperaria de pessoas que executam a v1.17 quando perguntado, então por que não atualizar para a v1.20 para obter a correção? :rindo:

Retroceder isso para pelo menos 1.19 seria ótimo, pois isso tornará a correção disponível relativamente em breve. Suspeito que algumas pessoas vão adiar o 1.20 devido à depreciação do Docker.

Retroceder isso para pelo menos 1.19 seria ótimo, pois isso tornará a correção disponível relativamente em breve.

Isso já foi feito.

Suspeito que algumas pessoas vão adiar o 1.20 devido à depreciação do Docker.

Nada mudou em 1.20 em relação ao docker, exceto um aviso de suspensão de uso. No final do período de reprovação, o suporte dockershim será removido.

recebendo esses erros em 1.20 em um raspbian 10. onde alguém começa a conseguir uma correção para tudo isso? parece que o custo de execução de um cluster gerenciado em nuvem é muito mais econômico do que tentar executá-lo em seu próprio cluster

Para minha própria clareza, isso parece que deve ser resolvido por # 95981, e isso foi feito para 1.20 e foi portado de volta para 1.19?

95981 foi mesclado com 1,20 e selecionado para 1,19 em # 96770.

/fechar

@caesarxuchao : Fechando esta edição.

Em resposta a isso :

95981 foi mesclado com 1,20 e selecionado para 1,19 em # 96770.

/fechar

Instruções para interagir comigo usando comentários de RP estão disponíveis aqui . Se você tiver dúvidas ou sugestões relacionadas ao meu comportamento, registre um problema no repositório kubernetes / test-infra .

Haverá alguma escolha de backport / cereja para v1.16, v1.17 ou ou v1.18?

@chilicat consulte https://github.com/kubernetes/kubernetes/pull/95981#issuecomment -730561539. Não pretendo selecioná-lo para versões 1.18 ou anteriores.

Esta página foi útil?
0 / 5 - 0 avaliações