Soluciona problemas de kube-dns en GKE


En esta página, se muestra cómo resolver problemas con kube-dns en Google Kubernetes Engine (GKE).

Identifica el origen de los problemas de DNS en kube-dns

Los errores como dial tcp: i/o timeout, no such host o Could not resolve host suelen indicar problemas con la capacidad de kube-dns para resolver consultas.

Si viste uno de esos errores, pero no conoces la causa, usa las siguientes secciones para ayudarte a encontrarla. Las siguientes secciones están organizadas para comenzar con los pasos que probablemente te ayudarán más, así que prueba cada sección en orden.

Verifica si los Pods de kube-dns se están ejecutando

Los Pods de kube-dns son fundamentales para la resolución de nombres dentro del clúster. Si no se están ejecutando, es probable que tengas problemas con la resolución de DNS.

Para verificar que los Pods de kube-dns se estén ejecutando sin reinicios recientes, consulta el estado de estos Pods:

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

El resultado es similar a este:

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

En este resultado, POD_ID_1 y POD_ID_2 representan identificadores únicos que se agregan automáticamente a los Pods de kube-dns.

Si el resultado muestra que alguno de tus Pods de kube-dns no tiene el estado Running, sigue estos pasos:

  1. Usa los registros de auditoría de actividad del administrador para investigar si hubo cambios recientes, como actualizaciones de versiones de clústeres o grupos de nodos, o cambios en el ConfigMap de kube-dns. Para obtener más información sobre los registros de auditoría, consulta la información del registro de auditoría de GKE. Si encuentras cambios, revierte y vuelve a ver el estado de los Pods.

  2. Si no encuentras ningún cambio reciente pertinente, investiga si se produce un error de OOM en el nodo en el que se ejecuta el Pod de kube-dns. Si ves un error similar al siguiente en los mensajes de registro de Cloud Logging, significa que estos Pods están experimentando un error de OOM:

    Warning: OOMKilling Memory cgroup out of memory
    

    Este mensaje indica que Kubernetes finalizó un proceso debido a un consumo excesivo de recursos. Kubernetes programa los Pods en función de las solicitudes de recursos, pero permite que los Pods consuman hasta sus límites de recursos. Si los límites son más altos que las solicitudes o no hay límites, el uso de recursos del Pod puede exceder los recursos del sistema.

    Para resolver este error, puedes borrar las cargas de trabajo que generan problemas o establecer límites de memoria o CPU. Si deseas obtener más información para establecer límites, consulta Administración de recursos para Pods y contenedores en la documentación de Kubernetes. Para obtener más información sobre los eventos de OOM, consulta Soluciona problemas relacionados con eventos de OOM.

  3. Si no encuentras ningún mensaje de error de OOM, reinicia la Deployment de kube-dns:

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

    Después de reiniciar la Deployment, verifica si tus Pods de kube-dns se están ejecutando.

Si estos pasos no funcionan o todos tus Pods de kube-dns tienen el estado Running, pero sigues teniendo problemas de DNS, verifica que el archivo /etc/resolv.conf esté configurado correctamente.

Verifica que /etc/resolv.conf esté configurado correctamente

Revisa el archivo /etc/resolv.conf de los Pods que tienen problemas de DNS y asegúrate de que las entradas que contiene sean correctas:

  1. Visualiza el archivo /etc/resolv.conf del Pod:

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

    Reemplaza POD_NAME por el nombre del pod que tiene problemas de DNS. Si hay varios Pods que tienen problemas, repite los pasos de esta sección para cada uno de ellos.

    Si el binario del Pod no admite el comando kubectl exec, es posible que este comando falle. Si esto sucede, crea un Pod simple para usarlo como entorno de prueba. Este procedimiento te permite ejecutar un Pod de prueba en el mismo espacio de nombres que el Pod problemático.

  2. Verifica que la dirección IP del servidor de nombres en el archivo /etc/resolv.conf sea correcta:

    • Los Pods que usan una red del host deben usar los valores del archivo /etc/resolv.conf del nodo. La dirección IP del servidor de nombres debe ser 169.254.169.254.
    • En el caso de los Pods que no usan una red de host, la dirección IP del servicio kube-dns debe ser la misma que la dirección IP del servidor de nombres. Para comparar las direcciones IP, completa los siguientes pasos:

      1. Obtén la dirección IP del servicio kube-dns:

        kubectl get svc kube-dns -n kube-system
        

        El resultado es similar a este:

        NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)         AGE
        kube-dns   ClusterIP   192.0.2.10   <none>        53/UDP,53/TCP   64d
        
      2. Toma nota del valor en la columna IP de clúster. En este ejemplo, es 192.0.2.10.

      3. Compara la dirección IP del servicio kube-dns con la dirección IP del archivo /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
        

        En este ejemplo, los dos valores coinciden, por lo que la dirección IP incorrecta del servidor de nombres no es la causa del problema.

        Sin embargo, si las direcciones IP no coinciden, significa que se configuró un campo dnsConfig en el manifiesto del Pod de la aplicación.

        Si el valor del campo dnsConfig.nameservers es correcto, investiga tu servidor DNS y asegúrate de que funcione correctamente.

        Si no quieres usar el servidor de nombres personalizado, quita el campo y realiza un reinicio progresivo del Pod:

        kubectl rollout restart deployment POD_NAME
        

        Reemplaza POD_NAME por el nombre del Pod.

  3. Verifica las entradas search y ndots en /etc/resolv.conf. Asegúrate de que no haya errores ortográficos ni configuraciones obsoletas, y de que la solicitud fallida apunte a un servicio existente en el espacio de nombres correcto.

