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 Soluciona problemas de clústeres en la documentación de Kubernetes.

Si tienes un problema con la aplicación, sus pods o su objeto de controlador, consulta Soluciona problemas de aplicaciones.

No se encuentra el comando kubectl

Primero, instala el objeto binario kubectl mediante la ejecución del siguiente comando:

sudo gcloud components update kubectl

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 de escribir la ruta del 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/

Por último, ejecuta el siguiente comando a fin de cargar tu 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 en CLUSTER_NAME, usa el siguiente comando a fin de hacer una lista de 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 se interrumpen

Estos comandos dependen de que la instancia principal del clúster pueda comunicarse con los nodos en el clúster. Sin embargo, debido a que la instancia principal no se encuentra en la misma red de Compute Engine que los nodos del clúster, dependemos de los túneles 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 llaves SSH a fin de agregarlos a la lista de VM de usuarios autorizados. GKE también agrega una regla de firewall a la red de Compute Engine que permite el acceso SSH desde la dirección IP de la instancia principal a cada nodo en el clúster.

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

  1. El clúster no tiene nodos.

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

    A fin de solucionar este problema, cambia el tamaño del clúster, de modo que tenga al menos un nodo.

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

    En teoría, este problema solo afecta a la versión 1.1 de Kubernetes, pero también se puede generar como consecuencia de cambios reiterados en el tamaño del clúster.

    Para solucionar este problema, borra los pods que hayan estado en un estado de finalización durante unos cuantos minutos. De esa manera, los nodos antiguos se quitan de la API de la instancia principal y se reemplazan por los nodos nuevos.

  3. Las reglas de firewall de la red no permiten el acceso SSH a la instancia principal.

    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 con el formato gke-<cluster_name>-<random-characters>-ssh que permite el acceso SSH de manera específica a los nodos del clúster desde la IP de la instancia principal. Si no existe ninguna de estas reglas, la instancia principal no podrá abrir los túneles SSH.

    Para solucionar este problema, vuelve a agregar una regla de firewall que permita el acceso a las VM con la etiqueta que se encuentran en todos los nodos del clúster de la dirección IP de la instancia principal.

  4. La entrada de los metadatos comunes del proyecto para las “llaves SSH” está llena.

    Si la entrada de los metadatos del proyecto llamada “llaves SSH” está cerca del límite de tamaño de 32 KiB, GKE no puede agregar su propia llave SSH a fin de permitir que se abran los túneles SSH. Puedes ver los metadatos del proyecto si ejecutas gcloud compute project-info describe [--project=PROJECT]. Luego, verifica la longitud de la lista de llaves SSH.

    Para solucionar este problema, borra algunas de las llaves SSH que ya no sean necesarias.

  5. Estableciste un campo de metadatos con la clave “llaves SSH” en las VM del clúster.

    Para el agente de nodo en las VM, es preferible contar con llaves SSH por instancia en vez de llaves SSH por proyecto completo. Por esta razón, si estableciste cualquier llave SSH en los nodos del clúster, los nodos no respetarán la llave SSH de la instancia principal en los metadatos del proyecto. Para verificarlo, ejecuta gcloud compute instances describe <VM-name> y busca un campo que diga “llaves SSH” en los metadatos.

    Para solucionar este problema, 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 el paquete de operaciones de Google Cloud

Asegúrate de haber activado la API de Cloud Monitoring y la API de Cloud Logging en tu proyecto y de que puedes ver el proyecto 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.

    La supervisión está habilitada de forma predeterminada en los clústeres creados mediante Developers Console y la herramienta de línea de comandos de gcloud, pero lo puedes verificar si ejecutas el siguiente comando o si haces clic en los detalles del clúster en Developers Console:

    gcloud container clusters describe cluster-name

    El resultado que muestra la herramienta de línea de comandos de gcloud debe indicar que el “monitoringService” es “monitoring.googleapis.com”, y Cloud Monitoring debe estar habilitado en Developers Console.

    Si la supervisión no está habilitada, habilítala mediante la ejecución del siguiente comando:

    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 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) que se ejecuta 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 buscar pods con heapster o gke-metrics-agent en el nombre.

  4. ¿La instancia principal del clúster puede comunicarse con los nodos?

    Cloud Monitoring depende de eso. Puedes ejecutar kubectl logs [POD-NAME] para verificar si ese es el caso. Si en el comando se muestra un error, es probable que los túneles SSH sean los que causan el problema. Consulta esta sección.

Si tienes un problema relacionado con el agente de Logging del paquete de operaciones, consulta la documentación de la solución de problemas.

Para obtener más información, consulta la documentación del paquete de operaciones.

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 cuenta por completo o inhabilitas la API, fallarán la creación de clústeres y todas las funciones de administración.

El nombre de la cuenta de servicio de Google Kubernetes Engine es el siguiente:

    service-[PROJECT_NUMBER]@container-engine-robot.iam.gserviceaccount.com
    

En el ejemplo anterior, [PROJECT_NUMBER] es el número del proyecto.

Para solucionar este problema, debes volver a habilitar la API de Kubernetes Engine; así, se restablecerán tus cuentas de servicio y permisos.

  1. Visita la página de API y servicios.
  2. Selecciona el proyecto.
  3. Haz clic en Habilitar API y servicios.
  4. Busca Kubernetes y, luego, selecciona la API en 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.

