Resolver problemas do kube-dns no GKE


Nesta página, mostramos como resolver problemas com o kube-dns no Google Kubernetes Engine (GKE).

Identificar a origem dos problemas de DNS no kube-dns

Erros como dial tcp: i/o timeout, no such host ou Could not resolve host geralmente indicam problemas com a capacidade do kube-dns de resolver consultas.

Se você encontrou um desses erros, mas não sabe a causa, use as seções a seguir para ajudar a descobrir. As seções a seguir estão organizadas para começar com as etapas que têm mais chances de ajudar você. Portanto, tente cada seção em ordem.

Verificar se os pods do kube-dns estão em execução

Os pods kube-dns são essenciais para a resolução de nomes no cluster. Se eles não estiverem em execução, é provável que você tenha problemas com a resolução de DNS.

Para verificar se os pods do kube-dns estão em execução sem reinicializações recentes, confira o status deles:

kubectl get pods -l k8s-app=kube-dns -n kube-system

O resultado será assim:

NAME                   READY          STATUS          RESTARTS       AGE
kube-dns-POD_ID_1      5/5            Running         0              16d
kube-dns-POD_ID_2      0/5            Terminating     0              16d

Nessa saída, POD_ID_1 e POD_ID_2 representam identificadores exclusivos que são anexados automaticamente aos pods do kube-dns.

Se a saída mostrar que algum dos seus pods kube-dns não tem o status Running, siga estas etapas:

  1. Use os registros de auditoria de atividades do administrador para investigar se houve mudanças recentes, como upgrades de versão do cluster ou do pool de nós, ou mudanças no kube-dns ConfigMap. Para saber mais sobre registros de auditoria, consulte Informações sobre a geração de registros de auditoria do GKE. Se encontrar mudanças, reverta-as e confira o status dos pods novamente.

  2. Se você não encontrar mudanças recentes relevantes, investigue se está ocorrendo um erro de falta de memória no nó em que o pod kube-dns é executado. Se você encontrar um erro semelhante ao seguinte nas mensagens de registro do Cloud Logging, esses pods estão enfrentando um erro de falta de memória:

    Warning: OOMKilling Memory cgroup out of memory
    

    Essa mensagem indica que o Kubernetes encerrou um processo devido ao consumo excessivo de recursos. O Kubernetes programa pods com base em solicitações de recursos, mas permite que eles consumam até os limites de recursos. Se os limites forem maiores que as solicitações ou não houver limites, o uso de recursos do pod poderá exceder os recursos do sistema.

    Para resolver esse erro, exclua as cargas de trabalho problemáticas ou defina limites de memória ou CPU. Para saber mais sobre como definir limites, consulte Gerenciamento de recursos para pods e contêineres na documentação do Kubernetes. Para mais informações sobre eventos de falta de memória, consulte Resolver problemas de eventos de falta de memória.

  3. Se você não encontrar mensagens de erro de falta de memória, reinicie a implantação do kube-dns:

    kubectl rollout restart deployment/kube-dns --namespace=kube-system
    

    Depois de reiniciar a implantação, verifique se os pods do kube-dns estão em execução.

Se essas etapas não funcionarem ou se todos os seus pods kube-dns tiverem o status Running, mas você ainda estiver com problemas de DNS, verifique se o arquivo /etc/resolv.conf está configurado corretamente.

Verifique se /etc/resolv.conf está configurado corretamente

