Configurar NodeLocal DNSCache

En esta página se explica cómo mejorar la latencia de búsqueda de DNS en un clúster de Google Kubernetes Engine (GKE) mediante NodeLocal DNSCache.

En los clústeres de GKE Autopilot, NodeLocal DNSCache está habilitado de forma predeterminada y no se puede anular.

Arquitectura

NodeLocal DNSCache es un complemento de GKE que puedes ejecutar además de kube-dns.

GKE implementa NodeLocal DNSCache como un DaemonSet que ejecuta una caché de DNS en cada nodo del clúster.

Cuando un pod hace una solicitud de DNS, esta se envía a la caché de DNS que se ejecuta en el mismo nodo que el pod. Si la caché no puede resolver la solicitud de DNS, la reenvía a uno de los siguientes lugares en función del destino de la consulta:

  • kube-dns: todas las consultas del dominio DNS del clúster (cluster.local) se reenvían a kube-dns. Los pods node-local-dns usan el servicio kube-dns-upstream para acceder a los pods kube-dns. En el siguiente diagrama, la dirección IP del servicio kube-dns es 10.0.0.10:53.
  • Dominios stub personalizados o servidores de nombres upstream: las consultas se reenvían directamente desde los pods de NodeLocal DNSCache.
  • Cloud DNS: todas las demás consultas se reenvían al servidor de metadatos local que se ejecuta en el mismo nodo que el pod del que procede la consulta. El servidor de metadatos local accede a Cloud DNS.

La ruta de una solicitud de DNS, tal como se describe en el párrafo anterior.

Cuando habilitas NodeLocal DNSCache en un clúster, GKE vuelve a crear todos los nodos del clúster que ejecutan GKE 1.15 o una versión posterior según el proceso de actualización de nodos.

Una vez que GKE haya recreado los nodos, GKE añadirá automáticamente la etiqueta addon.gke.io/node-local-dns-ds-ready=true a los nodos. No debes añadir esta etiqueta a los nodos del clúster manualmente.

Ventajas de NodeLocal DNSCache

NodeLocal DNSCache ofrece las siguientes ventajas:

  • Reducción del tiempo medio de petición de DNS
  • Las conexiones de los pods a su caché local no crean entradas en la tabla conntrack. De esta forma, se evitan las conexiones rechazadas y perdidas causadas por el agotamiento de la tabla conntrack y las condiciones de carrera.
  • Puedes usar NodeLocal DNSCache con Cloud DNS para GKE.
  • Las consultas de DNS de URLs externas (URLs que no hacen referencia a recursos del clúster) se reenvían directamente al servidor de metadatos de Cloud DNS local, lo que evita kube-dns.
  • Las cachés de DNS locales detectan automáticamente los dominios stub y los servidores de nombres upstream que se especifican en la sección Añadir resoluciones personalizadas para dominios stub.

Requisitos y limitaciones

  • NodeLocal DNSCache consume recursos de computación en cada nodo de tu clúster.
  • NodeLocal DNSCache no es compatible con los grupos de nodos de Windows Server.
  • NodeLocal DNSCache requiere GKE 1.15 o una versión posterior.
  • NodeLocal DNSCache accede a los pods de kube-dns mediante TCP.
  • NodeLocal DNSCache accede a upstreamServers y stubDomains mediante TCP y UDP en GKE 1.18 o versiones posteriores. Se debe poder acceder al servidor DNS mediante TCP y UDP.
  • Los registros DNS se almacenan en caché durante los siguientes periodos:
    • El tiempo de vida (TTL) del registro o 30 segundos si el TTL es superior a 30 segundos.
    • 5 segundos si la respuesta de DNS es NXDOMAIN.
  • Los pods de NodeLocal DNSCache escuchan en los puertos 53, 9253, 9353 y 8080 de los nodos. Si ejecutas otro hostNetwork pod o configuras un hostPorts con esos puertos, NodeLocal DNSCache fallará y se producirán errores de DNS. Los pods de NodeLocal DNSCache no usan el modo hostNetwork cuando se usa Dataplane V2 de GKE y no se usa Cloud DNS para GKE.
  • La caché DNS local solo se ejecuta en grupos de nodos que ejecutan versiones 1.15 y posteriores de GKE. Si habilitas NodeLocal DNSCache en un clúster con nodos que ejecutan versiones anteriores, los pods de esos nodos usarán kube-dns.

Habilitar NodeLocal DNSCache

En los clústeres de Autopilot, NodeLocal DNSCache está habilitado de forma predeterminada y no se puede anular.

En los clústeres estándar, puedes habilitar NodeLocal DNSCache en clústeres nuevos o ya creados mediante la CLI de Google Cloud. Puedes habilitar NodeLocal DNSCache en clústeres nuevos mediante la Trusted Cloud consola.

Habilitar NodeLocal DNSCache en un clúster nuevo

gcloud

Para habilitar NodeLocal DNSCache en un clúster nuevo, usa la marca --addons con el argumento NodeLocalDNS:

gcloud container clusters create CLUSTER_NAME \
    --location=COMPUTE_LOCATION \
    --addons=NodeLocalDNS

