3 historias de accidentes de Kubernetes en producci贸n: anti-afinidad, cierre elegante, webhook


Nota perev. : Presentamos una mini-selecci贸n de autopsias sobre los problemas fatales que enfrentaron los ingenieros de diferentes compa帽铆as al operar la infraestructura basada en Kubernetes. Cada nota habla sobre el problema en s铆, sus causas y consecuencias y, por supuesto, sobre una soluci贸n que ayuda a evitar situaciones similares en el futuro.

Como sabes, aprender de la experiencia de otra persona es m谩s barato y, por lo tanto, deja que estas historias te ayuden a estar preparado para posibles sorpresas. Por cierto, en este sitio se publica una selecci贸n amplia y actualizada de enlaces a tales "historias de fallas" (seg煤n los datos de este repositorio de Git ).

No 1. C贸mo el p谩nico del n煤cleo bloque贸 un sitio


Original: luz de luna .

Entre el 18 y el 22 de enero, el sitio web de Moonlight y API experimentaron fallas intermitentes. Todo comenz贸 con errores aleatorios de la API y termin贸 con un apagado completo. Los problemas se resolvieron y la aplicaci贸n volvi贸 a la normalidad.

Informaci贸n general


Moonlight utiliza un software conocido como Kubernetes. Kubernetes ejecuta aplicaciones en grupos de servidores. Estos servidores se llaman nodos. Las copias de la aplicaci贸n que se ejecutan en el nodo se denominan pods. Kubernetes tiene un planificador que determina din谩micamente qu茅 pods en qu茅 nodos deber铆an funcionar.

Cronograma


Los primeros errores del viernes estuvieron relacionados con problemas para conectarse a la base de datos Redis. Moonlight API usa Redis para verificar las sesiones para cada solicitud autenticada. Nuestra herramienta de monitoreo Kubernetes ha notificado que algunos nodos y pods no responden. Al mismo tiempo, Google Cloud inform贸 un mal funcionamiento de los servicios de red y decidimos que eran la causa de nuestros problemas.

A medida que disminu铆a el tr谩fico el fin de semana, los errores parec铆an resolverse en su mayor parte. Sin embargo, el martes por la ma帽ana, el sitio de Moonlight cay贸 y el tr谩fico externo no lleg贸 al cl煤ster. Encontramos a otra persona en Twitter con s铆ntomas similares y decidimos que el alojamiento de Google ten铆a una falla en la red. Nos contactamos con el servicio de asistencia de Google Cloud, que r谩pidamente remiti贸 el problema al equipo de asistencia t茅cnica.

El equipo de soporte t茅cnico de Google revel贸 algunos patrones en el comportamiento de los nodos en nuestro cl煤ster de Kubernetes. La utilizaci贸n de CPU de los nodos individuales alcanz贸 el 100%, despu茅s de lo cual se produjo el p谩nico del kernel en la m谩quina virtual y se bloque贸.

Razones


El ciclo que caus贸 la falla fue el siguiente:

  • El planificador de Kubernetes aloj贸 varios pods con alto consumo de CPU en el mismo nodo.
  • Los pods se comieron todos los recursos de la CPU en el nodo.
  • Luego vino el p谩nico del kernel, que condujo a un per铆odo de inactividad durante el cual el nodo no respondi贸 al planificador.
  • El programador movi贸 todas las c谩psulas ca铆das a un nuevo nodo, y el proceso se repiti贸, exacerbando la situaci贸n general.

Inicialmente, el error ocurri贸 en el pod de Redis, pero al final todos los pod que trabajan con tr谩fico cayeron, lo que condujo a un apagado completo. Los retrasos exponenciales durante la reprogramaci贸n han llevado a per铆odos m谩s largos de inactividad.

Soluci贸n


Pudimos restaurar el sitio agregando reglas anti-afinidad a todas las implementaciones principales. Distribuyen autom谩ticamente los pods sobre los nodos, aumentando la tolerancia a fallas y el rendimiento.