Analise o arquivo /etc/resolv.conf dos pods com problemas de DNS e verifique se as entradas estão corretas:

  1. Confira o arquivo /etc/resolv.conf do pod:

    kubectl exec -it POD_NAME -- cat /etc/resolv.conf
    

    Substitua POD_NAME pelo nome do pod que está com problemas de DNS. Se houver vários pods com problemas, repita as etapas desta seção para cada um deles.

    Se o binário do pod não for compatível com o comando kubectl exec, ele poderá falhar. Se isso acontecer, crie um pod simples para usar como ambiente de teste. Esse procedimento permite executar um pod de teste no mesmo namespace do pod problemático.

  2. Verifique se o endereço IP do servidor de nomes no arquivo /etc/resolv.conf está correto:

    • Os pods que usam uma rede de host precisam usar os valores no arquivo /etc/resolv.conf do nó. O endereço IP do servidor de nomes deve ser 169.254.169.254.
    • Para pods que não usam uma rede de host, o endereço IP do serviço kube-dns precisa ser o mesmo do endereço IP do servidor de nomes. Para comparar os endereços IP, siga estas etapas:

      1. Consiga o endereço IP do serviço kube-dns:

        kubectl get svc kube-dns -n kube-system
        

        O resultado será assim:

        NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)         AGE
        kube-dns   ClusterIP   192.0.2.10   <none>        53/UDP,53/TCP   64d
        
      2. Anote o valor na coluna "IP do cluster". Neste exemplo, é 192.0.2.10.

      3. Compare o endereço IP do serviço kube-dns com o endereço IP do arquivo /etc/resolv.conf:

        # cat /etc/resolv.conf
        
        search default.svc.cluster.local svc.cluster.local cluster.local c.PROJECT_NAME google.internal
        nameserver 192.0.2.10
        options ndots:5
        

        Neste exemplo, os dois valores correspondem. Portanto, um endereço IP de servidor de nomes incorreto não é a causa do problema.

        No entanto, se os endereços IP não corresponderem, isso significa que um campo dnsConfig está configurado no manifesto do pod do aplicativo.

        Se o valor no campo dnsConfig.nameservers estiver correto, investigue o servidor DNS e verifique se ele está funcionando corretamente.

        Se você não quiser usar o servidor de nomes personalizado, remova o campo e faça uma reinicialização gradual do pod:

        kubectl rollout restart deployment POD_NAME
        

        Substitua POD_NAME pelo nome do pod.

  3. Verifique as entradas search e ndots em /etc/resolv.conf. Verifique se não há erros de ortografia, configurações desatualizadas e se a solicitação com falha aponta para um serviço existente no namespace correto.

Fazer uma busca DNS

Depois de confirmar que /etc/resolv.conf está configurado corretamente e que o registro DNS está correto, use a ferramenta de linha de comando dig para realizar pesquisas de DNS do pod que está informando erros de DNS:

  1. Consulte um pod diretamente abrindo um shell dentro dele:

    kubectl exec -it POD_NAME -n NAMESPACE_NAME -- SHELL_NAME
    

    Substitua:

    • POD_NAME: o nome do pod que está informando erros de DNS.
    • NAMESPACE_NAME: o namespace a que o pod pertence.
    • SHELL_NAME: o nome do shell que você quer abrir. Por exemplo, sh ou /bin/bash.

    Esse comando pode falhar se o pod não permitir o comando kubectl exec ou se ele não tiver o binário dig. Se isso acontecer, crie um pod de teste com uma imagem que tenha o dig instalado:

    kubectl run "test-$RANDOM" ti --restart=Never --image=thockin/dnsutils - bash
    
  2. Verifique se o pod consegue resolver corretamente o serviço DNS interno do cluster:

    dig kubernetes
    

    Como o arquivo /etc/resolv.conf aponta para o endereço IP do serviço kube-dns, quando você executa esse comando, o servidor DNS é o serviço kube-dns.

    Você vai ver uma resposta DNS bem-sucedida com o endereço IP do Serviço de API do Kubernetes (geralmente algo como 10.96.0.1). Se você vir SERVFAIL ou nenhuma resposta, isso geralmente indica que o pod kube-dns não consegue resolver os nomes de serviço internos.

  3. Verifique se o serviço kube-dns consegue resolver um nome de domínio externo:

    dig example.com
    
  4. Se você estiver com dificuldades para um pod kube-dns específico responder a consultas DNS, verifique se ele consegue resolver um nome de domínio externo:

     dig example.com @KUBE_DNS_POD_IP
    

    Substitua KUBE_DNS_POD_IP pelo endereço IP do pod kube-dns. Se você não souber o valor desse endereço IP, execute o seguinte comando:

     kubectl get pods -n kube-system -l k8s-app=kube-dns -o wide
    

    O endereço IP está na coluna IP.

    Se a resolução do comando for bem-sucedida, você verá status: NOERROR e os detalhes do registro A, conforme mostrado no exemplo a seguir:

     ; <<>> DiG 9.16.27 <<>> example.com
     ;; global options: +cmd
     ;; Got answer:
     ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 31256
     ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
    
     ;; OPT PSEUDOSECTION:
     ; EDNS: version: 0, flags:; udp: 512
     ;; QUESTION SECTION:
     ;example.com.                   IN      A
    
     ;; ANSWER SECTION:
     example.com.            30      IN      A       93.184.215.14
    
     ;; Query time: 6 msec
     ;; SERVER: 10.76.0.10#53(10.76.0.10)
     ;; WHEN: Tue Oct 15 16:45:26 UTC 2024
     ;; MSG SIZE  rcvd: 56
    
  5. Saia do shell:

    exit
    