Haz los cambios siguientes:

Consola

Para habilitar NodeLocal DNSCache en un clúster nuevo, sigue estos pasos:

  1. Ve a la página Google Kubernetes Engine en la Trusted Cloud consola.

    Ir a Google Kubernetes Engine

  2. Junto a Estándar, haz clic en Configurar.

  3. Configura el clúster como quieras.

  4. En el panel de navegación, haz clic en Redes.

  5. En la sección Opciones de red avanzadas, marca la casilla Habilitar NodeLocal DNSCache.

  6. Haz clic en Crear.

Habilitar NodeLocal DNSCache en un clúster

Para habilitar NodeLocal DNSCache en un clúster, usa la marca --update-addons con el argumento NodeLocalDNS=ENABLED:

gcloud container clusters update CLUSTER_NAME \
    --location=COMPUTE_LOCATION \
    --update-addons=NodeLocalDNS=ENABLED

Haz los cambios siguientes:

Para aplicar este cambio, es necesario volver a crear los nodos, lo que puede provocar interrupciones en las cargas de trabajo en ejecución. Para obtener información sobre este cambio concreto, busca la fila correspondiente en la tabla Cambios manuales que recrean los nodos mediante una estrategia de actualización de nodos y respetando las políticas de mantenimiento. Para obtener más información sobre las actualizaciones de nodos, consulta Planificar interrupciones de actualizaciones de nodos.

Verificar que NodeLocal DNSCache esté habilitado

Para comprobar que NodeLocal DNSCache se está ejecutando, puedes enumerar los node-local-dnspods:

kubectl get pods -n kube-system -o wide | grep node-local-dns

El resultado debería ser similar al siguiente:

node-local-dns-869mt    1/1   Running   0   6m24s   10.128.0.35   gke-test-pool-69efb6b8-5d7m   <none>   <none>
node-local-dns-htx4w    1/1   Running   0   6m24s   10.128.0.36   gke-test-pool-69efb6b8-wssk   <none>   <none>
node-local-dns-v5njk    1/1   Running   0   6m24s   10.128.0.33   gke-test-pool-69efb6b8-bhz3   <none>   <none>

El resultado muestra un pod node-local-dns para cada nodo que ejecute la versión 1.15 o posterior de GKE.

Inhabilitar NodeLocal DNSCache

Puedes inhabilitar NodeLocal DNSCache con el siguiente comando:

gcloud container clusters update CLUSTER_NAME \
    --location=COMPUTE_LOCATION \
    --update-addons=NodeLocalDNS=DISABLED

Haz los cambios siguientes:

Para aplicar este cambio, es necesario volver a crear los nodos, lo que puede provocar interrupciones en las cargas de trabajo en ejecución. Para obtener información sobre este cambio concreto, busca la fila correspondiente en la tabla Cambios manuales que recrean los nodos mediante una estrategia de actualización de nodos y respetando las políticas de mantenimiento. Para obtener más información sobre las actualizaciones de nodos, consulta Planificar interrupciones de actualizaciones de nodos.

Solucionar problemas de NodeLocal DNSCache

Para obtener información general sobre cómo diagnosticar problemas de DNS de Kubernetes, consulta Depuración de la resolución de DNS.

NodeLocal DNSCache no se habilita inmediatamente

Cuando habilitas NodeLocal DNSCache en un clúster, es posible que GKE no actualice los nodos de inmediato si el clúster tiene una ventana de mantenimiento o exclusión configurada. Para obtener más información, consulta las advertencias sobre la recreación de nodos y las ventanas de mantenimiento.

Si prefieres no esperar, puedes aplicar los cambios a los nodos manualmente llamando al comando gcloud container clusters upgrade y pasando el indicador --cluster-version con la misma versión de GKE que ya está ejecutando el grupo de nodos. Para usar esta solución alternativa, debes usar la CLI de Google Cloud.

NodeLocal DNSCache con Cloud DNS

Si usas NodeLocal DNSCache con Cloud DNS, el clúster usa la dirección IP del servidor de nombres 169.254.20.10, como se muestra en el siguiente diagrama:

Arquitectura de NodeLocal DNSCache con Cloud DNS.

Por lo tanto, la dirección IP del servicio kube-dns puede ser diferente de la dirección IP del servidor de nombres que usan tus pods. Esta diferencia en las direcciones IP es normal, ya que se necesita la dirección IP del servidor de nombres 169.254.20.10 para que Cloud DNS funcione correctamente.

Para comprobar las direcciones IP, ejecuta los siguientes comandos:

  1. Para ver la dirección IP del servicio kube-dns, sigue estos pasos:

    kubectl get svc -n kube-system kube-dns -o jsonpath="{.spec.clusterIP}"
    

    El resultado es la dirección IP de kube-dns, como 10.0.0.10:53.

  2. Abre una sesión de shell en tu pod:

    kubectl exec -it POD_NAME -- /bin/bash
    
  3. En la sesión de shell del pod, lee el contenido del archivo /etc/resolv.conf:

    cat /etc/resolv.conf
    

    El resultado es 169.254.20.10