Kubernetes est谩 dise帽ado como un sistema host tolerante a fallas. Moonlight utiliza tres nodos en diferentes servidores para mayor estabilidad, y ejecutamos tres copias de cada aplicaci贸n que sirve el tr谩fico. La idea es tener una copia en cada nodo. En este caso, incluso una falla de dos nodos no conducir谩 al tiempo de inactividad. Sin embargo, Kubernetes a veces coloc贸 las tres c谩psulas con el sitio en el mismo nodo, creando as铆 un cuello de botella en el sistema. Al mismo tiempo, otras aplicaciones que demandaban potencia de procesador (es decir, representaci贸n del lado del servidor) estaban en el mismo nodo, y no en uno separado.

Se requiere un cl煤ster de Kubernetes correctamente configurado y que funcione correctamente para hacer frente a largos per铆odos de alta carga de CPU y colocar pods de manera que se maximice el uso de los recursos disponibles. Continuamos trabajando con el soporte de Google Cloud para identificar y abordar la causa ra铆z del kernel panic en los servidores.

Conclusi贸n


Las reglas anti-afinidad le permiten hacer que las aplicaciones que funcionan con tr谩fico externo sean m谩s tolerantes a fallas. Si tiene un servicio similar en Kubernetes, considere agregarlos.

Continuamos trabajando con los chicos de Google para encontrar y eliminar la causa de fallas en el n煤cleo del sistema operativo en los nodos.

No 2. El secreto "sucio" de Kubernetes y el punto final de Ingress


Original: Phil Pearl de Ravelin .

La elegancia est谩 sobrevalorada


Nosotros en Ravelin migramos a Kubernetes (en GKE). El proceso ha sido muy exitoso. Nuestros presupuestos de interrupci贸n de pods est谩n tan completos como siempre, los estados son verdaderamente majestuosos (un juego de palabras dif铆cil de traducir: "nuestros conjuntos con estado son muy majestuosos" - aprox. Transl.) , Y el reemplazo deslizante de los nodos funciona como un reloj.

La pieza final del rompecabezas es mover la capa API de m谩quinas virtuales antiguas al cl煤ster de Kubernetes. Para hacer esto, necesitamos configurar Ingress para que la API sea accesible desde el mundo exterior.

Al principio, la tarea parec铆a simple. Simplemente definimos el controlador Ingress, modificamos el Terraform para obtener un cierto n煤mero de direcciones IP, y Google se encarga de casi todo lo dem谩s. Y todo esto funcionar谩 como por arte de magia. Clase!

Sin embargo, con el tiempo, comenzaron a notar que las pruebas de integraci贸n reciben peri贸dicamente errores 502. A partir de esto, nuestro viaje comenz贸. Sin embargo, le ahorrar茅 tiempo e ir茅 directamente a las conclusiones.

Cierre elegante


Todo el mundo habla de un cierre elegante ("elegante", cierre gradual). Pero realmente no debes confiar en 茅l en Kubernetes. O al menos no deber铆a ser el cierre elegante que absorbi贸 con la leche de su madre . En el mundo de Kubernetes, este nivel de "elegancia" es innecesario y amenaza con serios problemas.

Mundo perfecto


As铆 es como, en la vista mayoritaria, el pod se elimina del servicio o del equilibrador de carga en Kubernetes:

  1. El controlador de replicaci贸n decide eliminar el pod.
  2. El pod de punto final se elimina del servicio o equilibrador de carga. Ya no llega nuevo tr谩fico al pod.
  3. Se llama a un gancho previo a la parada, o el pod recibe una se帽al SIGTERM.
  4. El pod "con gracia" est谩 desconectado. Deja de aceptar conexiones entrantes.
  5. La desconexi贸n "agraciada" se completa y el pod se destruye despu茅s de que todas sus conexiones existentes se detienen o finalizan.

Desafortunadamente, la realidad es completamente diferente.

Mundo real