Se algum desses comandos falhar, faça uma reinicialização gradual do Deployment do kube-dns:

kubectl rollout restart deployment/kube-dns --namespace=kube-system

Depois de concluir a reinicialização, tente os comandos dig novamente e verifique se eles agora são bem-sucedidos. Se ainda assim não funcionar, faça uma captura de pacote.

Fazer uma captura de pacote

Faça uma captura de pacote para verificar se as consultas de DNS estão sendo recebidas e respondidas adequadamente pelos pods kube-dns:

  1. Usando SSH, conecte-se ao nó que executa o pod kube-dns. Exemplo:

    1. No console Google Cloud , acesse a página Instâncias de VM.

      Acessar instâncias de VM

    2. Localize o nó a que você quer se conectar. Se você não souber o nome do nó no pod kube-dns, execute o seguinte comando:

      kubectl get pods -n kube-system -l k8s-app=kube-dns -o wide
      

      O nome do nó é listado na coluna .

    3. Na coluna Conectar, clique em SSH.

  2. No terminal, inicie a toolbox, uma ferramenta de depuração pré-instalada:

    toolbox
    
  3. No prompt raiz, instale o pacote tcpdump:

    apt update -y && apt install -y tcpdump
    
  4. Usando tcpdump, faça uma captura de pacote do seu tráfego DNS:

    tcpdump -i eth0 port 53" -w FILE_LOCATION
    

    Substitua FILE_LOCATION por um caminho para onde você quer salvar a captura.

  5. Analise a captura de pacotes. Verifique se há pacotes com endereços IP de destino que correspondem ao endereço IP do serviço kube-dns. Isso garante que as solicitações de DNS cheguem ao destino certo para resolução. Se o tráfego DNS não chegar aos pods corretos, isso pode indicar a presença de uma política de rede que está bloqueando as solicitações.

Verificar uma política de rede

Às vezes, políticas de rede restritivas podem interromper o tráfego de DNS. Para verificar se uma política de rede existe no namespace kube-system, execute o seguinte comando:

kubectl get networkpolicy -n kube-system

Se você encontrar uma política de rede, analise-a e verifique se ela permite a comunicação de DNS necessária. Por exemplo, se você tiver uma política de rede que bloqueia todo o tráfego de saída, ela também vai bloquear as solicitações de DNS.

Se a saída for No resources found in kube-system namespace, você não terá políticas de rede e poderá descartar essa possibilidade como causa do problema. Investigar registros pode ajudar você a encontrar mais pontos de falha.

Ativar o registro temporário de consultas DNS

Para ajudar a identificar problemas, como respostas DNS incorretas, ative temporariamente o registro de depuração de consultas DNS. Para ativar consultas, crie um pod com base em um pod kube-dns atual. Todas as mudanças na implantação do kube-dns são revertidas automaticamente.

Ativar o registro temporário de consultas DNS é um procedimento que consome muitos recursos. Por isso, recomendamos que você exclua o pod criado assim que coletar uma amostra adequada de registros.

