Acerca do kube-dns para o GKE

Se estiver a executar aplicações em clusters padrão, o kube-dns é o fornecedor de DNS predefinido que ajuda a ativar a deteção de serviços e a comunicação. Este documento descreve como gerir o DNS com o kube-dns, incluindo a respetiva arquitetura, configuração e práticas recomendadas para otimizar a resolução de DNS no seu ambiente do GKE.

Este documento destina-se a programadores, administradores e arquitetos responsáveis pela gestão de DNS no GKE. Para ver o contexto das funções e tarefas comuns no Google Cloud, consulte o artigo Funções e tarefas comuns do utilizador do GKE Enterprise.

Antes de começar, certifique-se de que conhece os serviços Kubernetes e os conceitos DNS gerais.

Compreenda a arquitetura kube-dns

O kube-dns funciona no seu cluster do GKE para permitir a resolução de DNS entre Pods e serviços.

O diagrama seguinte mostra como os seus Pods interagem com o serviço kube-dns:

Figura 1: diagrama que mostra como os pods enviam consultas DNS para o serviço `kube-dns`, que é suportado por pods `kube-dns`. Os pods `kube-dns` processam a resolução de DNS interna e encaminham as consultas externas para servidores DNS a montante.

Componentes principais

O kube-dns inclui os seguintes componentes principais:

  • kube-dns Pods: estes pods executam o kube-dns software do servidor. São executadas várias réplicas destes pods no espaço de nomes kube-system, e oferecem elevada disponibilidade e redundância.
  • kube-dns Serviço: este serviço do Kubernetes do tipo ClusterIP agrupa os kube-dnspods e expõe-nos como um único ponto final estável. O ClusterIP atua como o servidor DNS para o cluster, que os pods usam para enviar consultas DNS. kube-dns suporta até 1000 pontos finais por serviço sem interface.
  • kube-dns-autoscaler: este Pod ajusta o número de réplicas com base no tamanho do cluster, que inclui o número de nós e núcleos de CPU.kube-dns Esta abordagem ajuda a garantir que o kube-dns consegue processar cargas de consultas de DNS variáveis.

Resolução de DNS interna

Quando um Pod precisa de resolver um nome DNS no domínio do cluster, como myservice.my-namespace.svc.cluster.local, ocorre o seguinte processo:

  1. Configuração de DNS do pod: o kubelet em cada nó configura o ficheiro /etc/resolv.conf do pod. Este ficheiro usa o kube-dns do serviço ClusterIP como servidor de nomes.
  2. Consulta DNS: o Pod envia uma consulta DNS para o kube-dns serviço.
  3. Resolução de nomes: kube-dns recebe a consulta. Procura o endereço IP correspondente nos respetivos registos DNS internos e responde ao pod.
  4. Comunicação: o pod usa o endereço IP resolvido para comunicar com o serviço de destino.

Resolução de DNS externa

Quando um Pod precisa de resolver um nome DNS externo ou um nome que esteja fora do domínio do cluster, o kube-dns atua como um resolvedor recursivo. Encaminha a consulta para servidores DNS a montante configurados no respetivo ficheiro ConfigMap. Também pode configurar resolvedores personalizados para domínios específicos, que também são conhecidos como domínios stub. Esta configuração direciona o kube-dns para encaminhar pedidos para esses domínios para servidores DNS upstream específicos.

Configure o DNS do pod

No GKE, o agente kubelet em cada nó configura as definições de DNS para os pods que são executados nesse nó.

Configure o ficheiro /etc/resolv.conf

Quando o GKE cria um pod, o agente kubelet modifica o ficheiro /etc/resolv.conf do pod. Este ficheiro configura o servidor DNS para a resolução de nomes e especifica domínios de pesquisa. Por predefinição, o kubelet configura o pod para usar o serviço DNS interno do cluster, kube-dns, como servidor de nomes. Também preenche os domínios de pesquisa no ficheiro. Estes domínios de pesquisa permitem-lhe usar nomes não qualificados em consultas DNS. Por exemplo, se um Pod consultar myservice, o Kubernetes tenta primeiro resolver myservice.default.svc.cluster.local, depois myservice.svc.cluster.local e, em seguida, outros domínios da lista search.