La mayor parte de la documentaci贸n sugiere que todo sucede de manera un poco diferente, pero no escriben expl铆citamente sobre esto en ning煤n lado. El principal problema es que el paso 3 no sigue al paso 2. Se producen simult谩neamente. En los servicios ordinarios, la eliminaci贸n de puntos finales es tan r谩pida que la probabilidad de encontrar problemas es extremadamente baja. Sin embargo, con Ingresss, todo es diferente: generalmente responden mucho m谩s lentamente, por lo que el problema se vuelve obvio. Pod puede obtener SIGTERM mucho antes de que los cambios en los puntos finales entren en Ingress.

Como resultado, un apagado correcto no es lo que se requiere de un pod. Recibir谩 nuevas conexiones y debe continuar proces谩ndolas, de lo contrario, los clientes comenzar谩n a recibir los errores n煤mero 500 y toda la maravillosa historia sobre implementaciones y escalas sin complicaciones comenzar谩 a desmoronarse.

Esto es lo que realmente sucede:

  1. El controlador de replicaci贸n decide eliminar el pod.
  2. El pod de punto final se elimina del servicio o equilibrador de carga. En el caso de Ingresss, esto puede llevar alg煤n tiempo, y el nuevo tr谩fico continuar谩 fluyendo hacia el pod.
  3. Se llama a un gancho previo a la parada, o el pod recibe una se帽al SIGTERM.
  4. En gran medida, el pod debe ignorar esto, continuar trabajando y mantener nuevas conexiones. Si es posible, deber铆a indicarles a los clientes que ser铆a bueno cambiarse a otro lugar. Por ejemplo, en el caso de HTTP, puede enviar Connection: close en los encabezados de respuesta.
  5. La c谩psula sale solo cuando el per铆odo de espera "elegante" expira y SIGKILL la mata.
  6. Aseg煤rese de que este per铆odo sea m谩s largo que el tiempo que lleva reprogramar el equilibrador de carga.

Si se trata de un c贸digo de terceros y no puede cambiar su comportamiento, entonces lo mejor que puede hacer es agregar un gancho previo a la detenci贸n que solo duerma durante un per铆odo "elegante", de modo que el pod contin煤e funcionando como si nada sucedi贸

N煤mero 3. C贸mo un webhook simple caus贸 una falla del cl煤ster


Original: Jetstack .

Jetstack ofrece a sus clientes plataformas multiempresa en Kubernetes. A veces hay requisitos especiales que no podemos satisfacer con la configuraci贸n est谩ndar de Kubernetes. Para implementarlos, recientemente comenzamos a usar el Open Policy Agent (escribimos sobre el proyecto con m谩s detalle en esta revisi贸n , aprox. Transl.) Como controlador de acceso para implementar pol铆ticas especiales.

Este art铆culo describe el error causado por esta integraci贸n mal configurada.

Incidente


Nos dedicamos a actualizar el asistente para el cl煤ster de desarrollo, en el que varios equipos probaron sus aplicaciones durante la jornada laboral. Era un cl煤ster regional en la zona europa-oeste1 en Google Kubernetes Engine (GKE).

Se advirti贸 a los comandos que se estaba realizando una actualizaci贸n, sin tiempo de inactividad esperado. Ese mismo d铆a, ya hicimos una actualizaci贸n similar a otro entorno de preproducci贸n.

Comenzamos la actualizaci贸n usando nuestra tuber铆a GKE Terraform. La actualizaci贸n del asistente no se complet贸 hasta que expir贸 el tiempo de espera de Terraform, que configuramos durante 20 minutos. Esta fue la primera llamada de atenci贸n de que algo sali贸 mal, aunque en la consola GKE el cl煤ster todav铆a figuraba como "actualizaci贸n".

Reiniciar la tuber铆a condujo al siguiente error

 google_container_cluster.cluster: Error waiting for updating GKE master version: All cluster resources were brought up, but the cluster API is reporting that: component "kube-apiserver" from endpoint "gke-..." is unhealthy 

