Soluciona problemas

Obtén información sobre los pasos de la solución de problemas que pueden servirte si tienes dificultades con Google Kubernetes Engine (GKE).

Depura los recursos de Kubernetes

Si tienes un problema con el clúster, consulta la página sobre cómo solucionar problemas de clústeres en la documentación de Kubernetes.

Si tienes un problema con tu aplicación, sus pods o su objeto de controlador, consulta la página sobre cómo solucionar problemas de aplicaciones.

No se encuentra el comando kubectl

  1. Instala el objeto binario kubectl mediante la ejecución del siguiente comando:

    sudo gcloud components update kubectl
    
  2. Responde “sí” cuando el instalador te solicite modificar la variable de entorno $PATH. Si modificas esta variable, podrás usar los comandos kubectl sin necesidad que escribir la ruta de archivo completa.

    Como alternativa, agrega la siguiente línea a ~/.bashrc (o ~/.bash_profile en macOS, o donde tu shell almacene las variables de entorno):

    export PATH=$PATH:/usr/local/share/google/google-cloud-sdk/bin/
    
  3. Ejecuta el siguiente comando para cargar el archivo .bashrc (o .bash_profile) actualizado:

    source ~/.bashrc
    

Los comandos kubectl muestran el error “conexión rechazada”

Establece el contexto del clúster con el siguiente comando:

gcloud container clusters get-credentials cluster-name

Si tienes dudas sobre qué ingresar para cluster-name, usa el siguiente comando para hacer una lista de tus clústeres:

gcloud container clusters list

Los comandos kubectl muestran el error “no se pudo negociar una versión de API”

Asegúrate de que kubectl tenga credenciales de autenticación:

gcloud auth application-default login

Los comandos kubectl logs, attach, exec y port-forward dejan de responder

Estos comandos dependen que el plano de control del clúster (instancia principal) pueda comunicarse con los nodos en el clúster. Sin embargo, debido a que el plano de control no está en la misma red de Compute Engine que los nodos del clúster, dependemos de los túneles de SSH para habilitar una comunicación segura.

GKE guarda un archivo de clave pública SSH en los metadatos del proyecto de Compute Engine. Todas las VM de Compute Engine que usan imágenes proporcionadas por Google verifican con regularidad los metadatos comunes del proyecto y los metadatos de la instancia para las claves SSH a fin de agregarlos a la lista de usuarios autorizados de la VM. GKE también agrega una regla de firewall a la red de Compute Engine, lo que permite el acceso SSH desde la dirección IP del plano de control a cada nodo en el clúster.

Si alguno de los comandos kubectl anteriores no se ejecuta, es probable que el servidor de la API no pueda abrir los túneles SSH con los nodos. Verifica las siguientes causas posibles:

  1. El clúster no tiene nodos.

    Si reduces la cantidad de nodos en tu clúster a cero, los túneles de SSH no funcionarán.

    A fin de arreglarlo, cambia el tamaño del clúster para tener al menos un nodo.

  2. Los pods en el clúster se detuvieron en un estado de finalización y evitaron que los nodos que ya no existen se puedan quitar del clúster.

    Este problema debería afectar solo a la versión 1.1 de Kubernetes, pero también se puede generar por un cambio de tamaño del clúster reiterado.

    Para arreglarlo, borra los Pods que estén en un estado de finalización por más de unos minutos. Los nodos viejos se quitan del plano de control y se reemplazan por los nodos nuevos.

  3. Las reglas de firewall de la red no permiten el acceso de SSH al plano de control.

    Todas las redes de Compute Engine se crean con una regla de firewall llamada default-allow-ssh que permite el acceso SSH desde todas las direcciones IP (por supuesto, mediante la solicitud de una clave privada válida). GKE también inserta una regla SSH para cada clúster público con el formato gke-cluster-name-random-characters-ssh que permite el acceso SSH de forma específica desde el plano de control del clúster hacia los nodos del clúster. Si no existe ninguna de estas reglas, el plano de control no podrá abrir los túneles SSH.

    Para solucionar esto, vuelve a agregar una regla de firewall que permita el acceso a las VM con las etiquetas que se encuentran en todos los nodos del clúster desde la dirección IP del plano de control.

  4. La entrada de los metadatos comunes del proyecto para las “ssh-keys” está llena.

    Si la entrada de metadatos del proyecto llamada "ssh-keys" está cerca del límite de tamaño máximo, GKE no puede agregar su propia clave SSH a fin de habilitarla para abrir túneles SSH. Para ver los metadatos del proyecto, ejecuta el siguiente comando:

    gcloud compute project-info describe [--project=PROJECT]
    

    Luego, verifica la longitud de la lista de llaves SSH.

    Para arreglarlo, borra algunas de las llaves SSH que ya no sean necesarias.

  5. Estableciste un campo de metadatos con la clave “ssh-keys” en las VM del clúster.

    El agente de nodo en las VM prefiere claves SSH por instancia en vez de claves SSH por proyecto completo, por lo que, si estableciste claves SSH de forma específica en los nodos del clúster, los nodos no respetaran la clave SSH del plano de control en los metadatos del proyecto. Para verificarlo, ejecuta gcloud compute instances describe <VM-name> y busca un campo que diga “claves SSH” en los metadatos.

    Para arreglarlo, borra las Llaves SSH por instancia de los metadatos de la instancia.