Realiza una búsqueda de DNS

Después de confirmar que /etc/resolv.conf está configurado correctamente y que el registro DNS es correcto, usa la herramienta de línea de comandos dig para realizar búsquedas de DNS desde el Pod que informa errores de DNS:

  1. Consulta un Pod directamente abriendo una shell dentro de él:

    kubectl exec -it POD_NAME -n NAMESPACE_NAME -- SHELL_NAME
    

    Reemplaza lo siguiente:

    • POD_NAME: Es el nombre del Pod que informa errores de DNS.
    • NAMESPACE_NAME: Es el espacio de nombres al que pertenece el Pod.
    • SHELL_NAME: Es el nombre del shell que deseas abrir. Por ejemplo, sh o /bin/bash.

    Este comando podría fallar si tu Pod no permite el comando kubectl exec o si no tiene el binario dig. Si esto sucede, crea un Pod de prueba con una imagen que tenga instalado dig:

    kubectl run "test-$RANDOM" ti --restart=Never --image=thockin/dnsutils - bash
    
  2. Verifica si el Pod puede resolver correctamente el servicio de DNS interno del clúster:

    dig kubernetes
    

    Dado que el archivo /etc/resolv.conf apunta a la dirección IP del servicio de kube-dns, cuando ejecutas este comando, el servidor DNS es el servicio de kube-dns.

    Deberías ver una respuesta de DNS correcta con la dirección IP del servicio de la API de Kubernetes (a menudo, algo como 10.96.0.1). Si ves SERVFAIL o no hay respuesta, esto suele indicar que el Pod de kube-dns no puede resolver los nombres de servicio internos.

  3. Verifica si el servicio kube-dns puede resolver un nombre de dominio externo:

    dig example.com
    
  4. Si tienes dificultades con un Pod de kube-dns en particular que responde a las consultas de DNS, verifica si ese Pod puede resolver un nombre de dominio externo:

     dig example.com @KUBE_DNS_POD_IP
    

    Reemplaza KUBE_DNS_POD_IP por la dirección IP del Pod de kube-dns. Si no conoces el valor de esta dirección IP, ejecuta el siguiente comando:

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

    La dirección IP se encuentra en la columna IP.

    Si la resolución del comando se realiza correctamente, verás status: NOERROR y los detalles del registro A, como se muestra en el siguiente ejemplo:

     ; <<>> 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. Sal de la shell:

    exit
    

Si falla alguno de estos comandos, realiza un reinicio progresivo de la Deployment de kube-dns:

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

Después de completar el reinicio, vuelve a intentar los comandos dig y comprueba si ahora se ejecutan correctamente. Si siguen fallando, realiza una captura de paquetes.

Cómo tomar una captura de paquetes

Realiza una captura de paquetes para verificar si los Pods de kube-dns reciben las consultas de DNS y responden a ellas de forma adecuada:

  1. Conéctate al nodo que ejecuta el Pod kube-dns con SSH. Por ejemplo:

    1. En la Google Cloud consola, ve a la página Instancias de VM.

      Ir a Instancias de VM

    2. Ubica el nodo al que deseas conectarte. Si no conoces el nombre del nodo en tu Pod de kube-dns, ejecuta el siguiente comando:

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

      El nombre del nodo aparece en la columna Nodo.

    3. En la columna Conectar, haz clic en SSH.

  2. En la terminal, inicia toolbox, una herramienta de depuración preinstalada:

    toolbox
    
  3. En el mensaje de raíz, instala el paquete tcpdump:

    apt update -y && apt install -y tcpdump
    
  4. Con tcpdump, realiza una captura de paquetes de tu tráfico de DNS:

    tcpdump -i eth0 port 53" -w FILE_LOCATION
    

    Reemplaza FILE_LOCATION por la ruta de acceso en la que deseas guardar la captura.

  5. Revisa la captura de paquetes. Verifica si hay paquetes con direcciones IP de destino que coincidan con la dirección IP del servicio kube-dns. Esto garantiza que las solicitudes de DNS lleguen al destino correcto para su resolución. Si no ves que el tráfico de DNS llega a los Pods correctos, es posible que haya una política de red que bloquee las solicitudes.

