Solución de 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).

Si necesitas asistencia adicional, comunícate con Atención al cliente de Cloud.

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 tu aplicación, sus Pods o tu objeto de controlador, consulta Soluciona problemas de aplicaciones.

Si tienes un problema relacionado con la conectividad entre las VMs de Compute Engine que se encuentran en la misma red de nube privada virtual (VPC) o en dos redes de VPC conectadas con el intercambio de tráfico entre redes de VPC, consulta Soluciona problemas La conectividad entre las instancias de máquina virtual (VM) con direcciones IP internas

Si experimentas una pérdida de paquetes cuando envías tráfico desde un clúster a una dirección IP externa mediante Cloud NAT, clústeres nativos de la VPC o Agente de enmascaramiento de IP, consulta Soluciona problemas de pérdida de paquetes de Cloud NAT desde un clúster de GKE.

Soluciona problemas con el comando kubectl

No se encuentra el comando kubectl

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

    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

Se agota el tiempo de espera del comando kubectl

Después de crear un clúster, si se intenta ejecutar el comando kubectl en el clúster, se muestra un error, como Unable to connect to the server: dial tcp IP_ADDRESS: connect: connection timed out o Unable to connect to the server: dial tcp IP_ADDRESS: i/o timeout.

Esto puede ocurrir cuando kubectl no puede comunicarse con el plano de control del clúster.

Para resolver este problema, verifica que el contexto donde el clúster esté establecido:

  1. Ve a $HOME/.kube/config o ejecuta el comando kubectl config view para verificar que el archivo de configuración contenga el contexto del clúster y la dirección IP externa del plano de control.

  2. Configura las credenciales del clúster:

    gcloud container clusters get-credentials CLUSTER_NAME \
        --location=COMPUTE_LOCATION \
        --project=PROJECT_ID
    

    Reemplaza lo siguiente:

    • CLUSTER_NAME: es el nombre de tu clúster.
    • COMPUTE_LOCATION: la ubicación de Compute Engine.
    • PROJECT_ID es el ID del proyecto en el que se creó el clúster de GKE.
  3. Si el clúster es un clúster de GKE privado, asegúrate de que la IP saliente de la máquina desde la que intentas conectarte esté incluida en la lista de redes autorizadas existentes. Puedes encontrar las redes autorizadas existentes en Console o mediante la ejecución del siguiente comando:

    gcloud container clusters describe CLUSTER_NAME \
        --location=COMPUTE_LOCATION \
        --project=PROJECT_ID \
        --format "flattened(masterAuthorizedNetworksConfig.cidrBlocks[])"
    

Si la IP saliente de la máquina no se incluye en la lista de redes autorizadas del resultado del comando anterior, sigue los pasos de No se puede acceder al plano de control de un clúster privado o Usa Cloud Shell para acceder a un clúster privado si te conectas desde Cloud Shell.

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 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 SSH o de proxy de Konnectivity para habilitar 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 ejecutan, es probable que el servidor de la API no pueda comunicarse con los nodos. Verifica las siguientes causas posibles:

  • El clúster no tiene nodos.

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

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

SSH

  • Las reglas de firewall de la red no permiten el acceso de SSH desde el 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 puede 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.

  • 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_ID]
    

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

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

  • 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 ssh-keys en los metadatos.

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

Proxy de Konnectivity

  • Determina si tu clúster usa el proxy de Konnectivity mediante la verificación de la siguiente implementación del sistema:

    kubectl get deployments konnectivity-agent --namespace kube-system
    
  • Las reglas de firewall de la red no permiten el acceso del agente de Konnectivity al plano de control.

    Durante la creación del clúster, los pods del agente de Konnectivity establecen y mantienen una conexión con el plano de control en el puerto 8132. Cuando se ejecuta uno de los comandos kubectl, el servidor de la API usa esta conexión para comunicarse con el clúster.

    Si las reglas de firewall de la red contienen reglas de denegación de salida, puede impedir que el agente se conecte. Debes permitir el tráfico de salida al plano de control del clúster en el puerto 8132. (En comparación, el servidor de la API usa 443).

  • La política de red del clúster bloquea la entrada del espacio de nombres kube-system al espacio de nombres workload. Para encontrar las políticas de red en el espacio de nombres afectado, ejecuta el siguiente comando:

    kubectl get networkpolicy --namespace AFFECTED_NAMESPACE
    

    Para resolver el problema, agrega lo siguiente al campo spec.ingress de las políticas de red:

    - from:
      - namespaceSelector:
          matchLabels:
            kubernetes.io/metadata.name: kube-system
        podSelector:
          matchLabels:
            k8s-app: konnectivity-agent
    

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.

Soluciona problemas de error 4xx

Errores de autenticación y autorización para conectarte a clústeres de GKE

Este problema puede ocurrir cuando intentas ejecutar un comando kubectl en tu clúster de GKE desde un entorno local. El comando falla y muestra un mensaje de error, por lo general, con el código de estado HTTP 401 (no autorizado).

La causa de este problema podría ser una de las siguientes:

  • El complemento de autenticación gke-gcloud-auth-plugin no está instalado ni configurado de forma correcta.
  • No tienes los permisos para conectarte al servidor de la API del clúster y ejecutar comandos de kubectl.

Para diagnosticar la causa, haz lo siguiente:

Conéctate al clúster mediante curl.

Mediante curl, se omiten la CLI de kubectl y el complemento gke-gcloud-auth-plugin.

  1. Establece las variables de entorno:

    APISERVER=https://$(gcloud container clusters describe CLUSTER_NAME --location=COMPUTE_LOCATION --format "value(endpoint)")
    TOKEN=$(gcloud auth print-access-token)
    
  2. Verifica que tu token de acceso sea válido:

    curl https://oauth2.googleapis.com/tokeninfo?access_token=$TOKEN
    
  3. Verifica que puedas conectarte al extremo principal de la API en el servidor de la API:

    gcloud container clusters describe CLUSTER_NAME --location=COMPUTE_LOCATION --format "value(masterAuth.clusterCaCertificate)" | base64 -d > /tmp/ca.crt
    curl -s -X GET "${APISERVER}/api/v1/namespaces" --header "Authorization: Bearer $TOKEN" --cacert /tmp/ca.crt
    