Esta vez, la conexi贸n con el servidor API comenz贸 a interrumpirse peri贸dicamente y los equipos no pudieron implementar sus aplicaciones.

Mientras est谩bamos tratando de entender lo que estaba sucediendo, todos los nodos comenzaron a destruirse y recrearse en un ciclo sin fin. Esto ha llevado a una denegaci贸n indiscriminada de servicio para todos nuestros clientes.

Establecemos la causa ra铆z de la falla


Con el soporte de Google, pudimos determinar la secuencia de eventos que condujeron a la falla:

  1. GKE complet贸 la actualizaci贸n en una instancia del asistente y comenz贸 a aceptar todo el tr谩fico al servidor API en 茅l a medida que se actualizaban los siguientes asistentes.
  2. Durante la actualizaci贸n de la segunda instancia del asistente, el servidor API no pudo ejecutar PostStartHook para registrar la CA.
  3. Durante la ejecuci贸n de este enlace, el servidor API intent贸 actualizar ConfigMap llamado extension-apiserver-authentication en kube-system . No fue posible hacer esto porque el backend para el webhook de comprobaci贸n de Open Policy Agent (OPA) que configuramos no respondi贸.
  4. Para que el asistente pase una comprobaci贸n de estado, esta operaci贸n debe completarse correctamente. Como esto no sucedi贸, el segundo maestro ingres贸 al ciclo de emergencia y detuvo la actualizaci贸n.

El resultado fueron bloqueos peri贸dicos de la API, debido a que los kubelets no pudieron informar el estado del nodo. A su vez, esto condujo al hecho de que el mecanismo para la restauraci贸n autom谩tica de los nodos GKE (reparaci贸n autom谩tica de nodos ) comenz贸 a reiniciar los nodos. Esta caracter铆stica se describe en detalle en la documentaci贸n :

Un estado no saludable puede significar: Dentro de un tiempo determinado (aproximadamente 10 minutos), el nodo no da ning煤n estado en absoluto.

Soluci贸n


Cuando descubrimos que el recurso ValidatingAdmissionWebhook estaba causando un acceso intermitente al servidor API, lo eliminamos y restauramos el cl煤ster para que funcione.

Desde entonces, han configurado ValidatingAdmissionWebhook para OPA para monitorear solo aquellos espacios de nombres donde la pol铆tica es aplicable y a los que los equipos de desarrollo tienen acceso. Tambi茅n limitamos el webhook a Ingress and Service , los 煤nicos con los que funciona nuestra pol铆tica.

Desde que implementamos la OPA por primera vez, la documentaci贸n se ha actualizado para reflejar este cambio.

Tambi茅n agregamos una prueba de vida para asegurar que la OPA se reinicie en caso de que no est茅 disponible (e hicimos las modificaciones apropiadas a la documentaci贸n).

Tambi茅n consideramos deshabilitar el mecanismo de recuperaci贸n autom谩tica para los nodos GKE, pero a煤n as铆 decidimos abandonar esta idea.

Resumen


Si habilitamos las alertas de tiempo de respuesta del servidor API, inicialmente podr铆amos notar su aumento global para todas las solicitudes CREATE y UPDATE despu茅s de implementar el webhook para OPA.

Esto subraya la importancia de configurar pruebas para todas las cargas de trabajo. Mirando hacia atr谩s, podemos decir que el despliegue de OPA fue tan enga帽osamente simple que ni siquiera nos involucramos en la tabla de Helm (aunque deber铆a). El cuadro realiza una serie de ajustes m谩s all谩 de la configuraci贸n b谩sica descrita en el manual, incluida la configuraci贸n de livenessProbe para contenedores con un controlador de admisi贸n.

No fuimos los primeros en encontrar este problema: el problema aguas arriba permanece abierto. La funcionalidad en este asunto puede mejorarse claramente (y haremos un seguimiento de esto).

PD del traductor


Lea tambi茅n en nuestro blog:

Source: https://habr.com/ru/post/475026/


All Articles