En esta página se explica cómo usar el balanceo de carga nativo de contenedores en Google Kubernetes Engine (GKE). El balanceo de carga nativo de contenedores permite que los balanceadores de carga se dirijan directamente a los pods de Kubernetes y distribuyan el tráfico de forma uniforme entre los pods.
Para obtener más información sobre las ventajas, los requisitos y las limitaciones del balanceo de carga nativo de contenedores, consulta el artículo Balanceo de carga nativo de contenedores.
Antes de empezar
Antes de empezar, asegúrate de que has realizado las siguientes tareas:
- Habilita la API de Google Kubernetes Engine. Habilitar la API de Google Kubernetes Engine
- Si quieres usar Google Cloud CLI para esta tarea, instálala y, a continuación, inicialízala. Si ya has instalado la gcloud CLI, obtén la versión más reciente ejecutando
gcloud components update
.
Usar el balanceo de carga nativo de contenedores
En las siguientes secciones se explica cómo configurar el balanceo de carga nativo de contenedores en GKE.
Crea un clúster nativo de VPC
Para usar el balanceo de carga nativo de contenedores, tu clúster de GKE debe tener habilitadas las IPs con alias.
Por ejemplo, el siguiente comando crea un clúster de GKE, neg-demo-cluster
, con una subred aprovisionada automáticamente:
En el modo Autopilot, las direcciones IP de alias están habilitadas de forma predeterminada:
gcloud container clusters create-auto neg-demo-cluster \ --location=COMPUTE_LOCATION
Sustituye
COMPUTE_LOCATION
por la ubicación de Compute Engine del clúster.En el modo Estándar, habilita las direcciones IP de alias al crear el clúster:
gcloud container clusters create neg-demo-cluster \ --enable-ip-alias \ --create-subnetwork="" \ --network=default \ --location=us-central1-a
Crear un despliegue
En el siguiente ejemplo de Deployment,
neg-demo-app
, se ejecuta una sola instancia de un servidor HTTP contenedorizado. Te recomendamos que uses cargas de trabajo que utilicen la señal Pod readiness.
Usar los comentarios sobre la disponibilidad de los pods
apiVersion: apps/v1 kind: Deployment metadata: labels: run: neg-demo-app # Label for the Deployment name: neg-demo-app # Name of Deployment spec: selector: matchLabels: run: neg-demo-app template: # Pod template metadata: labels: run: neg-demo-app # Labels Pods from this Deployment spec: # Pod specification; each Pod created by this Deployment has this specification containers: - image: registry.k8s.io/serve_hostname:v1.4 # Application to run in Deployment's Pods name: hostname # Container name ports: - containerPort: 9376 protocol: TCP
Usar un retraso codificado
apiVersion: apps/v1 kind: Deployment metadata: labels: run: neg-demo-app # Label for the Deployment name: neg-demo-app # Name of Deployment spec: minReadySeconds: 60 # Number of seconds to wait after a Pod is created and its status is Ready selector: matchLabels: run: neg-demo-app template: # Pod template metadata: labels: run: neg-demo-app # Labels Pods from this Deployment spec: # Pod specification; each Pod created by this Deployment has this specification containers: - image: registry.k8s.io/serve_hostname:v1.4 # Application to run in Deployment's Pods name: hostname # Container name # Note: The following line is necessary only on clusters running GKE v1.11 and lower. # For details, see https://cloud.google.com/kubernetes-engine/docs/how-to/container-native-load-balancing#align_rollouts ports: - containerPort: 9376 protocol: TCP terminationGracePeriodSeconds: 60 # Number of seconds to wait for connections to terminate before shutting down Pods
En esta implementación, cada contenedor ejecuta un servidor HTTP. El servidor HTTP devuelve el nombre de host del servidor de aplicaciones (el nombre del pod en el que se ejecuta el servidor) como respuesta.
Guarda este archivo de manifiesto como neg-demo-app.yaml
y, a continuación, crea la implementación:
kubectl apply -f neg-demo-app.yaml
Crear un servicio para un balanceador de carga nativo de contenedores
Una vez que hayas creado una implementación, tendrás que agrupar sus pods en un servicio.
El siguiente servicio de ejemplo, neg-demo-svc
, se dirige al ejemplo de Deployment que has creado en la sección anterior:
apiVersion: v1
kind: Service
metadata:
name: neg-demo-svc # Name of Service
spec: # Service's specification
type: ClusterIP
selector:
run: neg-demo-app # Selects Pods labelled run: neg-demo-app
ports:
- name: http
port: 80 # Service's port
protocol: TCP
targetPort: 9376
El balanceador de carga no se crea hasta que crea un objeto Ingress para el servicio.
Guarda este archivo de manifiesto como neg-demo-svc.yaml
y, a continuación, crea el servicio:
kubectl apply -f neg-demo-svc.yaml
Crear un objeto Ingress para el servicio
En el siguiente ejemplo de Ingress,
neg-demo-ing
, se dirige al servicio que has creado:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: neg-demo-ing
spec:
defaultBackend:
service:
name: neg-demo-svc # Name of the Service targeted by the Ingress
port:
number: 80 # Should match the port used by the Service
Guarda este manifiesto como neg-demo-ing.yaml
y, a continuación, crea el Ingress:
kubectl apply -f neg-demo-ing.yaml
Al crear el Ingress, se crea un balanceador de carga de aplicaciones en el proyecto y se crean grupos de puntos finales de red(NEGs) en cada zona en la que se ejecuta el clúster. Los endpoints de la NEG y los del servicio se mantienen sincronizados.
Verificar el Ingress
Una vez que hayas desplegado una carga de trabajo, agrupado sus pods en un servicio y creado un Ingress para el servicio, debes verificar que el Ingress haya aprovisionado el balanceador de carga nativo de contenedor correctamente.
Consulta el estado del Ingress:
kubectl describe ingress neg-demo-ing
El resultado incluye eventos ADD
y CREATE
:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ADD 16m loadbalancer-controller default/neg-demo-ing
Normal Service 4s loadbalancer-controller default backend set to neg-demo-svc:32524
Normal CREATE 2s loadbalancer-controller ip: 192.0.2.0
Probar el balanceador de carga
En las siguientes secciones se explica cómo puedes probar la funcionalidad de un balanceador de carga nativo de contenedor.
Visitar la dirección IP de Ingress
Espera varios minutos a que se configure el balanceador de carga de aplicaciones.
Para comprobar que el balanceador de carga nativo de contenedores funciona, visita la dirección IP de Ingress.
Para obtener la dirección IP de Ingress, ejecuta el siguiente comando:
kubectl get ingress neg-demo-ing
En la salida del comando, la dirección IP de Ingress se muestra en la columna ADDRESS
. Visita la dirección IP en un navegador web.
Comprobar el estado de los servicios backend
También puedes consultar el estado de salud del servicio de backend del balanceador de carga.
Obtén una lista de los servicios backend que se ejecutan en tu proyecto:
gcloud compute backend-services list
Anota el nombre del servicio de backend, que incluye el nombre del servicio, como
neg-demo-svc
.Obtén el estado de salud del servicio backend:
gcloud compute backend-services get-health BACKEND_SERVICE_NAME --global
Sustituye
BACKEND_SERVICE_NAME
por el nombre del servicio backend.
Probar el objeto Ingress
Otra forma de comprobar que el balanceador de carga funciona correctamente es escalando el Deployment de ejemplo, enviando solicitudes de prueba al Ingress y verificando que responde el número correcto de réplicas.
Escala la
neg-demo-app
implementación de una a dos instancias:kubectl scale deployment neg-demo-app --replicas 2
Este comando puede tardar varios minutos en completarse.
Verifica que el lanzamiento se haya completado:
kubectl get deployment neg-demo-app
El resultado debe incluir dos réplicas disponibles:
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE neg-demo-app 2 2 2 2 26m
Obtén la dirección IP de Ingress:
kubectl describe ingress neg-demo-ing
Si este comando devuelve un error 404, espera unos minutos a que se inicie el balanceador de carga y vuelve a intentarlo.
Cuenta el número de respuestas distintas del balanceador de carga:
for i in `seq 1 100`; do \ curl --connect-timeout 1 -s IP_ADDRESS && echo; \ done | sort | uniq -c
Sustituye
IP_ADDRESS
por la dirección IP de entrada.El resultado debería ser similar al siguiente:
44 neg-demo-app-7f7dfd7bc6-dcn95 56 neg-demo-app-7f7dfd7bc6-jrmzf
En esta salida, el número de respuestas distintas es el mismo que el número de réplicas, lo que indica que todos los pods de backend están sirviendo tráfico.
Limpieza
Después de completar las tareas de esta página, siga estos pasos para eliminar los recursos y evitar que se le cobren cargos no deseados en su cuenta:
Elimina el clúster
gcloud
gcloud container clusters delete neg-demo-cluster
Consola
Ve a la página Google Kubernetes Engine en la Trusted Cloud consola.
Selecciona neg-demo-cluster y haz clic en delete Eliminar.
Cuando se te pida que confirmes la acción, haz clic en Eliminar.
Solución de problemas
Usa las técnicas que se indican a continuación para verificar tu configuración de red. En las siguientes secciones se explica cómo resolver problemas específicos relacionados con el balanceo de carga nativo del contenedor.
Consulta la documentación sobre balanceo de carga para saber cómo enumerar tus grupos de endpoints de red.
Puedes encontrar el nombre y las zonas del NEG que corresponden a un servicio en la anotación
neg-status
del servicio. Obtén la especificación del servicio con lo siguiente:kubectl get svc SVC_NAME -o yaml
La anotación
metadata:annotations:cloud.google.com/neg-status
muestra el nombre del NEG correspondiente al servicio y las zonas del NEG.Puedes comprobar el estado del servicio backend que corresponde a un NEG con el siguiente comando:
gcloud compute backend-services --project PROJECT_NAME \ get-health BACKEND_SERVICE_NAME --global
El servicio de backend tiene el mismo nombre que su NEG.
Para imprimir los registros de eventos de un servicio, sigue estos pasos:
kubectl describe svc SERVICE_NAME
La cadena de nombre del servicio incluye el nombre y el espacio de nombres del servicio de GKE correspondiente.
No se puede crear un clúster con IPs de alias
- Síntomas
Cuando intentes crear un clúster con IPs de alias, puede que se produzca el siguiente error:
ResponseError: code=400, message=IP aliases cannot be used with a legacy network.
- Posibles causas
Este error se produce si intentas crear un clúster con IPs de alias que también use una red antigua.
- Resolución
Asegúrate de no crear un clúster con IPs de alias y una red antigua habilitada al mismo tiempo. Para obtener más información sobre cómo usar IPs con alias, consulta el artículo Crear un clúster nativo de VPC.
El tráfico no llega a los endpoints
- Síntomas
- Errores 502 o 503, o conexiones rechazadas.
- Posibles causas
Los nuevos endpoints suelen estar disponibles después de asociarlos al balanceador de carga, siempre que respondan a las comprobaciones de estado. Es posible que se produzcan errores 502 o que se rechacen conexiones si el tráfico no puede llegar a los endpoints.
Los errores 502 y las conexiones rechazadas también pueden deberse a un contenedor que no gestione
SIGTERM
. Si un contenedor no gestiona explícitamenteSIGTERM
, se cierra inmediatamente y deja de gestionar solicitudes. El balanceador de carga sigue enviando tráfico entrante al contenedor finalizado, lo que provoca errores.El balanceador de carga nativo de contenedores solo tiene un endpoint de backend. Durante una actualización gradual, el endpoint antiguo se desprograma antes de que se programe el nuevo.
Los pods de backend se implementan en una zona nueva por primera vez después de aprovisionar un balanceador de carga nativo de contenedor. La infraestructura del balanceador de carga se programa en una zona cuando hay al menos un endpoint en ella. Cuando se añade un nuevo endpoint a una zona, se programa la infraestructura del balanceador de carga, lo que provoca interrupciones del servicio.
- Resolución
Configura los contenedores para que gestionen
SIGTERM
y sigan respondiendo a las solicitudes durante el periodo de gracia de finalización (30 segundos de forma predeterminada). Configura los pods para que empiecen a fallar las comprobaciones del estado cuando recibanSIGTERM
. Esto indica al balanceador de carga que deje de enviar tráfico al pod mientras se está desprogramando el endpoint.Si tu aplicación no se cierra correctamente y deja de responder a las solicitudes al recibir una señal
SIGTERM
, puedes usar el hook preStop para gestionar la señalSIGTERM
y seguir sirviendo tráfico mientras se está desprogramando el endpoint.lifecycle: preStop: exec: # if SIGTERM triggers a quick exit; keep serving traffic instead command: ["sleep","60"]
Consulta la documentación sobre la finalización de pods.
Si el backend del balanceador de carga solo tiene una instancia, configura la estrategia de lanzamiento para evitar que se cierre la única instancia antes de que se programe por completo la nueva. En el caso de los pods de aplicaciones gestionados por la carga de trabajo
Deployment
, esto se puede conseguir configurando la estrategia de lanzamiento con el parámetromaxUnavailable
igual a0
.strategy: rollingUpdate: maxSurge: 1 maxUnavailable: 0
Para solucionar el problema de que el tráfico no llega a los endpoints, compruebe que las reglas del cortafuegos permiten el tráfico TCP entrante a sus endpoints en los intervalos
130.211.0.0/22
y35.191.0.0/16
. Para obtener más información, consulta el artículo Añadir comprobaciones del estado de la documentación de Cloud Load Balancing.Consulta los servicios de backend de tu proyecto. La cadena de nombre del servicio backend correspondiente incluye el nombre y el espacio de nombres del servicio de GKE correspondiente:
gcloud compute backend-services list
Recupera el estado de salud del backend del servicio de backend:
gcloud compute backend-services get-health BACKEND_SERVICE_NAME
Si todos los backends están en mal estado, es posible que tu cortafuegos, Ingress o servicio estén mal configurados.
Si algunos back-ends no están en buen estado durante un breve periodo, puede que la causa sea la latencia de programación de la red.
Si algunos back-ends no aparecen en la lista de servicios de back-end, puede que se deba a la latencia de programación. Para comprobarlo, ejecuta el siguiente comando, donde
NEG_NAME
es el nombre del servicio de backend. (Los NEG y los servicios de backend tienen el mismo nombre):gcloud compute network-endpoint-groups list-network-endpoints NEG_NAME
Comprueba si todos los endpoints esperados están en el NEG.
Si tienes un número reducido de backends (por ejemplo, 1 pod) seleccionado por un balanceador de carga nativo de contenedor, te recomendamos que aumentes el número de réplicas y distribuyas los pods de backend en todas las zonas que abarca el clúster de GKE. De esta forma, se asegurará de que la infraestructura del balanceador de carga subyacente esté totalmente programada. De lo contrario, considera la posibilidad de restringir los pods de backend a una sola zona.
Si configuras una política de red para el endpoint, asegúrate de que se permita el tráfico de entrada desde la subred de solo proxy.
Lanzamiento detenido
- Síntomas
- El lanzamiento de una implementación actualizada se detiene y el número de réplicas actualizadas no coincide con el número de réplicas deseado.
- Posibles causas
Las comprobaciones del estado de la implementación están fallando. Puede que la imagen del contenedor sea incorrecta o que la comprobación del estado no se haya configurado correctamente. La sustitución gradual de pods espera hasta que el pod recién iniciado supere su puerta de disponibilidad de pods. Esto solo ocurre si el pod responde a las comprobaciones del estado del balanceador de carga. Si el pod no responde o si la comprobación del estado está mal configurada, no se pueden cumplir las condiciones de la puerta de disponibilidad y el lanzamiento no puede continuar.
Si usas
kubectl
1.13 o una versión posterior, puedes comprobar el estado de las puertas de preparación de un pod con el siguiente comando:kubectl get pod POD_NAME -o wide
Consulta la columna
READINESS GATES
.Esta columna no existe en
kubectl
1.12 ni en versiones anteriores. Un pod marcado como en estadoREADY
puede tener una comprobación de disponibilidad fallida. Para verificarlo, usa el siguiente comando:kubectl get pod POD_NAME -o yaml
Los readiness gates y su estado se muestran en el resultado.
- Resolución
Verifica que la imagen del contenedor de la especificación del pod de tu Deployment funcione correctamente y pueda responder a las comprobaciones de estado. Verifica que las comprobaciones de estado estén configuradas correctamente.
Errores del modo degradado
- Síntomas
A partir de la versión 1.29.2-gke.1643000 de GKE, es posible que aparezcan las siguientes advertencias en tu servicio en Explorador de registros cuando se actualicen los NEGs:
Entering degraded mode for NEG <service-namespace>/<service-name>-<neg-name>... due to sync err: endpoint has missing nodeName field
- Posibles causas
Estas advertencias indican que GKE ha detectado errores de configuración de endpoints durante una actualización de NEG basada en objetos
EndpointSlice
, lo que ha activado un proceso de cálculo más detallado llamado modo degradado. GKE sigue actualizando los NEGs de la mejor forma posible, ya sea corrigiendo la configuración incorrecta o excluyendo los endpoints no válidos de las actualizaciones de los NEGs.Algunos errores habituales son los siguientes:
endpoint has missing pod/nodeName field
endpoint corresponds to an non-existing pod/node
endpoint information for attach/detach operation is incorrect
- Resolución
Normalmente, estos eventos se deben a estados transitorios y se solucionan solos. Sin embargo, los eventos causados por errores de configuración en objetos
EndpointSlice
personalizados siguen sin resolverse. Para entender la configuración incorrecta, examina los objetosEndpointSlice
correspondientes al servicio:kubectl get endpointslice -l kubernetes.io/service-name=<service-name>
Valida cada endpoint en función del error del evento.
Para solucionar el problema, debe modificar manualmente los objetos
EndpointSlice
. La actualización hace que los NEGs se actualicen de nuevo. Una vez que se haya corregido la configuración incorrecta, el resultado será similar al siguiente:NEG <service-namespace>/<service-name>-<neg-name>... is no longer in degraded mode
Problemas conocidos
El balanceo de carga nativo de contenedores en GKE tiene los siguientes problemas conocidos:
Condición de carrera de la comprobación de preparación de NEG
En determinadas condiciones, las comprobaciones de disponibilidad pueden devolver un estado "false positive" antes de que la comprobación de estado de entrada informe de un estado correcto, lo que genera eventos de error como los siguientes en el objeto Ingress:
NEG is not attached to any BackendService with health checking. Marking condition "cloud.google.com/load-balancer-neg-ready" to True.
Síntomas
Este problema provoca que el balanceador de carga informe de un error 503
(failed_to_pick_backend
) al tráfico mientras GKE realiza la actualización continua de la carga de trabajo de la implementación.
Causas
Aunque el controlador NEG de GKE se basa en la información de la comprobación del estado de NEG de Compute Engine para informar de si el endpoint está en buen estado, ten en cuenta la siguiente secuencia de eventos:
- Se crea un nuevo pod a partir de una actualización continua.
- El controlador de NEG de GKE añade esta nueva dirección IP de Pod al grupo de puntos finales de red.
- El controlador NEG de GKE solicita el estado de salud del endpoint recién añadido.
- El servicio NEG de Compute Engine aún no tiene información sobre el estado y devuelve un estado vacío.
- El controlador NEG de GKE da por hecho que un estado vacío significa que no se ha configurado ninguna comprobación de estado y marca el pod como Ready.
- GKE elimina el Pod antiguo porque cree que el nuevo está listo para servir tráfico.
- Si el nuevo Pod es el único backend que queda para el balanceador de carga, este devuelve una respuesta
503 Service Unavailable
. - Una vez que el pod empiece a superar su comprobación de estado, el balanceador de carga empezará a devolver respuestas
200 OK
como se espera.
El controlador NEG de GKE no puede distinguir entre dos estados de comprobación del estado diferentes: missing-health-check-because-not-attached-to-backend y missing-health-check-because-health-check-is-not-yet-programmed.
Como el controlador de NEG no puede hacer esta distinción, el controlador de NEG de GKE debe asumir que, si ninguno de los endpoints del NEG tiene información de comprobación de estado, este NEG no debe pertenecer a ningún BackendService.
Aunque es poco probable que se dé esta situación, si tienes un número relativamente pequeño de pods (por ejemplo, 2) en comparación con el número de NEGs, aumentará el riesgo de que se produzca esta condición de carrera. Recuerde que las NEGs se crean para cada región, con una NEG por zona, lo que suele dar como resultado tres NEGs.
Por lo tanto, si hay un número relativamente mayor de pods, de forma que cada NEG siempre tenga varios pods antes de que empiece la actualización gradual, es muy poco probable que se active esta condición de carrera.
Soluciones:
La mejor forma de evitar esta condición de carrera (y, en última instancia, de evitar respuestas 503 Service Unavailable
durante las actualizaciones continuas) es tener más back-ends en el grupo de endpoints de red.
Asegúrate de que la estrategia de actualización continua esté configurada para que siempre se ejecute al menos un pod.
Por ejemplo, si solo se ejecutan 2 pods con normalidad, una configuración de ejemplo podría ser la siguiente:
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1
El ejemplo anterior es una sugerencia. Debe actualizar la estrategia en función de varios factores, como el número de réplicas.
Recolección de elementos no utilizados incompleta
GKE recoge los elementos no utilizados de los balanceadores de carga nativos de contenedores cada dos minutos. Si se elimina un clúster antes de que se eliminen por completo los equilibradores de carga, debes eliminar manualmente los NEG del equilibrador de carga.
Para ver los NEGs de tu proyecto, ejecuta el siguiente comando:
gcloud compute network-endpoint-groups list
En el resultado del comando, busca los NEGs correspondientes.
Para eliminar un NEG, ejecuta el siguiente comando y sustituye NEG_NAME
por el nombre del NEG:
gcloud compute network-endpoint-groups delete NEG_NAME
Alinear las implementaciones de cargas de trabajo con la propagación de endpoints
Cuando despliegas una carga de trabajo en tu clúster o actualizas una carga de trabajo, el balanceador de carga nativo de contenedor puede tardar más en propagar los nuevos endpoints que en finalizar el lanzamiento de la carga de trabajo. El Deployment de ejemplo que vas a desplegar en esta guía usa dos campos para alinear su lanzamiento con la propagación de los endpoints: terminationGracePeriodSeconds
y minReadySeconds
.
terminationGracePeriodSeconds
permite que el pod se cierre correctamente esperando a que finalicen las conexiones después de que se haya programado la eliminación de un pod.
minReadySeconds
añade un periodo de latencia después de que se cree un pod. Especificas el número mínimo de segundos en que debe estar un pod nuevo en el estado Ready
, sin que falle ninguno de sus contenedores, para que se considere que está disponible.
Debes configurar los valores minReadySeconds
y terminationGracePeriodSeconds
de tus cargas de trabajo en 60 segundos o más para asegurarte de que el servicio no se interrumpa debido a las implementaciones de cargas de trabajo.
terminationGracePeriodSeconds
está disponible en todas las especificaciones de Pod y minReadySeconds
está disponible en Deployments y DaemonSets.
Para obtener más información sobre cómo ajustar los lanzamientos, consulta RollingUpdateStrategy.
initialDelaySeconds
en el pod readinessProbe
no se respeta
Podrías esperar que el balanceador de carga nativo de contenedor respete la configuración initialDelaySeconds
del Pod readinessProbe
. Sin embargo, readinessProbe
se implementa mediante kubelet y la configuración initialDelaySeconds
controla la comprobación de estado de kubelet, no el balanceador de carga nativo de contenedor. El balanceo de carga nativo de contenedores tiene su propia comprobación de estado.