Ten en cuenta que estas características no se requieren para el funcionamiento correcto del clúster. Si prefieres mantener el acceso exterior bloqueado para la red del clúster, ten en cuenta que las características como estas no funcionarán.

Las métricas del clúster no aparecen en Cloud Monitoring

Asegúrate de haber activado la API de Cloud Monitoring y la API de Cloud Logging en el proyecto y de que lo puedes ver en Cloud Monitoring.

Si el problema persiste, verifica alguna de las posibles causas siguientes:

  1. Asegúrate de que habilitaste la supervisión en tu clúster.

    Monitoring está habilitado de forma predeterminada para los clústeres creados desde Google Cloud Console y desde la herramienta de línea de comandos de gcloud; pero puedes verificarlo si ejecutas el siguiente comando o haces clic en los detalles del clúster en Cloud Console:

    gcloud container clusters describe cluster-name
    

    El resultado de este comando debe indicar que “monitoringService” es “monitoring.googleapis.com” y Cloud Monitoring debe estar habilitado en Cloud Console.

    Si la supervisión no está habilitada, ejecuta el siguiente comando para habilitarla:

    gcloud container clusters update cluster-name --monitoring-service=monitoring.googleapis.com
    
  2. ¿Cuánto tiempo pasó desde que se creó el clúster o se habilitó la supervisión?

    Puede tomar hasta una hora para que las métricas de un clúster nuevo comiencen a aparecer Cloud Monitoring.

  3. ¿Hay un heapster o gke-metrics-agent (el colector de OpenTelemetry) ejecutándose en el clúster en el espacio de nombres “kube-system”?

    Es posible que este pod no pueda programar cargas de trabajo porque el clúster se está quedando sin recursos. Para comprobar si OpenTelemetry o Heapster están en ejecución, puedes llamar a kubectl get pods --namespace=kube-system y verificar los Pods con heapster o gke-metrics-agent en el nombre.

  4. ¿El plano de control del clúster puede comunicarse con los nodos?

    Cloud Monitoring depende de eso. Para verificar si este es el caso, ejecuta el siguiente comando:

    kubectl logs pod-name
    

    Si este comando muestra un error, es posible que los túneles SSH causen el problema. Consulta esta sección para obtener más información.

Si tienes un problema relacionado con el agente de Cloud Logging, consulta su documentación de solución de problemas.

Para obtener más información, consulta la documentación de Logging.

Error 404: Recurso “no encontrado” cuando se llama a los comandos gcloud container

Vuelve a autenticarte en la herramienta de línea de comandos de gcloud:

gcloud auth login

Error 400/403: Faltan permisos de edición en una cuenta

La cuenta de servicio predeterminada de Compute Engine o la cuenta de servicio asociada con GKE se borró o editó de forma manual.

Cuando habilitas la API de Compute Engine o la API de Kubernetes Engine, se crea una cuenta de servicio y se le otorgan permisos de edición en el proyecto. Si en algún momento editas los permisos, quitas la función “Agente de servicio de Kubernetes Engine” y la cuenta por completo o inhabilitas la API, la creación de clústeres y la funcionalidad de administración completa fallarán.

El nombre de tu cuenta de servicio de Google Kubernetes Engine es el siguiente, en el que project-number es el número de proyecto:

service-project-number@container-engine-robot.iam.gserviceaccount.com

Para resolver el problema, si quitaste la función Agente de servicios de Kubernetes Engine de la cuenta de servicio de Google Kubernetes Engine, vuelve a agregarla. De lo contrario, debes volver a habilitar la API de Kubernetes Engine, así, se restablecerán las cuentas de servicio y permisos de forma correcta. Puedes hacerlo en la herramienta de gcloud o en Cloud Console.