Cómo verificar si hay una política de red

En ocasiones, las políticas de red restrictivas pueden interrumpir el tráfico de DNS. Para verificar si existe una política de red en el espacio de nombres kube-system, ejecuta el siguiente comando:

kubectl get networkpolicy -n kube-system

Si encuentras una política de red, revísala y asegúrate de que permita la comunicación de DNS necesaria. Por ejemplo, si tienes una política de red que bloquea todo el tráfico de salida, la política también bloqueará las solicitudes de DNS.

Si el resultado es No resources found in kube-system namespace, no tienes ninguna política de red y puedes descartar esta opción como la causa del problema. Investigar los registros puede ayudarte a encontrar más puntos de falla.

Habilita el registro temporal de consultas de DNS

Para ayudarte a identificar problemas, como respuestas de DNS incorrectas, habilita temporalmente el registro de depuración de las consultas de DNS. Para habilitar las consultas, crea un Pod basado en un Pod kube-dns existente. Los cambios en la Deployment de kube-dns se revierten automáticamente.

Habilitar el registro temporal de consultas de DNS es un procedimiento que requiere muchos recursos, por lo que te recomendamos que borres el Pod que crees tan pronto como recopiles una muestra adecuada de registros.

Para habilitar el registro temporal de consultas de DNS, completa los siguientes pasos:

  1. Recupera un Pod de kube-dns y almacénalo en una variable llamada POD:

    POD=$(kubectl -n kube-system get pods --selector=k8s-app=kube-dns -o jsonpath="{.items[0].metadata.name}")
    
  2. Crea un Pod llamado kube-dns-debug. Este Pod es una copia del Pod almacenado en la variable POD, pero con el registro de dnsmasq habilitado. Este comando no modifica el 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. Inspecciona los registros:

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

    También puedes ver las consultas en Cloud Logging.

  4. Cuando termines de ver los registros de consultas de DNS, borra el Pod:kube-dns-debug

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

Investiga el Pod de kube-dns

Revisa cómo los Pods de kube-dns reciben y resuelven las consultas de DNS con Cloud Logging.

Para ver las entradas de registro relacionadas con el Pod de kube-dns, completa los siguientes pasos:

  1. En la Google Cloud consola, ve a la página Explorador de registros.

    Ir al Explorador de registros

  2. En el panel de consultas, ingresa el siguiente filtro para ver los eventos relacionados con el contenedor 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"
    

    Reemplaza lo siguiente:

    • CLUSTER_NAME: Es el nombre del clúster al que pertenece el Pod de kube-dns.
    • CLUSTER_LOCATION: Es la ubicación de tu clúster.
  3. Haz clic en Ejecutar consulta.

  4. Revise el resultado. En el siguiente ejemplo de resultado, se muestra un posible error que podrías ver:

    {
       "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."
    },
    

    En este ejemplo, kube-dns no pudo resolver example.com en un tiempo razonable. Este tipo de error puede deberse a varios problemas. Por ejemplo, es posible que el servidor ascendente esté configurado de forma incorrecta en el ConfigMap de kube-dns o que haya un tráfico de red alto.

Si no tienes habilitado Cloud Logging, consulta los registros de 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

Investiga los cambios recientes en el ConfigMap de kube-dns

Si de repente se producen fallas en la resolución de DNS en tu clúster, una de las causas puede ser un cambio de configuración incorrecto realizado en el ConfigMap de kube-dns. En particular, los cambios de configuración en las definiciones de los dominios de stub y los servidores upstream pueden causar problemas.

Para verificar si hay actualizaciones en la configuración del dominio de zona, completa los siguientes pasos:

  1. En la Google Cloud consola, ve a la página Explorador de registros.

    Ir al Explorador de registros

  2. En el panel de consultas, ingresa la siguiente 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. Haz clic en Ejecutar consulta.

  4. Revise el resultado. Si hubo actualizaciones, el resultado es similar al siguiente:

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

    Si ves una actualización, expande el resultado para obtener más información sobre los cambios. Verifica que los dominios de stub y sus servidores DNS ascendentes correspondientes estén definidos correctamente. Si las entradas son incorrectas, es posible que se produzcan errores de resolución para esos dominios.