Para ativar o registro temporário de consultas de DNS, siga estas etapas:

  1. Recupere um pod kube-dns e armazene-o em uma variável chamada POD:

    POD=$(kubectl -n kube-system get pods --selector=k8s-app=kube-dns -o jsonpath="{.items[0].metadata.name}")
    
  2. Crie um pod chamado kube-dns-debug. Esse pod é uma cópia do pod armazenado na variável POD, mas com o registro do dnsmasq ativado. Esse comando não modifica o pod kube-dns original:

    kubectl apply -f <(kubectl get pod -n kube-system ${POD} -o json | jq -e '
    
    (
    
    (.spec.containers[] | select(.name == "dnsmasq") | .args) += ["--log-queries"]
    
    )
    
    | (.metadata.name = "kube-dns-debug")
    
    | (del(.metadata.labels."pod-template-hash"))
    
    ')
    
  3. Inspecione os registros:

    kubectl logs -f --tail 100 -c dnsmasq -n kube-system kube-dns-debug
    

    Também é possível ver as consultas no Cloud Logging.

  4. Depois de terminar de ver os registros de consultas DNS, exclua o pod kube-dns-debug:

    kubectl -n kube-system delete pod kube-dns-debug
    

Investigar o pod kube-dns

Analise como os pods kube-dns recebem e resolvem consultas de DNS com o Cloud Logging.

Para conferir as entradas de registro relacionadas ao pod kube-dns, siga estas etapas:

  1. No console Google Cloud , acesse a página Explorador de registros.

    Acessar o Explorador de registros

  2. No painel de consulta, insira o filtro a seguir para ver eventos relacionados ao contêiner kube-dns:

    resource.type="k8s_container"
    resource.labels.namespace_name="kube-system"
    resource.labels.Pod_name:"kube-dns"
    resource.labels.cluster_name="CLUSTER_NAME"
    resource.labels.location="CLUSTER_LOCATION"
    

    Substitua:

    • CLUSTER_NAME: o nome do cluster a que o pod kube-dns pertence.
    • CLUSTER_LOCATION: o local do cluster.
  3. Clique em Executar consulta.

  4. Verifique a saída. O exemplo de saída a seguir mostra um possível erro que pode aparecer:

    {
       "timestamp": "2024-10-10T15:32:16.789Z",
       "severity": "ERROR",
       "resource": {
          "type": "k8s_container",
          "labels": {
          "namespace_name": "kube-system",
          "Pod_name": "kube-dns",
          "cluster_name": "CLUSTER_NAME",
          "location": "CLUSTER_LOCATION"
          }
       },
       "message": "Failed to resolve 'example.com': Timeout."
    },
    

    Neste exemplo, o kube-dns não conseguiu resolver example.com em um tempo razoável. Esse tipo de erro pode ser causado por vários problemas. Por exemplo, o servidor upstream pode estar configurado incorretamente no ConfigMap do kube-dns ou pode haver um alto tráfego de rede.

Se o Cloud Logging não estiver ativado, confira os registros do Kubernetes:

Pod=$(kubectl get Pods -n kube-system -l k8s-app=kube-dns -o name | head -n1)
kubectl logs -n kube-system $Pod -c dnsmasq
kubectl logs -n kube-system $Pod -c kubedns
kubectl logs -n kube-system $Pod -c sidecar

Investigar mudanças recentes no kube-dns ConfigMap

Se você encontrar falhas de resolução de DNS no cluster, uma das causas pode ser uma mudança incorreta na configuração feita no ConfigMap do kube-dns. Em particular, mudanças na configuração dos domínios de stub e das definições dos servidores upstream podem causar problemas.

Para verificar se há atualizações nas configurações do domínio stub, siga estas etapas:

  1. No console Google Cloud , acesse a página Explorador de registros.

    Acessar o Explorador de registros

  2. No painel de consulta, digite a seguinte consulta:

    resource.labels.cluster_name="clouddns"
    resource.type="k8s_container"
    resource.labels.namespace_name="kube-system"
    labels.k8s-pod/k8s-app="kube-dns" jsonPayload.message=~"Updated stubDomains to"
    
  3. Clique em Executar consulta.

  4. Verifique a saída. Se houver atualizações, a saída será semelhante a esta:

    Updated stubDomains to map[example.com: [8.8.8.8 8.8.4.4 1.1.3.3 1.0.8.111]]
    

    Se houver uma atualização, expanda o resultado para saber mais sobre as mudanças. Verifique se todos os domínios de stub e os servidores DNS upstream correspondentes estão definidos corretamente. Entradas incorretas podem causar falhas de resolução para esses domínios.

Para verificar mudanças no servidor upstream, siga estas etapas:

  1. No console Google Cloud , acesse a página Explorador de registros.

    Acessar o Explorador de registros

  2. No painel de consulta, digite a seguinte consulta:

    resource.labels.cluster_name="clouddns"
    resource.type="k8s_container" resource.labels.namespace_name="kube-system"
    labels.k8s-pod/k8s-app="kube-dns" jsonPayload.message=~"Updated upstreamNameservers to"
    
  3. Clique em Executar consulta.

  4. Verifique a saída. Se houver mudanças, a saída será semelhante a esta:

    Updated upstreamNameservers to [8.8.8.8]
    

    Expanda o resultado para saber mais sobre as mudanças. Verifique se a lista de servidores DNS upstream está correta e se eles podem ser acessados do cluster. Se esses servidores estiverem indisponíveis ou mal configurados, a resolução geral de DNS poderá falhar.

Se você verificou mudanças nos domínios stub e nos servidores upstream, mas não encontrou resultados, confira todas as mudanças com o seguinte filtro:

resource.type="k8s_cluster"
protoPayload.resourceName:"namespaces/kube-system/configmaps/kube-dns"
protoPayload.methodName=~"io.k8s.core.v1.configmaps."

Analise as mudanças listadas para ver se elas causaram o erro.

Entrar em contato com o atendimento ao cliente do Cloud

Se você seguiu as seções anteriores, mas ainda não consegue diagnosticar a causa do problema, entre em contato com o Cloud Customer Care.

Resolver problemas comuns

Se você tiver um erro ou problema específico, siga as orientações nas seções a seguir.

Problema: tempos limite de DNS intermitentes

Se você notar tempos limite intermitentes de resolução de DNS que ocorrem quando há um aumento no tráfego de DNS ou quando o horário comercial começa, tente as seguintes soluções para otimizar a performance do DNS:

  • Verifique o número de pods kube-dns em execução no cluster e compare com o número total de nós do GKE. Se não houver recursos suficientes, considere aumentar a escala dos pods do kube-dns.

  • Para melhorar o tempo médio de busca DNS, ative o cache DNS NodeLocal.

  • A resolução de DNS para nomes externos pode sobrecarregar o pod kube-dns. Para reduzir o número de consultas, ajuste a configuração ndots no arquivo /etc/resolv.conf. ndots representa o número de pontos que precisam aparecer em um nome de domínio para resolver uma consulta antes da consulta absoluta inicial.

    O exemplo a seguir é o arquivo /etc/resolv.conf de um pod de aplicativo:

    search default.svc.cluster.local svc.cluster.local cluster.local c.PROJECT_ID.internal google.internal
    nameserver 10.52.16.10
    options ndots:5
    

    Neste exemplo, o kube-dns procura cinco pontos no domínio consultado. Se o pod fizer uma chamada de resolução de DNS para example.com, os registros serão semelhantes ao exemplo a seguir:

    "A IN example.com.default.svc.cluster.local." NXDOMAIN
    "A IN example.com.svc.cluster.local." NXDOMAIN
    "A IN example.com.cluster.local." NXDOMAIN
    "A IN example.com.google.internal." NXDOMAIN
    "A IN example.com.c.PROJECT_ID.internal." NXDOMAIN
    "A IN example.com." NOERROR
    

    Para resolver esse problema, mude o valor de ndots para 1 e procure apenas um ponto ou adicione um ponto (.) ao final do domínio que você consulta ou usa. Exemplo:

    dig example.com.
    

Problema: as consultas DNS falham de forma intermitente em alguns nós

Se você notar que as consultas DNS estão falhando intermitentemente em alguns nós, poderá ver os seguintes sintomas:

  • Quando você executa comandos dig no endereço IP do serviço kube-dns ou no endereço IP do pod, as consultas DNS falham intermitentemente com tempos limite.
  • A execução de comandos dig de um pod no mesmo nó que o pod kube-dns falha.

Para resolver esse problema, siga estas etapas:

  1. Faça um teste de conectividade. Defina o pod ou nó problemático como a origem e o destino como o endereço IP do pod kube-dns. Isso permite verificar se você tem as regras de firewall necessárias para permitir esse tráfego.
  2. Se o teste não for bem-sucedido e o tráfego estiver sendo bloqueado por uma regra de firewall, use o Cloud Logging para listar as mudanças manuais feitas nas regras de firewall. Procure mudanças que bloqueiem um tipo específico de tráfego:

    1. No console Google Cloud , acesse a página Explorador de registros.

      Acessar o Explorador de registros

    2. No painel de consulta, digite a seguinte consulta:

      logName="projects/project-name/logs/cloudaudit.googleapis.com/activity"
      resource.type="gce_firewall_rule"
      
    3. Clique em Executar consulta. Use a saída da consulta para determinar se alguma mudança foi feita. Se você encontrar algum erro, corrija e reaplique a regra de firewall.

      Não faça mudanças em nenhuma regra de firewall automatizada.

  3. Se não houver mudanças nas regras de firewall, verifique a versão do pool de nós e confira se ela é compatível com o plano de controle e outros pools de nós em funcionamento. Se algum dos pools de nós do cluster tiver mais de duas versões secundárias mais antigas que o plano de controle, isso pode causar problemas. Para mais informações sobre essa incompatibilidade, consulte A versão do nó não é compatível com a versão do plano de controle.

  4. Para determinar se as solicitações estão sendo enviadas para o IP de serviço kube-dns correto, capture o tráfego de rede no nó problemático e filtre a porta 53 (tráfego DNS). Capture o tráfego nos próprios pods kube-dns para ver se as solicitações estão chegando aos pods pretendidos e se estão sendo resolvidas corretamente.

A seguir