Sobre o kube-dns para GKE

Se você estiver executando aplicativos em clusters Standard, o kube-dns será o provedor de DNS padrão que ajuda a ativar a descoberta e a comunicação de serviços. Este documento descreve como gerenciar o DNS com o kube-dns, incluindo arquitetura, configuração e práticas recomendadas para otimizar a resolução de DNS no ambiente do GKE.

Este documento é destinado a desenvolvedores, administradores e arquitetos responsáveis por gerenciar o DNS no GKE. Para saber mais sobre papéis e tarefas comuns no Google Cloud, consulte Funções e tarefas de usuário comuns do GKE Enterprise.

Antes de começar, familiarize-se com os serviços do Kubernetes e os conceitos gerais de DNS.

Entender a arquitetura do kube-dns

O kube-dns opera no cluster do GKE para ativar a resolução de DNS entre pods e serviços.

O diagrama a seguir mostra como seus pods interagem com o serviço kube-dns:

Figura 1: diagrama mostrando como os pods enviam consultas DNS ao serviço "kube-dns", que é apoiado por pods "kube-dns". Os pods `kube-dns` processam
a resolução de DNS interno e encaminham consultas externas para servidores DNS
upstream.

Principais componentes

O kube-dns inclui os seguintes componentes principais:

  • Pods kube-dns:executam o software do servidor kube-dns. Várias réplicas desses pods são executadas no namespace kube-system e oferecem alta disponibilidade e redundância.
  • Serviço kube-dns:este Serviço do Kubernetes do tipo ClusterIP agrupa os pods kube-dns e os expõe como um único endpoint estável. O ClusterIP atua como o servidor DNS do cluster, que os pods usam para enviar consultas DNS. O kube-dns aceita até 1.000 endpoints por serviço headless.
  • kube-dns-autoscaler:esse pod ajusta o número de réplicas kube-dns com base no tamanho do cluster, que inclui o número de nós e núcleos de CPU. Essa abordagem ajuda a garantir que o kube-dns possa lidar com cargas de consultas de DNS variadas.

Resolução de DNS interna

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

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

Resolução de DNS externa

Quando um pod precisa resolver um nome DNS externo ou um nome fora do domínio do cluster, o kube-dns atua como um resolvedor recursivo. Ele encaminha a consulta para servidores DNS upstream configurados no arquivo ConfigMap. Você também pode configurar resolvedores personalizados para domínios específicos, também conhecidos como domínios de stub. Essa configuração direciona o kube-dns para encaminhar solicitações desses domínios para servidores DNS upstream específicos.

Configurar o DNS do pod

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

Configurar o arquivo /etc/resolv.conf

Quando o GKE cria um pod, o agente kubelet modifica o arquivo /etc/resolv.conf do pod. Esse arquivo configura o servidor DNS para resolução de nomes e especifica domínios de pesquisa. Por padrão, o kubelet configura o pod para usar o serviço DNS interno do cluster, kube-dns, como servidor de nomes. Ele também preenche os domínios de pesquisa no arquivo. Com eles, é possível usar nomes não qualificados em consultas DNS. Por exemplo, se um pod consultar myservice, o Kubernetes primeiro tentará resolver myservice.default.svc.cluster.local, depois myservice.svc.cluster.local e, em seguida, outros domínios da lista search.

O exemplo a seguir mostra uma configuração /etc/resolv.conf padrão:

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

Esse arquivo 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 buscas de DNS.
  • options ndots:5: define o limite para quando o GKE considera um nome totalmente qualificado. Um nome é considerado totalmente qualificado se tiver cinco ou mais pontos.

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

Personalizar kube-dns

O kube-dns oferece uma resolução de DNS padrão robusta. É possível personalizar o comportamento dele para necessidades específicas, como melhorar a eficiência da resolução ou usar resolvedores de DNS preferidos. Para configurar os domínios de stub e os servidores de nomes upstream, modifique o ConfigMap kube-dns no namespace kube-system.