Para verificar si hay cambios en el servidor upstream, completa los siguientes pasos:

  1. En la Google Cloud consola, ve a la página Explorador de registros.

    Ir al Explorador de registros

  2. En el panel de consultas, ingresa la siguiente 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. Haz clic en Ejecutar consulta.

  4. Revise el resultado. Si hubo cambios, el resultado es similar al siguiente:

    Updated upstreamNameservers to [8.8.8.8]
    

    Expande el resultado para obtener más información sobre los cambios. Verifica que la lista de servidores DNS ascendentes sea precisa y que se pueda acceder a estos servidores desde tu clúster. Si estos servidores no están disponibles o están mal configurados, es posible que falle la resolución general de DNS.

Si verificaste los cambios en los dominios stub y los servidores upstream, pero no encontraste ningún resultado, verifica todos los cambios con el siguiente filtro:

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

Revisa los cambios que se enumeran para ver si causaron el error.

Comunícate con Atención al cliente de Cloud

Si completaste las secciones anteriores, pero aún no puedes diagnosticar la causa del problema, comunícate con Atención al cliente de Cloud.

Soluciona problemas habituales

Si experimentaste un error o problema específico, sigue las recomendaciones de las siguientes secciones.

Problema: Se agota el tiempo de espera de DNS de forma intermitente

Si observas que se agota el tiempo de espera de la resolución de DNS de forma intermitente cuando aumenta el tráfico de DNS o cuando comienzan las horas de trabajo, prueba las siguientes soluciones para optimizar el rendimiento de DNS:

  • Verifica la cantidad de Pods de kube-dns que se ejecutan en el clúster y compárala con la cantidad total de nodos de GKE. Si no hay suficientes recursos, considera aumentar la escala de los Pods de kube-dns.

  • Para mejorar el tiempo promedio de búsqueda de DNS, habilita NodeLocal DNS Cache.

  • La resolución de DNS para nombres externos puede sobrecargar el Pod de kube-dns. Para reducir la cantidad de búsquedas, ajusta el parámetro de configuración ndots en el archivo /etc/resolv.conf. ndots representa la cantidad de puntos que deben aparecer en un nombre de dominio para resolver una consulta antes de la consulta absoluta inicial.

    El siguiente ejemplo es el archivo /etc/resolv.conf de un Pod de aplicación:

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

    En este ejemplo, kube-dns busca cinco puntos en el dominio que se consulta. Si el Pod realiza una llamada de resolución de DNS para example.com, tus registros se verán similares al siguiente ejemplo:

    "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 este problema, cambia el valor de ndots a 1 para buscar solo un punto o agrega un punto (.) al final del dominio que consultas o usas. Por ejemplo:

    dig example.com.
    

Problema: Las consultas de DNS fallan de forma intermitente desde algunos nodos

Si observas que las consultas de DNS fallan de forma intermitente desde algunos nodos, es posible que veas los siguientes síntomas:

  • Cuando ejecutas comandos dig en la dirección IP del servicio kube-dns o en la dirección IP del Pod, las consultas de DNS fallan de forma intermitente con tiempos de espera.
  • Falla la ejecución de comandos dig desde un Pod en el mismo nodo que el Pod kube-dns.

Para resolver este problema, realiza los siguientes pasos:

  1. Realiza una prueba de conectividad. Establece el Pod o el nodo problemático como la fuente y el destino como la dirección IP del Pod kube-dns. Esto te permite verificar si tienes las reglas de firewall necesarias para permitir este tráfico.
  2. Si la prueba no se realiza correctamente y una regla de firewall bloquea el tráfico, usa Cloud Logging para enumerar los cambios manuales que se realizaron en las reglas de firewall. Busca los cambios que bloquean un tipo específico de tráfico:

    1. En la Google Cloud consola, ve a la página Explorador de registros.

      Ir al Explorador de registros

    2. En el panel de consultas, ingresa la siguiente consulta:

      logName="projects/project-name/logs/cloudaudit.googleapis.com/activity"
      resource.type="gce_firewall_rule"
      
    3. Haz clic en Ejecutar consulta. Usa el resultado de la consulta para determinar si se realizaron cambios. Si observas algún error, corrígelo y vuelve a aplicar la regla de firewall.

      Asegúrate de no realizar cambios en ninguna regla de firewall automática.

  3. Si no hubo cambios en las reglas del firewall, verifica la versión del grupo de nodos y asegúrate de que sea compatible con el plano de control y otros grupos de nodos que funcionen. Si alguno de los grupos de nodos del clúster tiene más de dos versiones secundarias anteriores a la versión del plano de control, es posible que esto genere problemas. Para obtener más información sobre esta incompatibilidad, consulta La versión del nodo no es compatible con la versión del plano de control.

  4. Para determinar si las solicitudes se envían a la IP de servicio de kube-dns correcta, captura el tráfico de red en el nodo problemático y filtra el puerto 53 (tráfico de DNS). Captura el tráfico en los Pods de kube-dns para ver si las solicitudes llegan a los Pods previstos y si se resuelven correctamente.

¿Qué sigue?