Si el comando curl falla con un resultado similar al siguiente, verifica que tengas los permisos correctos para acceder al clúster:

{
"kind": "Status",
"apiVersion": "v1",
"metadata": {},
"status": "Failure",
"message": "Unauthorized",
"reason": "Unauthorized",
"code": 401
}

Si el comando curl se ejecuta de forma correcta, verifica si el complemento es la causa.

Configura el complemento en kubeconfig

En los siguientes pasos, se configura tu entorno local para ignorar el objeto binario gke-gcloud-auth-plugin cuando se autentique en el clúster. En los clientes de Kubernetes que ejecutan la versión 1.25 y posteriores, el objeto binario gke-gcloud-auth-plugin es obligatorio, por lo que debes seguir estos pasos si deseas acceder a tu clúster sin necesidad del complemento.

  1. Instala la versión 1.24 de la CLI de kubectl mediante curl:

    curl -LO https://dl.k8s.io/release/v1.24.0/bin/linux/amd64/kubectl
    

    Puedes usar cualquier versión 1.24 o anterior de la CLI de kubectl.

  2. Abre el archivo de secuencia de comandos de inicio de la shell, como .bashrc para la shell de Bash, en un editor de texto:

    vi ~/.bashrc
    
  3. Agrega la siguiente línea al archivo y guárdala:

    export USE_GKE_GCLOUD_AUTH_PLUGIN=False
    
  4. Ejecuta la secuencia de comandos de inicio:

    source ~/.bashrc
    
  5. Obtén credenciales para el clúster, que configura el archivo .kube/config:

    gcloud container clusters get-credentials CLUSTER_NAME \
        --location=COMPUTE_LOCATION
    

    Reemplaza lo siguiente:

  6. Ejecuta un comando kubectl:

    kubectl cluster-info
    

Si recibes un error 401 o un error de autorización similar, asegúrate de tener los permisos correctos para realizar la operación.

Error 400: El grupo de nodos requiere recreación

El siguiente problema ocurre cuando intentas realizar una acción que vuelve a crear el plano de control y los nodos, como cuando completas una rotación de credenciales en curso.

La operación falla porque GKE no volvió a crear uno o más grupos de nodos en el clúster. En el backend, los grupos de nodos están marcados para su recreación, pero la operación de recreación real puede tomar un tiempo en comenzar.

El mensaje de error es similar al siguiente:

ERROR: (gcloud.container.clusters.update) ResponseError: code=400, message=Node pool "test-pool-1" requires recreation.

Para solucionar este problema, realiza una de las siguientes acciones:

  • Espera a que se realice la recreación. Esto puede tardar horas, días o semanas, según factores como los períodos de mantenimiento y las exclusiones existentes.
  • Inicia de forma manual una recreación de los grupos de nodos afectados mediante el inicio de una actualización de la versión a la misma versión que el plano de control. Para iniciar una recreación, ejecuta el siguiente comando:

    gcloud container clusters upgrade CLUSTER_NAME \
        --node-pool=POOL_NAME
    

    Una vez completada la actualización, vuelve a intentar la operación.

Error 403: Permisos insuficientes

El siguiente error ocurre cuando intentas conectarte a un clúster de GKE mediante gcloud container clusters get-credentials, pero la cuenta no tiene permiso para acceder al servidor de la API de Kubernetes.

ERROR: (gcloud.container.clusters.get-credentials) ResponseError: code=403, message=Required "container.clusters.get" permission(s) for "projects/<your-project>/locations/<region>/clusters/<your-cluster>".

Para solucionar este problema, haz lo siguiente:

  1. Identifica la cuenta que tiene el problema de acceso:

    gcloud auth list
    
  2. Otorga el acceso requerido a la cuenta mediante las instrucciones que aparecen en Autenticar en el servidor de la API de Kubernetes.

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

Vuelve a autenticarte en Google Cloud CLI:

gcloud auth login

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

Se borró tu cuenta de servicio predeterminada de Compute Engine, el agente de servicio de las APIs de Google o la cuenta de servicio asociada con GKE o editar de forma manual.

Cuando habilitas la API de Compute Engine o la API de Kubernetes Engine, Google Cloud crea las siguientes cuentas de servicio y agentes:

  • Cuenta de servicio predeterminada de Compute Engine con permisos de edición en tu proyecto.
  • Agente de servicio de las APIs de Google con permisos de edición en tu proyecto.
  • Cuenta de servicio de Google Kubernetes Engine con el rol de Agente de servicio de Kubernetes Engine en tu proyecto.

Si en algún momento editas esos permisos, quitas las vinculaciones de roles del proyecto, quitas la cuenta de servicio 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

El siguiente comando se puede usar para verificar que la cuenta de servicio de Google Kubernetes Engine tenga el rol de Agente de servicio de Kubernetes Engine asignada en el proyecto:

gcloud projects get-iam-policy PROJECT_ID

Reemplaza PROJECT_ID con el ID del proyecto.

Para resolver el problema, si quitaste el rol Agente de servicios de Kubernetes Engine de la cuenta de servicio de Google Kubernetes Engine, vuelve a agregarla. De lo contrario, puedes volver a habilitar la API de Kubernetes Engine, así, se restablecerán las cuentas de servicio y permisos de forma correcta.

Consola

  1. Ve a la página API y servicios en la consola de Google Cloud.

    Ir a APIs y servicios.

  2. Elige 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 CLI de gcloud para volver a agregar la cuenta de servicio:

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