Modificar o ConfigMap kube-dns

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

  1. Abra o ConfigMap para edição:

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

    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. Salve o ConfigMap. O kube-dns recarrega automaticamente a configuração.

Domínios stub

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

Você inclui uma seção stubDomains no kube-dns ConfigMap.

Esta seção especifica o domínio e os servidores de nomes upstream correspondentes. Em seguida, kube-dns encaminha consultas de nomes dentro desse domínio para os servidores designados. Por exemplo, é possível encaminhar todas as consultas DNS de internal.mycompany.com para 192.168.0.10 e adicionar "internal.mycompany.com": ["192.168.0.10"] a stubDomains.

Quando você define um resolvedor personalizado para um domínio de stub, como example.com, o kube-dns encaminha todas as solicitações de resolução de nome para esse domínio, incluindo subdomínios como *.example.com, para os servidores especificados.

Servidores de nomes upstream

É possível configurar o kube-dns para usar servidores de nomes upstream personalizados e resolver nomes de domínio externos. Essa configuração instrui o kube-dns a encaminhar todas as solicitações de DNS, exceto as do domínio interno do cluster (*.cluster.local), para os servidores upstream designados. Domínios internos, como metadata.internal e *.google.internal, podem não ser resolvidos pelos seus servidores upstream personalizados. Se você ativar a federação de identidade da carga de trabalho para GKE ou tiver cargas de trabalho que dependam desses domínios, adicione um domínio stub para internal em ConfigMap. Use 169.254.169.254, o endereço IP do servidor de metadados, como o resolver para esse domínio stub.

Gerenciar uma implantação personalizada do kube-dns

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

Motivos para uma implantação personalizada

Considere uma implantação personalizada do kube-dns pelos seguintes motivos:

  • Alocação de recursos:ajuste os recursos de CPU e memória para pods kube-dns e otimize o desempenho em clusters com alto tráfego de DNS.
  • Versão da imagem:use uma versão específica da imagem kube-dns ou mude para um provedor de DNS alternativo, como o CoreDNS.
  • Configuração avançada:personalize níveis de geração de registros, políticas de segurança e comportamento de cache de DNS.

Escalonamento automático para implantações personalizadas

O kube-dns-autoscaler integrado funciona com a implantação kube-dns padrão. Se você criar uma implantação kube-dns personalizada, o escalonador automático integrado não a gerenciará. Portanto, é necessário configurar um escalonador automático separado, especificamente configurado para monitorar e ajustar a contagem de réplicas da sua implantação personalizada. Essa abordagem envolve a criação e a implantação da sua própria configuração de escalonador automático no cluster.

Ao gerenciar uma implantação personalizada, você é responsável por todos os componentes dela, como manter a imagem do escalonador automático atualizada. O uso de componentes desatualizados pode levar à degradação da performance ou a falhas de DNS.

Para instruções detalhadas sobre como configurar e gerenciar sua própria implantação do kube-dns, consulte Como configurar uma implantação personalizada do kube-dns.

Resolver problemas

Para informações sobre como resolver problemas com kube-dns, consulte as seguintes páginas:

Otimizar a resolução de DNS

Nesta seção, descrevemos problemas comuns e práticas recomendadas para gerenciar o DNS no GKE.

Limite de domínios de pesquisa dnsConfig de um pod

O Kubernetes limita o número de domínios de pesquisa DNS a 32. Se você tentar definir mais de 32 domínios de pesquisa em um dnsConfig de um pod, o kube-apiserver não vai criar o pod, com um erro semelhante a este:

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 retorna essa mensagem de erro em resposta a uma tentativa de criação de pod. Para resolver esse problema, remova os caminhos de pesquisa extras da configuração.

Limite de nameservers upstream para kube-dns

O kube-dns limita o número de valores upstreamNameservers a três. Se você definir mais de três, o Cloud Logging vai mostrar um erro semelhante a este:

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

Nesse cenário, kube-dns ignora a configuração upstreamNameservers e continua usando a configuração válida anterior. Para resolver esse problema, remova o upstreamNameservers extra do kube-dns ConfigMap.