O exemplo seguinte mostra uma configuração /etc/resolv.conf predefinida:

nameserver 10.0.0.10
search default.svc.cluster.local svc.cluster.local cluster.local c.my-project-id.internal google.internal
options ndots:5

Este ficheiro tem as seguintes entradas:

  • nameserver: define o ClusterIP do serviço kube-dns.
  • search: define os domínios de pesquisa que são anexados a nomes não qualificados durante as procuras de DNS.
  • options ndots:5: define o limite para quando o GKE considera que um nome está totalmente qualificado. Um nome é considerado totalmente qualificado se tiver cinco ou mais pontos.

Os pods configurados com a definição hostNetwork: true herdam a respetiva configuração de DNS do anfitrião e não consultam diretamente o kube-dns.

Personalizar kube-dns

O kube-dns oferece uma resolução de DNS predefinida robusta. Pode personalizar o respetivo comportamento para necessidades específicas, como melhorar a eficiência da resolução ou usar resolvedores de DNS preferenciais. Os domínios stub e os servidores de nomes upstream são configurados através da modificação do kube-dns ConfigMap no espaço de nomes kube-system.

Modifique o kube-dns ConfigMap

Para modificar o kube-dns ConfigMap, faça o seguinte:

  1. Abra o ConfigMap para edição:

    kubectl edit configmap kube-dns -n kube-system
    
  2. Na secção data, adicione os campos stubDomains e upstreamNameservers para:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      labels:
        addonmanager.kubernetes.io/mode: EnsureExists
      name: kube-dns
      namespace: kube-system
    data:
      stubDomains: |
        {
          "example.com": [
            "8.8.8.8",
            "8.8.4.4"
          ],
          "internal": [ # Required if your upstream nameservers can't resolve GKE internal domains
            "169.254.169.254" # IP of the metadata server
          ]
        }
      upstreamNameservers: |
        [
          "8.8.8.8", # Google Public DNS
          "1.1.1.1" # Cloudflare DNS
        ]
    
  3. Guarde o ConfigMap. O kube-dns recarrega automaticamente a configuração.

Domínios stub

Os domínios stub permitem-lhe definir resolvedores de DNS personalizados para domínios específicos. Quando um pod consulta um nome nesse domínio fictício, o kube-dns encaminha a consulta para o resolvedor especificado em vez de usar o respetivo mecanismo de resolução predefinido.

Inclui uma secção stubDomains no kube-dns ConfigMap.

Esta secção especifica o domínio e os servidores de nomes a montante correspondentes. Em seguida, o kube-dns encaminha as consultas de nomes nesse domínio para os servidores designados. Por exemplo, pode encaminhar todas as consultas DNS para internal.mycompany.com para 192.168.0.10 e adicionar "internal.mycompany.com": ["192.168.0.10"] a stubDomains.

Quando define um resolvedor personalizado para um domínio stub, como example.com,kube-dns encaminha todos os pedidos de resolução de nomes para esse domínio, incluindo subdomínios como *.example.com, para os servidores especificados.

Servidores de nomes a montante

Pode configurar o kube-dns para usar servidores de nomes upstream personalizados para resolver nomes de domínios externos. Esta configuração indica ao kube-dns para encaminhar todos os pedidos DNS, exceto os pedidos para o domínio interno do cluster (*.cluster.local), para os servidores upstream designados. Os domínios internos, como metadata.internal e *.google.internal, podem não ser resolvidos pelos seus servidores upstream personalizados. Se ativar a federação de identidade da carga de trabalho para o GKE ou tiver cargas de trabalho que dependam destes domínios, adicione um domínio stub para internal no ConfigMap. Use 169.254.169.254, o endereço IP do servidor de metadados, como o resolvedor para este domínio fictício.