Soluciona problemas de creación de clústeres de GKE

Error CONDITION_NOT_MET: Restricción de constraints/compute.vmExternalIpAccess violada

Tienes la restricción de la política de la organización constraints/compute.vmExternalIpAccess configurada en Deny All o para restringir las IP externas a instancias de VM específicas en el nivel de organización, carpeta o proyecto en el que intentas crear un clúster de GKE público.

Cuando creas clústeres de GKE públicos, las VMs de Compute Engine subyacentes, que conforman los nodos trabajadores de este clúster, tienen asignadas direcciones IP externas. Si configuras la restricción de la política de la organización constraints/compute.vmExternalIpAccess como Deny All o para restringir IP externas a instancias de VM específicas, la política evitará que los nodos trabajadores de GKE obtengan direcciones IP externas, lo que da como resultado la falla de creación del clúster.

Para encontrar los registros de la operación de creación de clústeres, puedes revisar los Registros de auditoría de operaciones de clústeres de GKE mediante el Explorador de registros con una búsqueda similar a la siguiente:

resource.type="gke_cluster"
logName="projects/test-last-gke-sa/logs/cloudaudit.googleapis.com%2Factivity"
protoPayload.methodName="google.container.v1beta1.ClusterManager.CreateCluster"
resource.labels.cluster_name="CLUSTER_NAME"
resource.labels.project_id="PROJECT_ID"

Para resolver este problema, asegúrate de que la política vigente de la restricción constraints/compute.vmExternalIpAccess sea Allow All en el proyecto en el que intentas crear un clúster público de GKE. Consulta Restringe direcciones IP externas a instancias de VM específicas para obtener información sobre cómo trabajar con esta restricción. Después de establecer la restricción en Allow All, borra el clúster con errores y crea uno nuevo. Esto es necesario porque no es posible reparar el clúster con errores.

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 la consola de Google Cloud.

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.

Consola

Sigue los siguientes pasos:

  1. Ve a la página Cargas de trabajo en la consola de Google Cloud.

    Ir a Cargas de trabajo

  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 solucionar los errores CrashLoopBackOff con la consola de Google Cloud:

  1. Ve a la guía interactiva de Pods en un bucle de fallas:

    Ir a la guía

  2. En Clúster, ingresa el nombre del clúster en el que deseas solucionar problemas.

  3. En Espacio de nombres, ingresa el espacio de nombres con el que deseas solucionar problemas.

  4. (Opcional) Crea una alerta que te notifique sobre errores CrashLoopBackOff futuros:

    1. En la sección Sugerencias para la mitigación futura, selecciona Crear una alerta.

Inspecciona registros

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

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.

Consola

Sigue los siguientes pasos:

  1. Ve a la página Cargas de trabajo en la consola de Google Cloud.

    Ir a Cargas de trabajo

  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 la consola de Google Cloud 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

Consola

Sigue los siguientes pasos:

  1. Ve a la página Cargas de trabajo en la consola de Google Cloud.

    Ir a Cargas de trabajo

  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 manera manual:

    • Establece una conexión SSH al nodo:

      Por ejemplo, para establecer una conexión SSH a una VM, ejecuta lo siguiente:

      gcloud compute ssh VM_NAME --zone=ZONE_NAME
      

      Reemplaza lo siguiente:

    • Ejecuta docker-credential-gcr configure-docker. Con este comando, se genera un archivo de configuración en /home/[USER]/.docker/config.json. Asegúrate de que este archivo incluya el registro de la imagen en el campo credHelpers. Por ejemplo, el siguiente archivo incluye información de autenticación para imágenes alojadas en asia.gcr.io, eu.gcr.io, gcr.io, marketplace.gcr.io y us.gcr.io:

      {
        "auths": {},
        "credHelpers": {
          "asia.gcr.io": "gcr",
          "eu.gcr.io": "gcr",
          "gcr.io": "gcr",
          "marketplace.gcr.io": "gcr",
          "us.gcr.io": "gcr"
        }
      }
      
    • 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.

Error de permiso denegado

Si encuentras el error “permiso denegado” o “sin acceso de extracción”, verifica que accediste y tienes acceso a la imagen. Prueba uno de los siguientes métodos según el registro en el que alojas tus imágenes.

Artifact Registry

Si la imagen está en Artifact Registry, la cuenta de servicio del grupo de nodos necesita acceso de lectura al repositorio que contiene la imagen.

Otorga el rol artifactregistry.reader a la cuenta de servicio:

gcloud artifacts repositories add-iam-policy-binding REPOSITORY_NAME \
    --location=REPOSITORY_LOCATION \
    --member=serviceAccount:SERVICE_ACCOUNT_EMAIL \
    --role="roles/artifactregistry.reader"

Reemplaza lo siguiente:

  • REPOSITORY_NAME: Es el nombre de tu repositorio de Artifact Registry.
  • REPOSITORY_LOCATION: Es la región de tu repositorio de Artifact Registry.
  • SERVICE_ACCOUNT_EMAIL: La dirección de correo electrónico de la cuenta de servicio de IAM asociada con tu grupo de nodos.

Container Registry

Si la imagen está en Container Registry, la cuenta de servicio del grupo de nodos necesita acceso de lectura al bucket de Cloud Storage que contiene la imagen.

Otorga el rol roles/storage.objectViewer a la cuenta de servicio para que pueda leer desde el bucket:

gsutil iam ch \
serviceAccount:SERVICE_ACCOUNT_EMAIL:roles/storage.objectViewer \
  gs://BUCKET_NAME