Console

  1. Visita API y servicios en Cloud Console.

    Página de API y servicios

  2. Selecciona tu proyecto.

  3. Haga clic en Habilitar API y servicios.

  4. Busca Kubernetes y, luego, selecciona la API de los resultados de la búsqueda.

  5. Haz clic en Habilitar. Si habilitaste la API antes, primero debes inhabilitarla y, luego, habilitarla de nuevo. La habilitación de la API y los servicios relacionados puede tomar varios minutos.

gcloud

Ejecuta el siguiente comando en la herramienta de gcloud:

gcloud services enable container.googleapis.com

Replica las reglas de firewall automáticas 1.8.x (y versiones anteriores) en 1.9.x y versiones posteriores

Si tu clúster se ejecuta en la versión 1.9.x de Kubernetes, las reglas de firewall automáticas cambiaron a fin de no permitir que cargas de trabajo en un clúster de GKE inicien comunicación con otras VM de Compute Engine que se encuentran fuera del clúster, pero en la misma red.

Puedes replicar el comportamiento de las reglas de firewall automáticas de un clúster 1.8.x (y anterior) si realizas los pasos siguientes:

  1. Encuentra la red del clúster:

    gcloud container clusters describe cluster-name --format=get"(network)"
    
  2. Obtén el CIDR IPv4 del clúster que se usa para los contenedores:

    gcloud container clusters describe cluster-name --format=get"(clusterIpv4Cidr)"
    
  3. Crea una regla de firewall para la red, con el CIDR como el rango de origen, y permite todos los protocolos:

    gcloud compute firewall-rules create "cluster-name-to-all-vms-on-network" \
      --network="network" --source-ranges="cluster-ipv4-cidr" \
      --allow=tcp,udp,icmp,esp,ah,sctp
    

Restablece la cuenta de servicio predeterminada en el proyecto de GCP

La cuenta de servicio predeterminada de GKE, container-engine-robot, se puede desvincular de un proyecto por accidente. El agente de servicio de GKE es una función de administración de identidades y accesos (IAM) que otorga a la cuenta de servicio los permisos para administrar los recursos del clúster. Si quitas esta vinculación de función de la cuenta de servicio, la cuenta de servicio predeterminada se desvincula del proyecto, lo que puede evitar que se implementen aplicaciones y que se realicen otras operaciones de clúster.

Puedes verificar si la cuenta de servicio se quitó del proyecto con la herramienta de gcloud o Cloud Console.

gcloud

Ejecuta el siguiente comando:

gcloud projects get-iam-policy project-id

Reemplaza project-id con el ID del proyecto.

Console

Visita la página IAM y administración en Cloud Console.

Si en el comando o el panel no se muestra container-engine-robot entre las cuentas de servicio, la cuenta de servicio se desvinculó.

Si quitas la vinculación de función de agente de servicio de GKE, ejecuta los siguientes comandos para restablecer la vinculación de función:

PROJECT_ID=$(gcloud config get-value project)
PROJECT_NUMBER=$(gcloud projects describe "${PROJECT_ID}" --format "value(projectNumber)")
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
  --member "serviceAccount:service-${PROJECT_NUMBER}@container-engine-robot.iam.gserviceaccount.com" \
  --role roles/container.serviceAgent

Para confirmar que la vinculación de función se otorgó, usa lo siguiente:

gcloud projects get-iam-policy $PROJECT_ID

Si ves el nombre de la cuenta de servicio junto con la función container.serviceAgent, se otorgó la vinculación de función. Por ejemplo:

- members:
  - serviceAccount:service-1234567890@container-engine-robot.iam.gserviceaccount.com
  role: roles/container.serviceAgent

La clave de Cloud KMS está inhabilitada.

La cuenta de servicio predeterminada de GKE no puede usar una clave de Cloud KMS inhabilitada para la encriptación de secretos al nivel de la aplicación.

Para volver a habilitar una clave inhabilitada, consulta cómo habilitar una versión de clave inhabilitada.

Pods que quedaron en estado pendiente después de habilitar la asignación de nodos

Si tienes un problema con los pods que quedaron en estado pendiente después de habilitar la asignación de nodos, ten en cuenta lo siguiente:

A partir de la versión 1.7.6, GKE reserva CPU y memoria para la sobrecarga de Kubernetes, incluidos Docker y el sistema operativo. Consulta Arquitectura del clúster para obtener información sobre la cantidad de cada tipo de máquina que los pods pueden programar.