Faça a gestão de uma implementação personalizada do kube-dns

Num GKE padrão, o kube-dns é executado como uma implementação. Uma implementação kube-dns personalizada significa que, como administrador do cluster, pode controlar a implementação e personalizá-la de acordo com as suas necessidades, em vez de usar a implementação predefinida fornecida pelo GKE.

Motivos para uma implementação personalizada

Pondere uma implementação kube-dns personalizada pelos seguintes motivos:

  • Atribuição de recursos: ajuste os recursos de CPU e memória para kube-dns Pods para otimizar o desempenho em clusters com elevado tráfego de DNS.
  • Versão da imagem: use uma versão específica da imagem kube-dns ou mude para um fornecedor de DNS alternativo, como o CoreDNS.
  • Configuração avançada: personalize os níveis de registo, as políticas de segurança e o comportamento de colocação em cache de DNS.

Escala automática para implementações personalizadas

O kube-dns-autoscaler integrado funciona com a implementação kube-dns predefinida. Se criar uma kube-dnsimplementação personalizada, o escalador automático incorporado não a gere. Como tal, tem de configurar um escalador automático separado que esteja especificamente configurado para monitorizar e ajustar a quantidade de réplicas da sua implementação personalizada. Esta abordagem envolve a criação e a implementação da sua própria configuração do redimensionador automático no cluster.

Quando gere uma implementação personalizada, é responsável por todos os respetivos componentes, como manter a imagem do escalador automático atualizada. A utilização de componentes desatualizados pode provocar uma degradação do desempenho ou falhas de DNS.

Para obter instruções detalhadas sobre como configurar e gerir a sua própria implementação, consulte o artigo Configurar uma implementação kube-dns personalizada.kube-dns

Resolver problemas

Para informações sobre a resolução de problemas de kube-dns, consulte as seguintes páginas:

Otimize a resolução de DNS

Esta secção descreve problemas comuns e práticas recomendadas para gerir o DNS no GKE.

Limite de domínios de pesquisa de um dnsConfig

O Kubernetes limita o número de domínios de pesquisa DNS a 32. Se tentar definir mais de 32 domínios de pesquisa no dnsConfig de um Pod, o kube-apiserver não cria o Pod e apresenta um erro semelhante ao seguinte:

The Pod "dns-example" is invalid: spec.dnsConfig.searches: Invalid value: []string{"ns1.svc.cluster-domain.example", "my.dns.search.suffix1", "ns2.svc.cluster-domain.example", "my.dns.search.suffix2", "ns3.svc.cluster-domain.example", "my.dns.search.suffix3", "ns4.svc.cluster-domain.example", "my.dns.search.suffix4", "ns5.svc.cluster-domain.example", "my.dns.search.suffix5", "ns6.svc.cluster-domain.example", "my.dns.search.suffix6", "ns7.svc.cluster-domain.example", "my.dns.search.suffix7", "ns8.svc.cluster-domain.example", "my.dns.search.suffix8", "ns9.svc.cluster-domain.example", "my.dns.search.suffix9", "ns10.svc.cluster-domain.example", "my.dns.search.suffix10", "ns11.svc.cluster-domain.example", "my.dns.search.suffix11", "ns12.svc.cluster-domain.example", "my.dns.search.suffix12", "ns13.svc.cluster-domain.example", "my.dns.search.suffix13", "ns14.svc.cluster-domain.example", "my.dns.search.suffix14", "ns15.svc.cluster-domain.example", "my.dns.search.suffix15", "ns16.svc.cluster-domain.example", "my.dns.search.suffix16", "my.dns.search.suffix17"}: must not have more than 32 search paths.