Reemplaza lo siguiente:

  • SERVICE_ACCOUNT_EMAIL: El correo electrónico de la cuenta de servicio asociada con tu grupo de nodos. Puedes enumerar todas las cuentas de servicio en tu proyecto mediante gcloud iam service-accounts list.
  • BUCKET_NAME: es el nombre del bucket de Cloud Storage que contiene tus imágenes. Puedes enumerar todos los buckets de tu proyecto con gsutil ls.

Si tu administrador de registros configuró repositorios de gcr.io en Artifact Registry para almacenar imágenes del dominio gcr.io en lugar de Container Registry, debes otorgar acceso de lectura a Artifact Registry en lugar de Container Registry.

Registro privado

Si la imagen está en un registro privado, es posible que necesites claves para acceder a las imágenes. Consulta Usa registros privados para obtener más información.

401 Autorizado: No se pueden extraer imágenes del repositorio de Container Registry privado

Un error similar al siguiente puede ocurrir cuando extraes una imagen de un repositorio de Container Registry privado:

gcr.io/PROJECT_ID/IMAGE:TAG: rpc error: code = Unknown desc = failed to pull and
unpack image gcr.io/PROJECT_ID/IMAGE:TAG: failed to resolve reference
gcr.io/PROJECT_ID/IMAGE]:TAG: unexpected status code [manifests 1.0]: 401 Unauthorized

Warning  Failed     3m39s (x4 over 5m12s)  kubelet            Error: ErrImagePull
Warning  Failed     3m9s (x6 over 5m12s)   kubelet            Error: ImagePullBackOff
Normal   BackOff    2s (x18 over 5m12s)    kubelet            Back-off pulling image
  1. Identifica el nodo que ejecuta el Pod:

    kubectl describe pod POD_NAME | grep "Node:"
    
  2. Verifica que el nodo tenga el permiso de almacenamiento:

    gcloud compute instances describe NODE_NAME \
        --zone=COMPUTE_ZONE --format="flattened(serviceAccounts[].scopes)"
    

    El permiso de acceso del nodo debe contener al menos uno de los siguientes elementos:

    serviceAccounts[0].scopes[0]: https://www.googleapis.com/auth/devstorage.read_only
    serviceAccounts[0].scopes[0]: https://www.googleapis.com/auth/cloud-platform
    
  3. Vuelve a crear el grupo de nodos al que pertenece el nodo con suficiente permiso. No puedes modificar los nodos existentes, debes volver a crear el nodo con el permiso correcto.

    • Recomendado: Crea un grupo de nodos nuevo con el permiso gke-default:

      gcloud container node-pools create NODE_POOL_NAME \
          --cluster=CLUSTER_NAME \
          --zone=COMPUTE_ZONE \
          --scopes="gke-default"
      
    • Crea un grupo de nodos nuevo solo con el permiso de almacenamiento:

      gcloud container node-pools create NODE_POOL_NAME \
          --cluster=CLUSTER_NAME \
          --zone=COMPUTE_ZONE \
          --scopes="https://www.googleapis.com/auth/devstorage.read_only"
      

Pod no programable

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.

Si tienes configurado el clúster de GKE para enviar el servidor de la API de Kubernetes y las métricas del programador de Kubernetes a Cloud Monitoring, puedes encontrar más información sobre estos errores en métricas del programador y métricas del servidor de la API .

Puedes solucionar los errores PodUnschedulable con la consola de Google Cloud:

  1. Ve a la guía interactiva de Pods no programables:

    Ir a la guía

  2. En Clúster, ingresa el nombre del clúster en el que deseas solucionar problemas.

  3. En Espacio de nombres, ingresa el espacio de nombres con el que deseas solucionar problemas.

  4. (Opcional) Crea una alerta que te notifique sobre errores PodUnschedulable futuros:

    1. En la sección Sugerencias para la mitigación futura, selecciona Crear una alerta.

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.

Si las solicitudes de recursos de tu pod superan las de un solo nodo de cualquier grupo de nodos apto, GKE no programa el pod ni activa el escalamiento vertical para agregar un nodo nuevo. Para que GKE programe el Pod, debes solicitar menos recursos para el Pod o crear un grupo de nodos nuevo con recursos suficientes.

También puedes habilitar el aprovisionamiento automático de nodos para que GKE pueda crear de forma automática grupos de nodos con nodos en los que puedan ejecutarse los Pods no programados.

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

Reemplaza lo siguiente:

  • NODE_NAME: el nodo deseado.
  • LABEL_KEY: la clave de la etiqueta.
  • LABEL_VALUE: el valor de la etiqueta.

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 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 la consola de Google Cloud 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

Consola

Sigue los siguientes pasos:

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

    Ir a Google Kubernetes Engine

  2. Selecciona el clúster deseado. 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.

Se alcanzó el límite máximo de Pods por nodo

Si todos los nodos del clúster alcanzan el límite de máximo de Pods por nodo, los Pods se detendrán en estado no programable. En la pestaña Eventos del Pod, verás un mensaje que incluye la frase Too many pods.

  1. Verifica la configuración de Maximum pods per node desde la pestaña Nodos en los detalles del clúster de GKE en la consola de Google Cloud.

  2. Obtén una lista de nodos:

    kubectl get nodes
    
  3. Para cada nodo, verifica la cantidad de Pods que se ejecutan en el nodo:

    kubectl get pods -o wide | grep NODE_NAME | wc -l
    
  4. Si se alcanza el límite, agrega un grupo de nodos nuevo o agrega nodos adicionales al grupo existente.

Se alcanzó el tamaño máximo del grupo de nodos con el escalador automático del clúster habilitado

Si el grupo de nodos alcanzó su tamaño máximo según la configuración del escalador automático de clústeres, GKE no activa el escalamiento vertical para el Pod que, de lo contrario, se programaría con este grupo de nodos. Si quieres que el pod se programe con este grupo de nodos, cambia la configuración del escalador automático de clústeres.

Tamaño máximo del grupo de nodos alcanzado con el escalador automático del clúster inhabilitado