Aumentar o escalonamento vertical de kube-dns

Em clusters Standard, use um valor menor para nodesPerReplica para que mais pods kube-dns sejam criados quando os nós do cluster escalonar verticalmente. É altamente recomendável definir um valor explícito para o campo max para garantir que a máquina virtual (VM) do plano de controle do GKE não fique sobrecarregada devido ao grande número de pods kube-dns que monitoram a API Kubernetes.

É possível definir o valor do campo max como 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.

É possível modificar o número de réplicas de kube-dns editando o kube-dns-autoscaler ConfigMap.

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

O resultado será o seguinte:

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

O número de réplicas de kube-dns é calculado usando a seguinte fórmula:

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

Para escalonar verticalmente, mude o valor do campo nodesPerReplica para um valor menor e inclua um valor para o campo max.

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

Essa configuração cria um pod kube-dns 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 ultrapassar 120 nós, o número de réplicas de kube-dns não vai ultrapassar 15, que é o valor do campo max.

Para garantir um nível básico de disponibilidade de DNS no cluster, defina uma contagem mínima de réplicas para o campo kube-dns.

A saída do kube-dns-autoscaler ConfigMap com o campo min configurado é semelhante a esta:

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

Melhorar os tempos de busca DNS

Vários fatores podem causar alta latência com buscas DNS ou falhas de resolução de DNS com o provedor kube-dns padrão. Os aplicativos podem apresentar esses problemas como erros getaddrinfo EAI_AGAIN, que indicam uma falha temporária na resolução de nomes. As causas incluem:

  • Buscas DNS frequentes na sua carga de trabalho.
  • Alta densidade de pods por nó.
  • Executar kube-dns em VMs spot ou preemptivas, o que pode levar a exclusões inesperadas de nós.
  • Alto volume de consultas que excede a capacidade da instância dnsmasq no pod kube-dns. Uma única instância kube-dns tem um limite de 200 conexões TCP simultâneas no GKE versão 1.31 e mais recente, e um limite de 20 conexões TCP simultâneas no GKE versão 1.30 e anteriores.

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

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

Falhas de resolução de DNS podem ocorrer durante upgrades cluster do GKE devido a upgrades simultâneos de componentes do plano de controle, incluindo kube-dns. Essas falhas normalmente afetam uma pequena porcentagem de nós. Teste completamente os upgrades de cluster em um ambiente que não seja de produção antes de aplicá-los aos clusters de produção.

Garantir a descoberta de serviços

O kube-dns só cria registros DNS para serviços que têm endpoints. Se um serviço não tiver endpoints, o kube-dns não vai criar registros DNS para esse serviço.

Gerenciar discrepâncias de TTL de DNS

Se o kube-dns receber uma resposta DNS de um resolvedor de DNS upstream com um TTL grande ou infinito, ele vai manter esse valor de TTL. Esse comportamento pode criar uma discrepância entre a entrada em cache e o endereço IP real.

O GKE resolve esse problema em versões específicas do plano de controle, como 1.21.14-gke.9100 e mais recentes ou 1.22.15-gke.2100 e mais recentes. Essas versões definem um valor máximo de TTL como 30 segundos para qualquer resposta DNS que tenha um TTL maior. Esse comportamento é semelhante ao NodeLocal DNSCache.

Conferir métricas de kube-dns

É possível recuperar métricas sobre consultas de DNS no cluster diretamente dos kube-dns pods.

  1. Encontre os pods kube-dns no namespace kube-system:

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

    O resultado será o 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 acessar as métricas dele:

    • A porta 10055 expõe métricas kube-dns.
    • A porta 10054 expõe 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 será o seguinte:

    Forwarding from 127.0.0.1:10054 -> 10054
    Forwarding from 127.0.0.1:10055 -> 10055
    
  3. Em uma nova sessão do terminal, use o comando curl para acessar os 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
    

    A saída será semelhante a esta:

    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
    

A seguir