Si los pods están pendientes después de una actualización, sugerimos realizar lo siguiente:

  1. Asegúrate de que las solicitudes de CPU y memoria para los pods no excedan su uso máximo. Cuando GKE reserva CPU y memoria para la sobrecarga, los pods no pueden solicitar estos recursos. Los pods que solicitan más CPU o memoria de la que usan evitan que otros pods soliciten estos recursos y es posible que dejen el clúster con poco uso. Para obtener más información, consulta Cómo se programan los pods con solicitudes de recursos.

  2. Considera cambiar el tamaño del clúster. Para obtener instrucciones, consulta Cambia el tamaño de un clúster.

  3. Si deseas revertir este cambio, cambia a una versión inferior del clúster. Para obtener instrucciones, consulta Actualiza un clúster o grupo de nodos de forma manual.

Nodos de clúster privado que se crearon, pero no se unieron al clúster

A menudo, cuando se usan rutas personalizadas y dispositivos de red de terceros en la VPC que usa el clúster privado, la ruta predeterminada (0.0.0.0/0) se redirecciona al dispositivo, en lugar de a la puerta de enlace de Internet predeterminada. Además de la conectividad del plano de control, debes asegurarte de que sea posible acceder a los siguientes destinos:

  • *.googleapis.com
  • *.gcr.io
  • gcr.io

Configura el Acceso privado a Google en los tres dominios. Con esta práctica recomendada, se permite que los nodos nuevos se inicien y se unan al clúster, y se mantiene restringido el tráfico vinculado a Internet.

Soluciona problemas de cargas de trabajo implementadas

GKE muestra un error si existen problemas con los pods de una carga de trabajo. Puedes verificar el estado de un pod con la herramienta de línea de comandos de kubectl o Cloud Console.

kubectl

Para ver todos los pods en ejecución en tu clúster, ejecuta el comando siguiente:

kubectl get pods

Resultado:

NAME       READY  STATUS             RESTARTS  AGE
pod-name   0/1    CrashLoopBackOff   23        8d

Para obtener más información sobre un pod específico, ejecuta el siguiente comando:

kubectl describe pod pod-name

Reemplaza pod-name con el nombre del pod que desees.

Console

Completa los pasos siguientes:

  1. Visita el panel Cargas de trabajo de GKE en Cloud Console.

    Visitar el panel Cargas de trabajo de GKE

  2. Selecciona la carga de trabajo deseada. La pestaña Descripción general muestra el estado de la carga de trabajo.

  3. En la sección Pods administrados, haz clic en el mensaje de estado de error.

En las secciones siguientes, se explican algunos errores comunes que muestran las cargas de trabajo y cómo resolverlos.

CrashLoopBackOff

CrashLoopBackOff indica que un contenedor falla repetidas veces después de reiniciarse. Un contenedor puede fallar por varias razones y verificar los registros de un pod puede ayudar a solucionar la causa del problema.

De forma predeterminada, los contenedores que fallan se reinician con una demora exponencial limitada a cinco minutos. Puedes cambiar este comportamiento si configuras el campo restartPolicy de la especificación del pod de la implementación como spec: restartPolicy. El valor predeterminado del campo es Always.

Puedes averiguar por qué el contenedor de tu pod falla mediante la herramienta de línea de comandos de kubectl o Cloud Console.

kubectl

Para ver todos los pods en ejecución en tu clúster, ejecuta el comando siguiente:

kubectl get pods

Busca el pod con el error CrashLoopBackOff.

Para obtener los registros del pod, ejecuta el siguiente comando:

kubectl logs pod-name

Reemplaza pod-name con el nombre del pod problemático.

También puedes pasar la marca -p para obtener los registros de la instancia anterior del contenedor de un pod, si existe.

Console

Completa los pasos siguientes:

  1. Visita el panel Cargas de trabajo de GKE en Cloud Console.

    Visitar el panel Cargas de trabajo de GKE

  2. Selecciona la carga de trabajo deseada. La pestaña Descripción general muestra el estado de la carga de trabajo.

  3. En la sección Pods administrados, haz clic en el pod problemático.

  4. En el menú de pods, haz clic en la pestaña Registros.

Verifica el “Código de salida” del contenedor que falla

Para encontrar el código de salida, realiza las siguientes tareas:

  1. Ejecuta el siguiente comando:

    kubectl describe pod pod-name
    

    Reemplaza pod-name con el nombre del pod.

  2. Revisa el valor en el campo containers: container-name: last state: exit code:

    • Si el código de salida es 1, el contenedor falló debido a que la aplicación falló.
    • Si el código de salida es 0, verifica por cuánto tiempo se ejecutó la app.

    Los contenedores se detienen cuando el proceso principal de la aplicación se detiene. Si la app finaliza la ejecución con mucha rapidez, es posible que el contenedor continúe con el proceso de reinicio.