Si el grupo de nodos alcanzó la cantidad máxima de nodos y el escalador automático de clústeres está inhabilitado, GKE no puede programar el Pod con el grupo de nodos. Aumenta el tamaño de tu grupo de nodos o habilita el escalador automático del clúster para que GKE cambie el tamaño del clúster de forma automática.

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: el nombre del objeto StatefulSet.
  • PVC_NAME: 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.

Cuota insuficiente

Verifica que tu proyecto tenga suficiente cuota de Compute Engine para que GKE escale verticalmente tu clúster. Si GKE intenta agregar un nodo a tu clúster para programar el pod y escalar verticalmente superaría la cuota disponible de tu proyecto, recibirás el mensaje de error scale.up.error.quota.exceeded.

Para obtener más información, consulta Errores de ScaleUp.

APIs obsoletas

Asegúrate de no usar APIs obsoletas que se quitan con la versión secundaria de tu clúster. Para obtener más información, consulta Bajas de GKE.

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 para cada interfaz de Pod de Linux esté configurada de manera correcta en la MTU de la red de VPC del clúster.

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.

MTU de GKE

La MTU seleccionada para una interfaz de Pod depende de la Interfaz de red de contenedor (CNI) que usan los nodos del clúster y la configuración de MTU de VPC subyacente. Para obtener más información, consulta Pods.

El valor de MTU de la interfaz del Pod es 1460 o se hereda de la interfaz principal del nodo.

CNI MTU GKE Standard
kubenet 1,460 Default
kubenet
(GKE versión 1.26.1 y posteriores)
Heredada Default
Calico 1,460

Se habilita mediante --enable-network-policy.

Para obtener más información, consulta Controla la comunicación entre Pods y Services mediante las políticas de red.

netd Heredada Se habilita mediante cualquiera de las siguientes opciones:
GKE Dataplane V2 Heredada

Se habilita mediante --enable-dataplane-v2.

Para obtener más información, consulta Usa GKE Dataplane V2.

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

También puedes usar NodeLocal DNSCache para reducir las entradas de seguimiento de conexiones.

Se informa un mensaje que dice &quot;vincular: la dirección ya está en uso&quot; 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   registry.k8s.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

Error: “no se pudo asignar para el rango 0: no hay direcciones IP en el rango configurado”

La versión 1.18.17 y posteriores de GKE solucionaron un problema en el que los eventos de memoria insuficiente (OOM) generaban una expulsión incorrecta del Pod si el Pod se borró antes de que se iniciaran sus contenedores. Esta expulsión incorrecta podría provocar pods huérfanos que continuaron teniendo direcciones IP reservadas del rango de nodos asignado. Con el tiempo, GKE se quedó sin direcciones IP para asignar a los Pods nuevos debido a la compilación de Pods huérfanos. Esto generó el mensaje de error failed to allocate for range 0: no IP addresses in range set, porque el rango de nodos asignado no tenía IP disponibles para asignar a pods nuevos.

Para resolver este problema, actualiza tu clúster y los grupos de nodos a la versión 1.18.17 o posterior de GKE.

Para evitar este problema y resolverlo en clústeres con versiones de GKE anteriores a la 1.18.17, aumenta tus límites de recursos a fin de evitar eventos de OOM en el futuro y, luego, recupera las direcciones IP mediante quitar los Pods huérfanos.

También puedes ver las estadísticas de uso de direcciones IP de GKE.

Quita los Pods huérfanos de los nodos afectados

Puedes quitar los Pods huérfanos si vacías el nodo, actualizas el grupo de nodos o mueves los directorios afectados.

Desvío del nodo (recomendado)

  1. Acordona el nodo para evitar que se programen Pods nuevos en él:

     kubectl cordon NODE
    

    Reemplaza NODE por el nombre del nodo que deseas desviar.

  2. Desvía el nodo. GKE reprograma automáticamente los Pods administrados por implementaciones en otros nodos. Usa la marca --force para desviar los Pods huérfanos que no tienen un recurso de administración.

     kubectl drain NODE --force
    
  3. Desacordona el nodo para permitir que GKE programe nuevos pods en él:

     kubectl uncordon NODE
    

Mueve los directorios afectados

Puedes identificar los directorios de Pods huérfanos en /var/lib/kubelet/pods y quitarlos del directorio principal para permitir que GKE finalice los Pods.

Soluciona problemas de finalización de recursos

Espacio de nombres atascado en el estado Terminating

Los espacios de nombres usan finalizadores de Kubernetes para evitar la eliminación cuando aún existen uno o más recursos dentro de un espacio de nombres. Cuando borras un espacio de nombres mediante el comando kubectl delete, este ingresa al estado Terminating hasta que Kubernetes borre sus recursos dependientes y borra todos los finalizadores. El controlador del ciclo de vida del espacio de nombres primero enumera todos los recursos en el espacio de nombres que GKE debe borrar. Si GKE no puede borrar un recurso dependiente o si el controlador del ciclo de vida del espacio de nombres no puede verificar que el espacio de nombres está vacío, el espacio de nombres permanece en el estado Terminating hasta que resuelvas el problema.

Para resolver un espacio de nombres atascado en el estado Terminating, debes identificar y quitar los componentes en mal estado que bloquean la eliminación. Prueba una de las siguientes soluciones.

Busca y quita servicios de API no disponibles

  1. Enumera los servicios de API no disponibles:

    kubectl get apiservice | grep False
    
  2. Soluciona los problemas de los servicios que no responden:

    kubectl describe apiservice API_SERVICE
    

    Reemplaza API_SERVICE por el nombre del servicio que no responde.

  3. Verifica si el espacio de nombres aún se está finalizando:

    kubectl get ns | grep Terminating
    