O kube-apiserver devolve esta mensagem de erro em resposta a uma tentativa de criação de um grupo de anúncios. Para resolver este problema, remova os caminhos de pesquisa adicionais da configuração.

Limite de nameservers upstream para kube-dns

kube-dns limita o número de valores upstreamNameservers a três. Se definir mais de três, o Cloud Logging apresenta um erro semelhante ao seguinte:

Invalid configuration: upstreamNameserver cannot have more than three entries (value was &TypeMeta{Kind:,APIVersion:,}), ignoring update

Neste cenário, kube-dns ignora a configuração upstreamNameservers e continua a usar a configuração válida anterior. Para resolver este problema, remova o upstreamNameservers adicional de kube-dns ConfigMap.

Aumente a escala kube-dns

Nos clusters padrão, pode usar um valor inferior para nodesPerReplica para que sejam criados mais kube-dnspods quando os nós do cluster forem dimensionados. Recomendamos vivamente que defina um valor explícito para o campo max para ajudar a garantir que a máquina virtual (VM) do plano de controlo do GKE não fica sobrecarregada devido ao grande número de pods kube-dns que estão a monitorizar a API Kubernetes.

Pode definir o valor do campo max para o número de nós no cluster. Se o cluster tiver mais de 500 nós, defina o valor do campo max como 500.

Pode modificar o número de réplicas kube-dns editando o valor de kube-dns-autoscaler ConfigMap.

kubectl edit configmap kube-dns-autoscaler --namespace=kube-system

O resultado é semelhante ao seguinte:

linear: '{"coresPerReplica":256, "nodesPerReplica":16,"preventSinglePointFailure":true}'

O número de réplicas kube-dns é calculado através da seguinte fórmula:

replicas = max( ceil( cores * 1/coresPerReplica ) , ceil( nodes * 1/nodesPerReplica ) )
kube-dns

Para aumentar a escala, altere o valor do campo nodesPerReplica para um valor inferior e inclua um valor para o campo max.

linear: '{"coresPerReplica":256, "nodesPerReplica":8,"max": 15,"preventSinglePointFailure":true}'

Esta configuração cria um kube-dnspod para cada oito nós no cluster. Um cluster de 24 nós tem três réplicas e um cluster de 40 nós tem cinco réplicas. Se o cluster crescer para além de 120 nós, o número de réplicas não cresce para além de 15, que é o valor do campo max.kube-dns

Para ajudar a garantir um nível base de disponibilidade do DNS no seu cluster, defina uma quantidade mínima de réplicas para o campo kube-dns.

O resultado do kube-dns-autoscaler ConfigMap com o campo min configurado é semelhante ao seguinte:

linear: '{"coresPerReplica":256, "nodesPerReplica":8,"max": 15,"min": 5,"preventSinglePointFailure":true}'

Melhore os tempos de procura de DNS

Vários fatores podem causar uma latência elevada com procuras de DNS ou falhas de resolução de DNS com o fornecedor kube-dns predefinido. As aplicações podem ter estes problemas como erros getaddrinfo EAI_AGAIN, que indicam uma falha temporária na resolução de nomes. As causas incluem o seguinte:

  • Procuras de DNS frequentes na sua carga de trabalho.
  • Densidade de pods elevada por nó.
  • Executar o kube-dns em VMs Spot ou VMs preemptíveis, o que pode levar a eliminações inesperadas de nós.
  • Volume de consultas elevado que excede a capacidade da instância dnsmasq no agrupamento kube-dns. Uma única instância kube-dns tem um limite de 200 ligações TCP simultâneas na versão 1.31 e posteriores do GKE, e um limite de 20 ligações TCP simultâneas na versão 1.30 e anteriores do GKE.