Conéctate a un contenedor en ejecución

Abre una shell al pod:

kubectl exec -it pod-name -- /bin/bash

Si hay más de un contenedor en tu pod, agrega -c container-name.

Ahora, puedes ejecutar comandos bash desde el contenedor: puedes probar la red o verificar si tienes acceso a los archivos o a las bases de datos que usa tu aplicación.

ImagePullBackOff y ErrImagePull

ImagePullBackOff y ErrImagePull indican que la imagen que usa un contenedor no se puede cargar desde el registro de imágenes.

Puedes verificar este problema mediante Cloud Console o la herramienta de línea de comandos de kubectl.

kubectl

Para obtener más información sobre una imagen de contenedor de un Pod, ejecuta el comando siguiente:

kubectl describe pod pod-name

Console

Completa los pasos siguientes:

  1. Visita el panel Cargas de trabajo de GKE en Cloud Console.

    Visitar el panel Cargas de trabajo de GKE

  2. Selecciona la carga de trabajo deseada. La pestaña Descripción general muestra el estado de la carga de trabajo.

  3. En la sección Pods administrados, haz clic en el pod problemático.

  4. En el menú de pod, haz clic en la pestaña Eventos.

Si no se encuentra la imagen

Si tu imagen no se encuentra:

  1. Verifica que el nombre de la imagen sea correcto.
  2. Verifica que la etiqueta de la imagen sea correcta. (Intenta extraer la última imagen con :latest o sin etiqueta).
  3. Si la imagen tiene una ruta de registro completa, verifica que exista en el registro Docker que usas. Si proporcionas solo el nombre de la imagen, verifica el registro de Docker Hub.
  4. Prueba extraer la imagen de Docker de forma manual:

    • Establece una conexión SSH al nodo:

      Por ejemplo, establece una conexión SSH a example-instance en la zona us-central1-a:

      gcloud compute ssh example-instance --zone us-central1-a
      
    • Ejecuta docker pull image-name.

    Si esa opción funciona, necesitarás especificar ImagePullSecrets en un pod. Los pods solo pueden hacer referencia a los secretos de extracción de imagen en su propio espacio de nombres, por lo que este proceso puede realizarse una vez por espacio de nombres.

Si encuentras el error “permiso denegado” o “sin acceso de extracción”, verifica que accediste o tienes acceso a la imagen.

Si usas un registro privado, puede que necesite claves para leer imágenes.

Si la imagen está alojada en Container Registry, la cuenta de servicio asociada con tu grupo de nodos necesita acceso de lectura al depósito de Cloud Storage que contiene la imagen. Consulta la documentación de Container Registry para obtener más detalles.

PodUnschedulable

PodUnschedulable indica que tu pod no se puede programar debido a que los recursos son insuficientes o que hay algún error de configuración.

Recursos insuficientes

Puedes encontrar un error que indique una falta de CPU, memoria o algún otro recurso. Por ejemplo: “No hay nodos disponibles que coincidan con todos los predicados: CPU insuficiente (2)”, que indica que no hay CPU suficiente disponible en dos nodos para cumplir con las solicitudes de un pod.

La solicitud de CPU predeterminada es de 100 m o el 10% de una CPU (o un núcleo). Si deseas solicitar más o menos recursos, detalla el valor en la especificación del pod en spec: containers: resources: requests.

MatchNodeSelector

MatchNodeSelector indica que no hay nodos que coincidan con el selector de etiquetas del pod.

Para verificar esto, revisa las etiquetas que se especifican en el campo nodeSelector de la especificación del pod, debajo de spec: nodeSelector.

Para ver cómo están etiquetados los nodos en tu clúster, ejecuta el siguiente comando:

kubectl get nodes --show-labels

Para adjuntar una etiqueta a un nodo, ejecuta el siguiente comando:

kubectl label nodes node-name label-key=label-value

Reemplaza lo siguiente:

  • node-name con el nodo deseado
  • label-key con la clave de la etiqueta
  • label-value con el valor de la etiqueta

Para obtener más información, consulta la página sobre cómo asignar pods a nodos.

PodToleratesNodeTaints

PodToleratesNodeTaints indica que el pod no se puede programar en ningún nodo porque, por el momento, ningún nodo tolera su taint de nodo.

Para verificar que este sea el caso, ejecuta el comando siguiente:

kubectl describe nodes node-name

En el resultado, verifica el campo Taints, que enumera pares clave-valor y efectos de programación.

Si el efecto enumerado es NoSchedule, entonces no se puede programar ningún pod en ese nodo, a menos que tenga una tolerancia coincidente.