Busca y quita los recursos restantes

  1. Enumera todos los recursos restantes en el espacio de nombres de finalización:

    kubectl api-resources --verbs=list --namespaced -o name | xargs -n 1 kubectl get -n NAMESPACE
    

    Reemplaza NAMESPACE por el nombre del espacio de nombres que deseas borrar.

  2. Quita cualquier recurso que se muestre en el resultado.

  3. Verifica si el espacio de nombres aún se está finalizando:

    kubectl get ns | grep Terminating
    

Fuerza la eliminación del espacio de nombres

Puedes quitar los finalizadores que bloquean la eliminación del espacio de nombres para forzar la finalización del espacio de nombres.

  1. Guarda el manifiesto de espacio de nombre como un archivo YAML.

    kubectl get ns NAMESPACE -o yaml > ns-terminating.yml
    
  2. Abre el manifiesto en un editor de texto y quita todos los valores del campo spec.finalizers:

    vi ns-terminating.yml
    
  3. Verifica que el campo de los finalizadores esté vacío:

    cat ns-terminating.yml
    

    El resultado debe tener el siguiente aspecto:

    apiVersion: v1
    kind: Namespace
    metadata:
      annotations:
      name: NAMESPACE
    spec:
      finalizers:
    status:
      phase: Terminating
    
  4. Inicia un proxy HTTP para acceder a la API de Kubernetes:

    kubectl proxy
    
  5. Reemplaza el manifiesto del espacio de nombres mediante curl:

    curl -H "Content-Type: application/yaml" -X PUT --data-binary @ns-terminating.yml http://127.0.0.1:8001/api/v1/namespaces/NAMESPACE/finalize
    
  6. Verifica si el espacio de nombres aún se está finalizando:

    kubectl get ns | grep Terminating
    

Soluciona problemas de pérdida de paquetes de Cloud NAT desde un clúster de GKE

Las VMs de nodo en clústeres privados de GKE nativos de la VPC no tienen direcciones IP externas y no pueden conectarse a Internet por sí mismas. Puedes usar Cloud NAT para asignar las direcciones IP externas y los puertos que permiten que los clústeres privados hagan conexiones públicas.

Si una VM de nodo se queda sin su asignación de puertos IP y direcciones IP externas de Cloud NAT, los paquetes se descartarán. Para evitar esto, puedes reducir la frecuencia de paquetes salientes o aumentar la asignación de puertos y direcciones IP de origen de Cloud NAT disponibles. En las siguientes secciones, se describe cómo diagnosticar y solucionar problemas de pérdida de paquetes de Cloud NAT en el contexto de clústeres privados de GKE.

Diagnostica la pérdida de paquetes

En esta sección, se explica cómo registrar paquetes descartados con Cloud Logging y diagnosticar la causa de los paquetes descartados mediante Cloud Monitoring.

Registra paquetes descartados

Puedes registrar paquetes descartados con la siguiente consulta en Cloud Logging:

resource.type="nat_gateway"
resource.labels.region=REGION
resource.labels.gateway_name=GATEWAY_NAME
jsonPayload.allocation_status="DROPPED"
  • REGION: es el nombre de la región en la que se encuentra el clúster.
  • GATEWAY_NAME: el nombre de la puerta de enlace de Cloud NAT.

Este comando muestra una lista de todos los paquetes que descartó una puerta de enlace de Cloud NAT, pero no identifica la causa.

Supervisa las causas de la pérdida de paquetes

Para identificar las causas de los paquetes descartados, consulta el observador de métricas en Cloud Monitoring. Los paquetes se descartan por uno de tres motivos:

Para identificar los paquetes descartados debido a códigos de error OUT_OF_RESOURCES o ENDPOINT_ALLOCATION_FAILED, usa la siguiente consulta:

fetch nat_gateway
  metric 'router.googleapis.com/nat/dropped_sent_packets_count'
  filter (resource.gateway_name == NAT_NAME)
  align rate(1m)
  every 1m
  group_by [metric.reason],
    [value_dropped_sent_packets_count_aggregate:
       aggregate(value.dropped_sent_packets_count)]

Para identificar los paquetes descartados debido al código de error NAT_ALLOCATION_FAILED, usa la siguiente consulta:

fetch nat_gateway
  metric 'router.googleapis.com/nat/nat_allocation_failed'
  group_by 1m,
    [value_nat_allocation_failed_count_true:
       count_true(value.nat_allocation_failed)]
  every 1m

Soluciona problemas de Cloud NAT con el enmascaramiento de IP de GKE

Si las consultas anteriores muestran resultados vacíos y los Pods de GKE no pueden comunicarse con direcciones IP externas, soluciona los siguientes problemas de configuración:

Configuración Soluciona problemas
Cloud NAT configurado para aplicarse solo al rango de direcciones IP principal de la subred. Cuando Cloud NAT se configura solo para el rango de direcciones IP principal de la subred, los paquetes enviados desde el clúster hacia direcciones IP externas deben tener una dirección IP de nodo de origen. En esta configuración de Cloud NAT, haz lo siguiente:
  • Los Pods pueden enviar paquetes a direcciones IP externas si esos destinos de direcciones IP externas están sujetos al enmascaramiento de IP. Cuando implementes ip-masq-agent, verifica que la lista nonMasqueradeCIDRs no contenga la dirección IP y el puerto de destino. Los paquetes enviados a esos destinos se convierten primero en direcciones IP de nodo de origen antes de que Cloud NAT los procese.
  • Para permitir que los Pods se conecten a todas las direcciones IP externas con esta configuración de Cloud NAT, asegúrate de que se implemente ip-masq-agent y que la lista nonMasqueradeCIDRs solo contiene los rangos de direcciones IP del nodo y el Pod del clúster. Los paquetes enviados a destinos fuera del clúster primero se convierten en direcciones IP del nodo de origen antes de que Cloud NAT los procese.
  • Para evitar que los Pods envíen paquetes a algunas direcciones IP externas, debes bloquear esas direcciones de forma explícita para que no se enmascaren. Con el ip-masq-agent implementado, agrega las direcciones IP externas que deseas bloquear a la lista nonMasqueradeCIDRs. Los paquetes enviados a esos destinos salen del nodo con sus fuentes de dirección IP de Pod originales. Las direcciones IP del pod provienen de un rango de direcciones IP secundario de la subred del clúster. En esta configuración, Cloud NAT no funcionará en ese rango secundario.