Política de red con NodeLocal DNSCache

Si usas políticas de red con NodeLocal DNSCache y no usas Cloud DNS ni GKE Dataplane V2, debes configurar reglas para permitir que tus cargas de trabajo y los node-local-dnsPods envíen consultas de DNS.

Usa una regla ipBlock en tu manifiesto para permitir la comunicación entre tus pods y kube-dns.

El siguiente manifiesto describe una política de red que usa una regla ipBlock:

spec:
  egress:
  - ports:
    - port: 53
      protocol: TCP
    - port: 53
      protocol: UDP
    to:
    - ipBlock:
        cidr: KUBE_DNS_SVC_CLUSTER_IP/32
  podSelector: {}
  policyTypes:
    - Egress

Sustituye KUBE_DNS_SVC_CLUSTER_IP por la dirección IP del servicio kube-dns. Puedes obtener la dirección IP del servicio kube-dns con el siguiente comando:

kubectl get svc -n kube-system kube-dns -o jsonpath="{.spec.clusterIP}"

Problemas conocidos

Tiempo de espera de DNS en dnsPolicy ClusterFirstWithHostNet al usar NodeLocal DNSCache y GKE Dataplane V2

En los clústeres que usan GKE Dataplane V2 y NodeLocal DNSCache, los pods con hostNetwork definido como true y dnsPolicy definido como ClusterFirstWithHostNet no pueden acceder a los back-ends de DNS del clúster. Los registros DNS pueden contener entradas similares a las siguientes:

nslookup: write to 'a.b.c.d': Operation not permitted

;; connection timed out; no servers could be reached

El resultado indica que las solicitudes de DNS no pueden llegar a los servidores backend.

Una solución alternativa es definir dnsPolicy y dnsConfig para los pods hostNetwork:

spec:
 dnsPolicy: "None"
 dnsConfig:
   nameservers:
     - KUBE_DNS_UPSTREAM
   searches:
     - cluster.local
     - svc.cluster.local
     - NAMESPACE.svc.cluster.local
     - c.PROJECT_ID.internal
     - google.internal
   options:
     - name: ndots
       value: "5"

Haz los cambios siguientes:

  • NAMESPACE: el espacio de nombres del pod hostNetwork.
  • PROJECT_ID: el ID de tu proyecto de Trusted Cloud .
  • KUBE_DNS_UPSTREAM: ClusterIP del servicio kube-dns upstream. Puedes obtener este valor con el siguiente comando:

    kubectl get svc -n kube-system kube-dns-upstream -o jsonpath="{.spec.clusterIP}"
    

Las solicitudes de DNS del pod ahora pueden llegar a kube-dns y omitir NodeLocal DNSCache.

Errores de tiempo de espera de NodeLocal DNSCache

En los clústeres en los que NodeLocal DNSCache está habilitado, los registros pueden contener entradas similares a las siguientes:

[ERROR] plugin/errors: 2 <hostname> A: read tcp <node IP: port>-><kubedns IP>:53: i/o timeout

El resultado incluye la dirección IP del servicio kube-dns-upstream Cluster IP. En este ejemplo, no se ha recibido la respuesta a una solicitud de DNS de kube-dns en 2 segundos. Esto puede deberse a uno de los siguientes motivos:

  • Un problema de conectividad de red subyacente.
  • Las consultas de DNS de la carga de trabajo han aumentado significativamente o se debe a un aumento de los grupos de nodos.

Por lo tanto, los pods kube-dns no pueden gestionar todas las solicitudes a tiempo. La solución alternativa consiste en aumentar el número de réplicas de kube-dns ajustando los parámetros de escalado automático.

Escalar verticalmente kube-dns

Puedes usar un valor inferior para nodesPerReplica para asegurarte de que se creen más pods de kube-dns a medida que se escalen los nodos del clúster. Te recomendamos que definas un valor max explícito para asegurarte de que la máquina virtual (VM) del plano de control de GKE no se vea sobrecargada debido al gran número de pods de kube-dns que monitorizan la API de Kubernetes.

Puedes definir max como el número de nodos del clúster. Si el clúster tiene más de 500 nodos, asigna el valor 500 a max.

En los clústeres estándar, puedes modificar el número de réplicas de kube-dns editando el kube-dns-autoscaler ConfigMap. Esta configuración no se admite en clústeres de Autopilot.

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

El resultado debería ser similar al siguiente:

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

El número de réplicas de kube-dns se calcula mediante la siguiente fórmula:

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

Para aumentar la escala, cambia nodesPerReplica a un valor más pequeño e incluye un valor de max.

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

La configuración crea un pod kube-dns por cada 8 nodos del clúster. Un clúster de 24 nodos tendrá 3 réplicas y un clúster de 40 nodos tendrá 5 réplicas. Si el clúster supera los 120 nodos, el número de réplicas de kube-dns no superará las 15, el valor de max.

Para asegurar un nivel de disponibilidad de DNS básico en tu clúster, define un número mínimo de réplicas para kube-dns.

La salida de kube-dns-autoscaler ConfigMap con el campo min sería similar a la siguiente:

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

Siguientes pasos