Una manera de resolver este problema es quitar el taint. Por ejemplo, para quitar un taint NoSchedule, ejecuta el siguiente comando:

kubectl taint nodes node-name key:NoSchedule-

PodFitsHostPorts

PodFitsHostPorts indica que un puerto que un nodo quiere usar ya está en uso.

Para resolver este problema, verifica el valor hostPort de la especificación del pod en spec: containers: ports: hostPort. Es posible que debas cambiar este valor para otro puerto.

No tiene disponibilidad mínima

Si un nodo tiene recursos adecuados, pero todavía ves el mensaje Does not have minimum availability, comprueba el estado del pod. Si el estado es SchedulingDisabled o Cordoned, el nodo no puede programar pods nuevos. Puedes verificar el estado de un nodo con Cloud Console o la herramienta de línea de comandos de kubectl.

kubectl

Para obtener los estados de los nodos, ejecuta el siguiente comando:

kubectl get nodes

Para habilitar la programación en el nodo, ejecuta lo siguiente:

kubectl uncordon node-name

Console

Completa los pasos siguientes:

  1. Visita el panel Cargas de trabajo de GKE en Cloud Console.

    Visitar el panel Clústeres de GKE

  2. Selecciona el clúster que desees. La pestaña Nodos muestra los nodos y su estado.

Para habilitar la programación en el nodo, realiza los pasos siguientes:

  1. En la lista, haz clic en el nodo deseado.

  2. En Detalles del nodo, haz clic en el botón Desvincular.

Desvincula PersistentVolumeClaims

Unbound PersistentVolumeClaims indica que el pod hace referencia a una PersistentVolumeClaim que no está vinculada. Este error puede ocurrir si no se pudo aprovisionar el PersistentVolume. Puedes verificar que el aprovisionamiento falló, si obtienes los eventos de la PersistentVolumeClaim y los examinas en busca de errores.

Para obtener los eventos, ejecuta el siguiente comando:

kubectl describe pvc statefulset-name-pvc-name-0

Reemplaza lo siguiente:

  • statefulset-name con el nombre del objeto StatefulSet
  • pvc-name con el nombre del objeto PersistentVolumeClaim

Esto también puede ocurrir si hubo un error de configuración durante el aprovisionamiento previo manual de un PersistentVolume y su vinculación a una PersistentVolumeClaim. Puedes intentar aprovisionar el volumen de nuevo.

Problemas de conectividad

Como se mencionó en el debate de Descripción general de la red, es importante comprender cómo los pods están conectados desde sus espacios de nombres de red con el espacio de nombres raíz en el nodo para solucionar problemas de manera efectiva. En el siguiente debate, supone que el clúster usa el CNI nativo de GKE en lugar del de Calico, a menos que se indique lo contrario. Es decir, no se aplicó ninguna política de red.

Los pods en nodos seleccionados no tienen disponibilidad

Si los pods en nodos seleccionados no tienen conectividad de red, asegúrate de que el puente de Linux esté activo:

ip address show cbr0

En caso contrario, actívalo:

sudo ip link set cbr0 up

Asegúrate de que el nodo esté aprendiendo las direcciones MAC de pod adjuntas en cbr0:

arp -an

Los pods en los nodos seleccionados tienen conectividad mínima

Si los pods en los nodos seleccionados tienen una conectividad mínima, primero debes confirmar si hay paquetes perdidos. Para ello, ejecuta tcpdump en el contenedor de la caja de herramientas:

sudo toolbox bash

Instala tcpdump en la caja de herramientas si aún no lo hiciste:

apt install -y tcpdump

Ejecuta tcpdump para cbr0:

tcpdump -ni cbr0 host hostname and port port-number and [tcp|udp|icmp]

Si parece que los paquetes grandes se descartan más adelante en el puente (por ejemplo, el protocolo de enlace TCP se completa, pero no se reciben saludos SSL), asegúrate de que la MTU del puente de Linux esté configurada de manera correcta en 1460 o menos:

ip address show cbr0

Cuando se utilizan superposiciones (por ejemplo, Weave o Flannel), esta MTU debe reducirse aún más para acomodar la sobrecarga de encapsulación en la superposición.

Conexiones fallidas intermitentes

iptables reenvía las conexiones hacia y desde los pods. Los flujos se registran como entradas en la tabla conntrack y, cuando hay muchas cargas de trabajo por nodo, el agotamiento de la tabla de conntrack puede manifestarse como un error. Estos se pueden registrar en la consola en serie del nodo, por ejemplo:

nf_conntrack: table full, dropping packet