Cloud NAT configurado para aplicarse solo al rango de direcciones IP secundario de la subred utilizado para las IP de Pods.

Cuando Cloud NAT se configura solo para el rango de direcciones IP secundario de la subred que usan las IP del Pod del clúster, los paquetes enviados desde el clúster hacia direcciones IP externas deben tener una dirección IP del Pod de origen. En esta configuración de Cloud NAT, se dan las siguientes situaciones:

  • El uso de un agente de enmascaramiento de IP hace que los paquetes pierdan su dirección IP de Pod de origen cuando se procesa con Cloud NAT. Para conservar la dirección IP del Pod de origen, especifica los rangos de direcciones IP de destino en una lista nonMasqueradeCIDRs. Con la ip-masq-agent implementada, cualquier paquete enviado a los destinos en la lista nonMasqueradeCIDRs conserva sus direcciones IP de Pod de origen antes de que Cloud NAT las procese.
  • Para permitir que los Pods se conecten a todas las direcciones IP externas con esta configuración de Cloud NAT, asegúrate de que ip-masq-agent esté implementado y que la lista nonMasqueradeCIDRs sea lo más grande posible (0.0.0.0/0 especifica todos los destinos de direcciones IP). Los paquetes enviados a todos los destinos conservan las direcciones IP del Pod de origen antes de que Cloud NAT las procese.

Optimizaciones para evitar la pérdida de paquetes

Puedes detener la pérdida de paquetes de las siguientes maneras:

Optimiza tu aplicación

Cuando una aplicación realiza varias conexiones salientes a la misma dirección IP y puerto de destino, puede consumir con rapidez todas las conexiones que Cloud NAT puede realizar a ese destino mediante la cantidad de direcciones de origen de NAT y tuplas de puertos de origen asignadas. En esta situación, reducir la tasa de paquetes salientes de la aplicación ayuda a reducir la pérdida de paquetes.

Para obtener detalles sobre cómo Cloud NAT usa direcciones de origen y puertos de origen para realizar conexiones, incluidos los límites de la cantidad de conexiones simultáneas a un destino, consultaPuertos y conexiones.

Reducir la tasa de conexiones salientes desde la aplicación puede ayudar a mitigar la pérdida de paquetes. Puedes lograr esto si reutlizar conexiones abiertas. Los métodos comunes para reutilizar conexiones incluyen la agrupación de conexiones, la multiplexación de conexiones con protocolos como HTTP/2 o el establecimiento de conexiones persistentes reutilizadas para varias solicitudes. Para obtener más información, consulta Puertos y conexiones.

La versión del nodo no es compatible con la versión del plano de control

Verifica qué versión de Kubernetes ejecuta el plano de control de tu clúster y, luego, verifica la versión de Kubernetes que ejecutan los grupos de nodos de tu clúster. 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 con tu clúster.

El equipo de GKE realiza actualizaciones periódicas del plano de control del clúster por ti de forma periódica. Los planos de control se actualizan a las versiones estables más nuevas de Kubernetes. De forma predeterminada, los nodos de un clúster tienen habilitada la actualización automática y se recomienda no inhabilitarla.

Si la actualización automática está inhabilitada para los nodos de un clúster y no actualizas manualmente la versión del grupo de nodos a una versión compatible con el plano de control, este no será compatible con tus nodos, ya que el plano de control se actualiza automáticamente con el tiempo. La incompatibilidad entre el plano de control y los nodos de tu clúster puede causar problemas inesperados.

Nota: La política de compatibilidad con el sesgo de versiones y versiones de Kubernetes garantiza que los planos de control sean compatibles con nodos de hasta dos versiones secundarias anteriores que el plano de control. Por ejemplo, los planos de control de Kubernetes 1.19 son compatibles con los nodos de Kubernetes 1.19, 1.18 y 1.17. Para resolver este problema, actualiza manualmente la versión del grupo de nodos a una versión compatible con el plano de control.

Si te preocupa que el proceso de actualización genere interrupciones en las cargas de trabajo que se ejecutan en los nodos afectados, sigue estos pasos para migrar tus cargas de trabajo a un grupo de nodos nuevo:

  1. Crea un grupo de nodos nuevo con una versión compatible.
  2. Acordona los nodos del grupo de nodos existente.
  3. De manera opcional, actualiza las cargas de trabajo que se ejecutan en el grupo de nodos existente para agregar un nodeSelector para la etiqueta cloud.google.com/gke-nodepool:NEW_NODE_POOL_NAME, en la que NEW_NODE_POOL_NAME es el nombre del grupo de nodos nuevo. Esto garantiza que GKE coloque esas cargas de trabajo en nodos en el grupo de nodos nuevo.
  4. Desvía el grupo de nodos existente.
  5. Comprueba que las cargas de trabajo se ejecuten de forma correcta en el grupo de nodos nuevo. Si es así, puedes borrar el grupo de nodos anterior. Si observas interrupciones en la carga de trabajo, reprograma las cargas de trabajo en los nodos existentes. Para ello, desacordona los nodos en el grupo de nodos existente y agota los nodos nuevos. Soluciona el problema y vuelve a intentarlo.

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 la consola de Google Cloud y desde CLI de Google Cloud de ; pero puedes verificarlo si ejecutas el siguiente comando o haces clic en los detalles del clúster en la consola de Google Cloud:

    gcloud container clusters describe CLUSTER_NAME
    

    El resultado de este comando debe incluir SYSTEM_COMPONENTS en la lista de enableComponents en la sección monitoringConfig, similar a esto:

    monitoringConfig:
      componentConfig:
        enableComponents:
        - SYSTEM_COMPONENTS
    

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

    gcloud container clusters update CLUSTER_NAME --monitoring=SYSTEM
    
  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.