Para melhorar os tempos de procura de DNS, faça o seguinte:

  • Evite executar componentes críticos do sistema, como kube-dns, em VMs de Spot ou VMs preemptíveis. Crie, pelo menos, um node pool com VMs padrão e sem VMs Spot nem VMs preemptivas. Use restrições e tolerâncias para ajudar a garantir que as cargas de trabalho críticas são agendadas nestes nós fiáveis.
  • Ative o NodeLocal DNSCache. O NodeLocal DNSCache armazena em cache as respostas DNS diretamente em cada nó, o que reduz a latência e a carga no serviço kube-dns. Se ativar o NodeLocal DNSCache e usar políticas de rede com regras de negação predefinidas, adicione uma política para permitir que as cargas de trabalho enviem consultas DNS para os pods.node-local-dns
  • Aumente a escala kube-dns.
  • Certifique-se de que a sua aplicação usa funções baseadas em dns.resolve* em vez de funções baseadas em dns.lookup, porque dns.lookup é síncrono.
  • Use nomes do domínio totalmente qualificados (FQDNs), por exemplo, https://google.com./ em vez de https://google.com/.

Podem ocorrer falhas de resolução de DNS durante as atualizações do cluster do GKE devido a atualizações simultâneas de componentes do plano de controlo, incluindo o kube-dns. Normalmente, estas falhas afetam uma pequena percentagem de nós. Teste exaustivamente as atualizações de clusters num ambiente de não produção antes de as aplicar a clusters de produção.

Garanta a deteção de serviços

kube-dns só cria registos de DNS para serviços que tenham pontos finais. Se um serviço não tiver pontos finais, o kube-dns não cria registos DNS para esse serviço.

Faça a gestão das discrepâncias de TTL de DNS

Se kube-dns receber uma resposta DNS de um resolvedor DNS a montante com um TTL grande ou infinito, mantém este valor de TTL. Este comportamento pode criar uma discrepância entre a entrada em cache e o endereço IP real.

O GKE resolve este problema em versões específicas do plano de controlo, como 1.21.14-gke.9100 e posteriores ou 1.22.15-gke.2100 e posteriores. Estas versões definem um valor TTL máximo de 30 segundos para qualquer resposta DNS que tenha um TTL superior. Este comportamento é semelhante ao NodeLocal DNSCache.

Veja as métricas de kube-dns

Pode obter métricas sobre consultas DNS no seu cluster diretamente dos kube-dns pods.

  1. Encontre os kube-dnspodskube-system no espaço de nomes kube-system:

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

    O resultado é semelhante ao seguinte:

    NAME                        READY     STATUS    RESTARTS   AGE
    kube-dns-548976df6c-98fkd   4/4       Running   0          48m
    kube-dns-548976df6c-x4xsh   4/4       Running   0          47m
    
  2. Escolha um dos pods e configure o encaminhamento de portas para aceder às métricas desse pod:

    • A porta 10055 expõe as métricas kube-dns.
    • A porta 10054 expõe as métricas dnsmasq.

    Substitua POD_NAME pelo nome do Pod escolhido.

    POD_NAME="kube-dns-548976df6c-98fkd" # Replace with your pod name
    kubectl port-forward pod/${POD_NAME} -n kube-system 10055:10055 10054:10054
    

    O resultado é semelhante ao seguinte:

    Forwarding from 127.0.0.1:10054 -> 10054
    Forwarding from 127.0.0.1:10055 -> 10055
    
  3. Numa nova sessão de terminal, use o comando curl para aceder aos endpoints de métricas.

    # Get kube-dns metrics
    curl http://127.0.0.1:10055/metrics
    
    # Get dnsmasq metrics
    curl http://127.0.0.1:10054/metrics
    

    O resultado será semelhante ao seguinte:

    kubedns_dnsmasq_errors 0
    kubedns_dnsmasq_evictions 0
    kubedns_dnsmasq_hits 3.67351e+06
    kubedns_dnsmasq_insertions 254114
    kubedns_dnsmasq_max_size 1000
    kubedns_dnsmasq_misses 3.278166e+06
    

O que se segue?