Si puedes determinar que los problemas intermitentes se generan debido al agotamiento de conntrack, es recomendable aumentar el tamaño del clúster (y así reducir la cantidad de cargas de trabajo y flujos por nodo) o aumentar nf_conntrack_max:

new_ct_max=$(awk '$1 == "MemTotal:" { printf "%d\n", $2/32; exit; }' /proc/meminfo)
sysctl -w net.netfilter.nf_conntrack_max="${new_ct_max:?}" \
  && echo "net.netfilter.nf_conntrack_max=${new_ct_max:?}" >> /etc/sysctl.conf

Se informa un mensaje que dice “vincular: la dirección ya está en uso” para un contenedor

Un contenedor en un pod no puede iniciarse porque, de acuerdo con los registros del contenedor, el puerto al que la aplicación intenta vincularse ya está reservado. El contenedor entra en una falla de repetición. Por ejemplo, en Cloud Logging, se muestra lo siguiente:

resource.type="container"
textPayload:"bind: Address already in use"
resource.labels.container_name="redis"

2018-10-16 07:06:47.000 CEST 16 Oct 05:06:47.533 # Creating Server TCP listening socket *:60250: bind: Address already in use
2018-10-16 07:07:35.000 CEST 16 Oct 05:07:35.753 # Creating Server TCP listening socket *:60250: bind: Address already in use

Cuando Docker falla, a veces un contenedor en ejecución se retrasa y queda inactivo. El proceso todavía se está ejecutando en el espacio de nombres de red asignado para el pod, y está escuchando en su puerto. Debido a que Docker y el kubelet no saben sobre el contenedor inactivo, intentan iniciar un nuevo contenedor con un proceso nuevo, que no puede vincularse en el puerto, ya que se agrega al espacio de nombres de red ya asociado con el pod.