Faltan permisos en la cuenta de los clústeres de VPC compartida

En el caso de los clústeres de VPC compartida, asegúrate de que la cuenta de servicio de GKE del proyecto de servicio tenga una vinculación para la función de usuario del agente de servicios de host en el proyecto host. Puedes hacer esto con la CLI de gcloud.

Para verificar si la vinculación de rol existe, ejecuta el siguiente comando en tu proyecto host:

gcloud projects get-iam-policy PROJECT_ID \
  --flatten="bindings[].members" \
  --format='table(bindings.role)' \
  --filter="bindings.members:SERVICE_ACCOUNT_NAME

Reemplaza lo siguiente:

  • PROJECT_ID: el ID de tu proyecto host.
  • SERVICE_ACCOUNT_NAME: El nombre de la cuenta de servicio de GKE

Busca la propiedad roles/container.hostServiceAgentUser en el resultado.

ROLE
...
roles/container.hostServiceAgentUser
...

Si el rol hostServiceAgentUser no está en la lista, sigue las instrucciones en Otorga el rol de usuario del agente de servicios de host para agregar la vinculación a la cuenta de servicio.

Restablece la cuenta de servicio predeterminada en el proyecto de Google Cloud

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 rol 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 CLI de gcloud o la consola de Google Cloud

gcloud

Ejecuta el siguiente comando:

gcloud projects get-iam-policy PROJECT_ID

Reemplaza PROJECT_ID con el ID del proyecto.

Consola

Visita la página IAM y administración en la consola de Google Cloud.

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_NUMBER=$(gcloud projects describe "PROJECT_ID" --format 'get(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

Habilita la cuenta de servicio predeterminada de Compute Engine

Es posible que los nodos no se registren con el clúster si la cuenta de servicio que se usa para el grupo de nodos está inhabilitada, que suele ser la cuenta de servicio predeterminada de Compute Engine.

Puedes verificar si la cuenta de servicio se inhabilitó en el proyecto con la CLI de gcloud o la consola de Google Cloud.

gcloud

Ejecuta el siguiente comando:

gcloud iam service-accounts list  --filter="NAME~'compute' AND disabled=true"

Consola

Ve a la página IAM y administración en la consola de Google Cloud.

Si en el comando o el panel se muestra que la cuenta de servicio está inhabilitada, ejecuta el siguiente comando para habilitarla:

gcloud iam service-accounts enable PROJECT_ID-compute@developer.gserviceaccount.com

Reemplaza PROJECT_ID con el ID del proyecto.

Si esto no resuelve los problemas de registro de nodos, consulta Soluciona problemas de registro de nodos para obtener más instrucciones sobre la solución de problemas.

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:

  • 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.

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

  • 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.

La autoridad de certificación raíz del clúster vencerá pronto

La autoridad de certificación raíz de tu clúster vencerá pronto. Para evitar que se interrumpan las operaciones normales del clúster, debes realizar una rotación de credenciales.

Ves el error “Instance Foo” no contiene metadatos 'instance-template'

Es posible que veas el error “Instance Foo” no contiene “instance-template” metadata” como un estado de un grupo de nodos que no puede actualizar, escalar ni realizar reparación automática de nodos.

Este mensaje indica que los metadatos de las instancias de VM, asignados por GKE, están dañados. Esto suele suceder cuando la automatización o las secuencias de comandos creadas de forma personalizada intentan agregar metadatos de instancia nuevos (como block-project-ssh-keys) y, en lugar de solo agregar o actualizar valores, también se borran los metadatos existentes. Puedes leer sobre los metadatos de instancias de VM en Establece metadatos personalizados.

En caso de cualquiera de los valores críticos de metadatos (entre otros: instance-template, kube-labels, kubelet-config, kubeconfig, cluster-name, configure-sh, cluster-uid), se borraron el nodo o el grupo de nodos completo en un estado inestable, ya que estos valores son fundamentales para las operaciones de GKE.

Si los metadatos de la instancia se dañaron, la mejor manera de recuperarlos es volver a crear el grupo de nodos que contiene las instancias de VM dañadas. Deberás agregar un grupo de nodos al clúster y aumentar el recuento de nodos en el grupo nuevo, a la vez que acordonas y quitas los nodos del otro. Consulta las instrucciones para migrar cargas de trabajo entre grupos de nodos.

Para encontrar quién y cuándo se editaron los metadatos de la instancia, puedes revisar la información del registro de auditoría de Compute Engine o buscar registros mediante el Explorador de registros con la consulta de búsqueda similar a esta:

resource.type="gce_instance_group_manager"
protoPayload.methodName="v1.compute.instanceGroupManagers.setInstanceTemplate"

En los registros, puedes encontrar la dirección IP del creador de la solicitud y el usuario-agente:

requestMetadata: {
  callerIp: "REDACTED"
  callerSuppliedUserAgent: "google-api-go-client/0.5 GoogleContainerEngine/v1"
}

La clave de Cloud KMS está inhabilitada.

El siguiente mensaje de error se produce si la cuenta de servicio predeterminada de GKE no puede acceder a la clave de Cloud KMS.

Cluster problem detected (Kubernetes Engine Service Agent account unable to use CloudKMS key configured for Application Level encryption).

Para resolver este problema, vuelve a habilitar la clave inhabilitada.

Para obtener más información sobre los secretos en GKE, consulta Encripta secretos en la capa de aplicación.