Como alternativa, puedes usar la herramienta de línea de comandos 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 el clúster ejecuta la versión 1.9.x de Kubernetes, las reglas de firewall automáticas cambiaron a fin de no permitir que las cargas de trabajo en un clúster de GKE establezcan 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 versiones anteriores) si realizas los siguientes pasos:

Primero, encuentra la red del clúster mediante el siguiente comando:

gcloud container clusters describe [CLUSTER_NAME] --format=get"(network)"

Luego, obtén el CIDR de IPv4 del clúster que se usa para los contenedores mediante el siguiente comando:

gcloud container clusters describe [CLUSTER_NAME] --format=get"(clusterIpv4Cidr)"

Por último, crea una regla de firewall para la red con el CIDR como el rango de origen y habilita todos los protocolos mediante el siguiente comando:

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

container-engine-robot, la cuenta de servicio predeterminada de GKE, se puede desvincular de un proyecto por accidente. El agente de servicio de GKE es una función de Cloud Identity and Access Management (Cloud IAM) que le otorga a la cuenta de servicio los permisos necesarios 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 impedirte implementar aplicaciones y realizar otras operaciones de clúster.

Puedes verificar si la cuenta de servicio se quitó de tu proyecto. Para hacerlo, ejecuta gcloud projects get-iam-policy [PROJECT_ID] o visita la página Cloud IAM y administración en Google 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 quitaste la vinculación de función de agente de servicio de GKE, ejecuta los siguientes comandos para restablecerla:

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ó, ejecuta el siguiente comando:

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 a nivel de la aplicación.

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

Soluciona problemas de cargas de trabajo implementadas

GKE muestra un error si existen problemas con los pods de una carga de trabajo. Puedes comprobar el estado de un pod mediante la herramienta de línea de comandos de kubectl o Google 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:

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 que desees. En la pestaña Descripción general, se 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 habituales que muestran las cargas de trabajo y cómo resolverlos.

CrashLoopBackOff

CrashLoopBackOff indica que un contenedor falla repetidas veces después de reiniciarse. Existen varias razones por las que un contenedor puede fallar, 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 del pod falla mediante la herramienta de línea de comandos 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 lo siguiente:

kubectl logs [POD_NAME]

En el comando anterior, [POD_NAME] es el nombre del pod con el error.

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 que desees. En la pestaña Descripción general, se muestra el estado de la carga de trabajo.

  3. En la sección Pods administrados, haz clic en el pod con el error.

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

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

Puedes encontrarlo en el resultado de kubectl describe pod [POD_NAME] 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 del siguiente modo:

kubectl exec -it [POD_NAME] -- /bin/bash

Si hay más de un contenedor en el 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 la imagen de contenedor de un pod, ejecuta el siguiente comando:

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 que desees. En la pestaña Descripción general, se muestra el estado de la carga de trabajo.

  3. En la sección Pods administrados, haz clic en el pod con el error.

  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 de Docker que usas. Si proporcionas solo el nombre de la imagen, verifica el registro de Docker Hub.
  4. Intenta extraer la imagen de Docker de forma manual mediante estos pasos:

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

      gcloud compute ssh example-instance --zone us-central1-a
    • Ejecuta docker pull [IMAGE_NAME].
      Si esta opción funciona, es posible que necesites 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 debe realizarse una vez por cada 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 se aloja en Google Container Registry, la cuenta de servicio asociada con el grupo de nodos necesita acceso de lectura al depósito de Google Cloud Storage que contiene la imagen. Consulta la documentación sobre Google Container Registry para obtener más detalles.

PodUnschedulable

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

Recursos insuficientes

Puedes experimentar 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 insuficientes (2)”, que indica que no hay suficientes CPU disponibles en dos nodos para cumplir con las solicitudes de un pod.

La solicitud de CPU predeterminada es de 100m 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]

Para obtener más información, consulta Asigna 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 es el caso, ejecuta el siguiente comando:

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, quitar un taint NoSchedule:

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 por 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. Para verificar el estado de un nodo, sigue estos pasos:

kubectl

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

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 eventos, ejecuta lo siguiente:

    kubectl describe pvc [STATEFULSET_NAME]-[PVC_NAME]-0
    

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, supón 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 los nodos seleccionados no tienen disponibilidad

Si los pods en los 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 1,460 o menos:

ip address show cbr0

Cuando se usan superposiciones (por ejemplo, Weave o Flannel), esta MTU debe reducirse aún más a fin de que se pueda alojar la sobrecarga de encapsulación en la superposición.

Conexiones fallidas intermitentes

Las iptables reenvían las conexiones hacia y desde los pods. Los flujos se registran como entradas en la tabla de conntrack y, cuando hay muchas cargas de trabajo por nodo, el agotamiento de la tabla de conntrack puede generar 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 genera 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 sigue en ejecución en el espacio de nombres de red asignado para el pod, y sigue la escucha en su puerto. Debido a que Docker y el kubelet no saben sobre el contenedor inactivo, intentan iniciar un contenedor nuevo 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, necesitas el UUID del pod, 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
    

También 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]

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
    

En esta lista, puedes ver los ID de contenedor, que también deben estar visibles en docker ps.

En este caso, se incluye lo siguiente:

  • docker-containerd-shim 276e173b0846e24b704d4 para pause
  • docker-containerd-shim ab4c7762f5abf40951770 para sh con sleep (sleep-ctr)
  • docker-containerd-shim 44e76e50e5ef4156fd5d3 para nginx (echoserver-ctr)

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 mediante el método descrito antes y eliminarlos con 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