Para diagnosticar este problema, haz lo siguiente:

  1. Necesitas el UUID del pod en el campo .metadata.uuid:

    kubectl get pod -o custom-columns="name:.metadata.name,UUID:.metadata.uid" ubuntu-6948dd5657-4gsgg
    
    name                      UUID
    ubuntu-6948dd5657-4gsgg   db9ed086-edba-11e8-bdd6-42010a800164
    
  2. Obtén el resultado de los siguientes comandos del nodo:

    docker ps -a
    ps -eo pid,ppid,stat,wchan:20,netns,comm,args:50,cgroup --cumulative -H | grep [Pod UUID]
    
  3. Verifica los procesos en ejecución de este pod. Debido a que el UUID de los espacios de nombres de cgroup contiene el UUID del pod, puedes usar el comando grep para buscar el UUID del pod en el resultado ps. Usa también el comando grep para analizar la línea anterior, de modo que obtengas los procesos docker-containerd-shim que tienen el ID del contenedor en el argumento. Corta el resto de la columna cgroup para obtener un resultado más simple:

    # ps -eo pid,ppid,stat,wchan:20,netns,comm,args:50,cgroup --cumulative -H | grep -B 1 db9ed086-edba-11e8-bdd6-42010a800164 | sed s/'blkio:.*'/''/
    1283089     959 Sl   futex_wait_queue_me  4026531993       docker-co       docker-containerd-shim 276e173b0846e24b704d4 12:
    1283107 1283089 Ss   sys_pause            4026532393         pause           /pause                                     12:
    1283150     959 Sl   futex_wait_queue_me  4026531993       docker-co       docker-containerd-shim ab4c7762f5abf40951770 12:
    1283169 1283150 Ss   do_wait              4026532393         sh              /bin/sh -c echo hello && sleep 6000000     12:
    1283185 1283169 S    hrtimer_nanosleep    4026532393           sleep           sleep 6000000                            12:
    1283244     959 Sl   futex_wait_queue_me  4026531993       docker-co       docker-containerd-shim 44e76e50e5ef4156fd5d3 12:
    1283263 1283244 Ss   sigsuspend           4026532393         nginx           nginx: master process nginx -g daemon off; 12:
    1283282 1283263 S    ep_poll              4026532393           nginx           nginx: worker process
    
  4. En esta lista, puedes ver los ID de contenedor, que también deben estar visibles en docker ps.

    En este caso, ocurre lo siguiente:

    • docker-containerd-shim 276e173b0846e24b704d4 para pausar
    • docker-containerd-shim ab4c7762f5abf40951770 para SH con sleep (sleep-ctr)
    • docker-containerd-shim 44e76e50e5ef4156fd5d3 para nginx (echoserver-ctr)
  5. Verifica aquellos en el resultado de docker ps:

    # docker ps --no-trunc | egrep '276e173b0846e24b704d4|ab4c7762f5abf40951770|44e76e50e5ef4156fd5d3'
    44e76e50e5ef4156fd5d383744fa6a5f14460582d0b16855177cbed89a3cbd1f   gcr.io/google_containers/echoserver@sha256:3e7b182372b398d97b747bbe6cb7595e5ffaaae9a62506c725656966d36643cc                   "nginx -g 'daemon off;'"                                                                                                                                                                                                                                                                                                                                                                     14 hours ago        Up 14 hours                             k8s_echoserver-cnt_ubuntu-6948dd5657-4gsgg_default_db9ed086-edba-11e8-bdd6-42010a800164_0
    ab4c7762f5abf40951770d3e247fa2559a2d1f8c8834e5412bdcec7df37f8475   ubuntu@sha256:acd85db6e4b18aafa7fcde5480872909bd8e6d5fbd4e5e790ecc09acc06a8b78                                                "/bin/sh -c 'echo hello && sleep 6000000'"                                                                                                                                                                                                                                                                                                                                                   14 hours ago        Up 14 hours                             k8s_sleep-cnt_ubuntu-6948dd5657-4gsgg_default_db9ed086-edba-11e8-bdd6-42010a800164_0
    276e173b0846e24b704d41cf4fbb950bfa5d0f59c304827349f4cf5091be3327   k8s.gcr.io/pause-amd64:3.1
    

    En casos normales, verás todos los ID de contenedor de ps que aparecen en docker ps. Si hay uno que no ves, es un contenedor inactivo, y es probable que veas un proceso secundario del proceso docker-containerd-shim process a la escucha en el puerto TCP que informa que ya está en uso.

    Para verificar esto, ejecuta netstat en el espacio de nombres de red del contenedor. Obtén el pid de cualquier proceso de contenedor (así que NO docker-containerd-shim) del pod.

    En el ejemplo anterior, se incluye lo siguiente:

    • 1283107 - pause
    • 1283169 - sh
    • 1283185 - sleep
    • 1283263 - nginx master
    • 1283282 - nginx worker
    # nsenter -t 1283107 --net netstat -anp
    Active Internet connections (servers and established)
    Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
    tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      1283263/nginx: mast
    Active UNIX domain sockets (servers and established)
    Proto RefCnt Flags       Type       State         I-Node   PID/Program name     Path
    unix  3      [ ]         STREAM     CONNECTED     3097406  1283263/nginx: mast
    unix  3      [ ]         STREAM     CONNECTED     3097405  1283263/nginx: mast
    
    gke-zonal-110-default-pool-fe00befa-n2hx ~ # nsenter -t 1283169 --net netstat -anp
    Active Internet connections (servers and established)
    Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
    tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      1283263/nginx: mast
    Active UNIX domain sockets (servers and established)
    Proto RefCnt Flags       Type       State         I-Node   PID/Program name     Path
    unix  3      [ ]         STREAM     CONNECTED     3097406  1283263/nginx: mast
    unix  3      [ ]         STREAM     CONNECTED     3097405  1283263/nginx: mast
    

    También puedes ejecutar netstat mediante ip netns, pero necesitas vincular el espacio de nombres de red del proceso de forma manual, ya que Docker no realiza la vinculación:

    # ln -s /proc/1283169/ns/net /var/run/netns/1283169
    gke-zonal-110-default-pool-fe00befa-n2hx ~ # ip netns list
    1283169 (id: 2)
    gke-zonal-110-default-pool-fe00befa-n2hx ~ # ip netns exec 1283169 netstat -anp
    Active Internet connections (servers and established)
    Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
    tcp        0      0 0.0.0.0:8080            0.0.0.0:*               LISTEN      1283263/nginx: mast
    Active UNIX domain sockets (servers and established)
    Proto RefCnt Flags       Type       State         I-Node   PID/Program name     Path
    unix  3      [ ]         STREAM     CONNECTED     3097406  1283263/nginx: mast
    unix  3      [ ]         STREAM     CONNECTED     3097405  1283263/nginx: mast
    gke-zonal-110-default-pool-fe00befa-n2hx ~ # rm /var/run/netns/1283169
    

Mitigación:

La mitigación a corto plazo consiste en identificar procesos inactivos con el método descrito antes y finalizar los procesos mediante el comando kill [PID].

La mitigación a largo plazo implica identificar por qué Docker falla y solucionar el problema. Algunos motivos posibles son los siguientes:

  • Los procesos zombie se acumulan, por lo que no hay espacios de nombres PID
  • Error en Docker
  • Presión de recursos / OOM