← Volver al blog
orders-api, con sus pods NotReady, separado de un PostgreSQL de Azure que está sano por una regla del NSG de los nodos que deniega el puerto 5432

Cómo pruebo a Kobi en Azure: rompo algo a propósito y evalúo lo que responde

Antes de que Kobi lea nada de tu nube, tiene que encontrar la causa cuando el clúster dice que todo está bien. Montamos un laboratorio en Azure, rompemos cosas como se rompen en la vida real, le hacemos a Kobi la pregunta que haría un operador y evaluamos cada respuesta con criterios escritos antes de empezar. Este es el método, con lo que costó cada prueba.

Los incidentes más difíciles de explicar son los que el clúster no ve. Los pods están Ready, la base de datos aparece como Available en Azure y la tienda devuelve 503. La causa está en una regla de red, en un parámetro o en un permiso, y nada de eso vive dentro de Kubernetes.

En la 2.3 conté que estamos conectando Kobi con AWS, Azure y GCP para que pueda seguir la causa fuera del clúster. Antes de dejarle leer la nube de nadie, necesito saber si la encuentra, y para eso uso incidentes concretos y la pregunta que haría alguien a las tres de la mañana.

El método tiene un nombre poco glamuroso: el examen se escribe antes de romper nada. Monto el fallo en un laboratorio de Azure tal como pasaría de verdad. Antes de preguntar, escribo qué tiene que encontrar Kobi y qué trampas tiene que evitar. Después le hago la pregunta del operador, sin pistas, y evalúo la respuesta contra esa lista. Un arreglo solo cuenta cuando la siguiente vuelta lo demuestra en el chat real.

Lo que hay debajo, en cinco líneas:

  • El laboratorio rompe Azure como se rompe en la vida real, con pistas falsas del mismo día.
  • Lo que Kobi sabe de Azure viaja en cuatro capas, y la que más pesa llega dentro del resultado de una herramienta.
  • La pregunta es la del operador, por ejemplo «La tienda no carga, ¿qué pasa?».
  • Cada respuesta se evalúa con criterios escritos antes, créditos incluidos.
  • El conector solo puede leer, y eso no depende de que el modelo se porte bien.

El laboratorio

Son dos clústeres de AKS que forman una tienda. En kubeshop-front corre la web. En kubeshop-back corren orders-api y catalog-api, que leen de un PostgreSQL flexible de Azure, fuera del clúster y en otra región.

Cada fallo lo inyecta un agente como lo haría una persona: un parámetro del servidor, un ALTER ROLE dentro de la base, una regla en un NSG. Y casi siempre hay ruido alrededor: cambios anteriores en el activity log, un reinicio, un corte que ya se resolvió.

Lo que se rompeLo que ve el clústerLa trampa
statement_timeout = 50: alguien quería 50 segundos y son milisegundosorders-api da 500, catalog-api sigue en 200Reiniciar o inventar el valor anterior
La contraseña del rol, cambiada con ALTER ROLE dentro de la baseTodo bien hasta el siguiente reinicioEl rollback y los cambios del día
Una regla de salida en el NSG de los nodosPods NotReady, la base AvailableCulpar a la base
Un permiso revocado con REVOKE500 en unos 30 msSeñalar a alguien sin registro
La base en otra regiónUnos 150 ms por páginaCulpar a la región de toda la diferencia
Una regla de entrada en el NSGPods Ready sin tráficoFiarse de las sondas sanas del balanceador

Hasta ahora todo se ha probado contra PostgreSQL. Azure SQL y Service Bus tienen escenarios preparados, y el resto de recursos que Kobi reconoce todavía no se ha probado.

El recorrido de una pregunta

Antes de los resultados, el arnés: lo que rodea al modelo para que una pregunta llegue a la causa. Un backend del clúster deja de alcanzar su base de datos en Azure, y el operador pregunta qué pasa. Las flechas son las llamadas de Kobi, en orden.

TU CLÚSTER KUBEBOLT AZURE · TU SUSCRIPCIÓN orders-api pod · shop-backend cannot reach database shop-db Service ExternalName pg-kubeshop-lab. postgres.database. azure.com operador Kobi Haiku 5.5 pasa a Sonnet 5.5 al salir a la nube B C get_external_ connections azure-postgres empieza por monitor, postgres, resourcehealth A Gateway MCP de KubeBolt D 48 comandos suscripción fijada sin datos ni secretos sin logins de la base KQL sin saltos auditado por org. textos propios Azure MCP Server solo lectura · sin caché ni telemetría junto a la API, en instalación propia Azure Resource Manager Activity log quién y cuándo cambios de red Métricas is_db_alive cada 5 minutos Resource Health disponible o degradado PostgreSQL SKU, versión y región 1 logs 2 host 3 clasifica el método 4 router 5 filtro 6 lectura SP de solo lectura 7 respuesta TU CLÚSTER KUBEBOLT AZURE · TU SUSCRIPCIÓN orders-api pod · shop-backend cannot reach database shop-db Service ExternalName pg-kubeshop-lab. postgres.database. azure.com operador Kobi Haiku 5.5 pasa a Sonnet 5.5 al salir a la nube B C get_external_ connections azure-postgres empieza por monitor, postgres, resourcehealth A Gateway MCP de KubeBolt D 48 comandos suscripción fijada sin datos ni secretos sin logins de la base KQL sin saltos auditado por org. textos propios Azure MCP Server solo lectura · sin caché ni telemetría junto a la API, en instalación propia Azure Resource Manager Activity log quién y cuándo cambios de red Métricas is_db_alive cada 5 minutos Resource Health disponible o degradado PostgreSQL SKU, versión y región 1 2 3 4 5 6 7
  1. Logs del backend. get_pod_logs devuelve los tramos de error, con su inicio y su fin.
  2. La dirección. El Service o el entorno del pod dan el host de la base de datos.
  3. La clasificación. get_external_connections reconoce el recurso por su dominio y devuelve el método.
  4. La herramienta de Azure. Kobi llama a monitor, postgres o resourcehealth.
  5. El filtro. El gateway comprueba el comando, fija la suscripción y quita lo que no debe salir.
  6. La lectura. El servidor MCP de Azure consulta con una identidad que solo puede leer.
  7. La respuesta. Causa, quién y cuándo, y la duración medida en los logs.
Las llamadas 1 a 4 las hace Kobi con sus herramientas de KubeBolt. La 5 y la 6 cruzan a Azure, siempre por el gateway, que puede rechazar una llamada antes de que salga. Las letras A a D son las cuatro capas de lo que Kobi sabe de Azure.

Las cuatro capas

La forma obvia de enseñarle a Kobi cada recurso es una skill por recurso. Las pruebas la descartaron: Haiku no siempre carga una skill (una de las nuestras no la cargó ni una vez), pero siempre lee el resultado de una herramienta. Así que lo que Kobi sabe de Azure llega en cuatro momentos distintos, y solo el primero depende del recurso concreto.

La clasificación de la dirección

Cuándo llega
Cada vez que Kobi sigue una dirección fuera del clúster, dentro del resultado de get_external_connections.
Qué lleva
El tipo de recurso (15 hoy, por su dominio), si la organización tiene el conector, por qué herramientas empezar y cómo investigar ese tipo.
«¿Está caído? Empieza por monitor_activitylog_list con el nombre del servidor y top 20: paradas y arranques, failover, cambios de firewall y red, quién y cuándo. No necesita grupo de recursos.»

La guía de dependencias externas

Cuándo llega
Cuando Kobi sospecha de algo fuera del clúster y la carga.
Qué lleva
El método general: seguir la clasificación, usar un conector solo si está activo, leer el activity log del recurso correcto.
«Las sondas de un balanceador entran por su propia regla (en Azure, AzureLoadBalancer): unos backends sanos no demuestran que el tráfico del cliente pase.»

La pista del conector

Cuándo llega
Solo si la organización tiene el conector activo.
Qué lleva
Cómo se llama una herramienta de Azure, que la suscripción la fija KubeBolt y cómo encontrar un grupo de recursos sin adivinarlo.
«Para una base de datos que dejó de responder, empieza por ese activity log. Ningún comando de configuración dice si el servidor está corriendo.»

La descripción de cada comando

Cuándo llega
Siempre, en cada herramienta que Kobi ve.
Qué lleva
Qué devuelve el comando y qué no, escrito por nosotros en lugar del texto de Microsoft.
«postgres_server_config_get: versión, SKU, región, almacenamiento, retención de backups. No dice si está corriendo, ni su red ni su firewall.»

Las citas son del código, traducidas.

El coste también lo decide el arnés. Kobi trabaja con Haiku 5.5 y pasa a Sonnet 5.5 cuando tiene que salir a la nube. Al principio escalaba con solo cargar la guía, y el lado del front costaba unos 49 créditos por prueba sin tocar Azure. Ahora escala según lo que encuentra la clasificación, y ese lado cuesta 3 o 4.

El examen se escribe antes

Los criterios cambian con cada escenario, pero hay una base común. La causa, con el valor y la hora. Quién hizo el cambio, si hay un registro que lo diga. El remedio en la capa correcta: si la culpa es de una regla del NSG, reiniciar los pods no cuenta. Las trampas del escenario. Nada inventado. Y cuántas llamadas y créditos costó.

Escribirlo antes importa porque una respuesta de Kobi casi siempre suena bien. Con la lista delante se ve lo que le falta.

El primer escenario de la tabla lo pasamos dos veces, con 17 días de diferencia. El 12 de octubre Kobi encontró la causa, el autor y la hora en 57 segundos, siguiendo el error desde el clúster del front hasta el del back y de ahí a Azure. Esta es la comparación con el 25 de septiembre, contando los arreglos de ese mismo día:

Criterio25 sep12 oct, con los arreglos
Causa: parámetro, valor y horaSíSí, y los tres cambios del día
Quién hizo el cambioNo lo nombróLo nombra, del activity log
Región del servidorInventada, la del clústerNo afirma ninguna
Valor al que volver250–500 ms, como si fuera el anteriorLo encuentra: «Déjalo en 0»

La prueba entera costó 100 créditos (unos 0,50 dólares) en la primera vuelta del 12 de octubre, y 90 con los arreglos.

El valor anterior estaba en el activity log de Azure, pero no cabía en lo que una herramienta puede entregar al modelo:

32 KB: lo que una herramienta entrega al modelo
90 días, top 50, en bruto 93 KB
90 días, una fila por operación 16 KB
90 días, solo ese parámetro 1,7 KB
Medido contra el servidor del laboratorio. Azure escribe cada operación como varias entradas; KubeBolt las une en una fila con quién, cuándo, el estado final y lo que se escribió, y deja filtrar por subrecurso.

Una respuesta de un agente casi siempre suena bien. Por eso el examen se escribe antes de romper nada.

Un caso entero: la regla que no se ve desde dentro

Alguien añade una regla al NSG de la red de los nodos de kubeshop-back: denegar la salida TCP al puerto 5432 de la base. La base sigue Available y su firewall, intacto. La sonda de readiness del backend abre una conexión a la base, expira, y los cuatro pods quedan NotReady. La tienda entera da 503, y desde la base no se ve nada porque el tráfico nunca le llega.

La pregunta fue «La tienda no carga, ¿qué pasa?».

En las dos vueltas, Kobi descartó la base con buen criterio. La diferencia está en cómo gastó sus cinco llamadas a Azure:

1.ª vuelta 12 oct · 2 preguntas · 73 créditos
  1. 1 Activity log de la base Vacío: la base no cambió
  2. 2 Métricas de la base La serie acaba antes del fallo
  3. 3 Lista de grupos La cuenta entera
  4. 4 Grupo de la base La base ya era conocida
  5. 5 Grupo del túnel Una pista falsa

Se queda en «algo en el camino de red». La regla llega con una segunda pregunta.

2.ª vuelta 13 oct · 1 pregunta · 55 créditos
Ya en la clasificación. El grupo de la red del clúster (MC_…), leído de las etiquetas de los nodos. No es una llamada.
  1. 1 Activity log de la base Vacío otra vez
  2. 2 Métricas de la base Viva en las 13 muestras
  3. 3 Grupo MC_… de los nodos La red del clúster
  4. 4 Activity log del NSG La regla, su autor y su hora
  5. 5 Sin usar

La regla en la primera respuesta, con sus dos escrituras y el borrado entre ellas.

Las llamadas a Azure de la primera respuesta del back, en orden. El tope es cinco.

En la primera vuelta, Kobi no sabía dónde está la red de su propio clúster, aunque los nodos lo dicen en sus etiquetas, y listó la cuenta para encontrarla. El arreglo no fue darle más llamadas: la clasificación entrega ahora ese grupo de red cuando Kobi sigue una dirección hacia Azure, y la guía cubre las dos direcciones del tráfico. Con la regla delante, Kobi propuso borrarla y confirmarlo con quien la escribió, y explicó por qué los pods seguían en Running: leyó el código del servidor, donde la readiness toca la base y la liveness no.

Kobi encuentra en Azure la regla del NSG de los nodos que bloquea la salida hacia PostgreSQL, con la base de datos sana
La respuesta de Kobi en el laboratorio, resumida: la base está sana y la causa está en la red del propio clúster.

El 10 de octubre habíamos probado la otra dirección, una regla que corta la entrada desde Internet hacia el balanceador. Acabó en un ir y venir entre los dos clústeres, con Haiku y con Sonnet, y nadie leyó el log del NSG. Con el mismo arreglo, la regla, su autor y su hora salieron en la primera respuesta.

Ese caso deja una idea que vale fuera del laboratorio: Ready no quiere decir alcanzable. La readiness la hace el kubelet desde el propio nodo, y las sondas del balanceador entran por una regla de Azure reservada para ellas. Ninguna cruza la regla nueva, así que dentro del clúster todo sigue en verde y la única señal es que los logs se callan.

Solo lectura por construcción

La última capa del arnés no le pide nada al modelo. Son reglas que el gateway de KubeBolt aplica antes de que una llamada salga hacia Azure:

comandos de Azure que el gateway deja pasar
48
que puedan escribir
0
tipos de recurso que Kobi reconoce por su dirección
15
  • Solo lectura, dos vecesEl servidor de Azure arranca en modo de solo lectura, y el gateway rechaza además cualquier comando cuyo nombre termine en un verbo de escritura.
  • La suscripción, fijadaCada llamada va a la suscripción del conector. Un identificador que intente salir de ella se rechaza.
  • Ni datos ni secretosValores de secretos, consultas a la base, blobs de Storage e items de Cosmos quedan fuera, aunque Microsoft los marque como lectura.
  • Sin entrar en la baseEl usuario y la contraseña de la base se quitan de cada petición. KubeBolt trabaja a nivel de servidor.
  • KQL sin saltosUna consulta no puede ir a otro workspace ni al Resource Graph.
  • Una identidad que solo leeUn service principal con roles de lectura: Reader, Monitoring Reader y Log Analytics Reader.
  • Sin memoriaEl servidor escucha solo en local, no manda telemetría y no guarda caché: «¿ya se recuperó?» nunca lee una respuesta vieja.
  • Por organizaciónEl conector se activa por organización, y cada llamada queda en su auditoría.

Cuando la causa está en Azure, Kobi te da el comando para arreglarla, pero no lo ejecuta.

Lo que todavía falla

La lista de huecos que sale de estas pruebas tiene bastantes más entradas de las que cuento aquí, unas resueltas y otras abiertas. Te cuento una de las que menos me preocupan.

Con el permiso revocado, Kobi dijo bien que nadie puede saber quién lo revocó, porque un REVOKE no pasa por Azure y el servidor del laboratorio no guarda sus sentencias. Pero luego propuso como «contacto más probable» al autor de la regla de red de una hora antes, por una coincidencia que además no era cierta. La regla que proponemos es corta: quién hizo un cambio solo se sabe por el registro de ese cambio.

Lo que todavía no es

Los conectores están en desarrollo y no tienen fecha. Azure es donde probamos primero. Hoy el conector funciona como un servidor junto a la API, pensado para instalaciones propias, y el modo para KubeBolt Cloud, con la identidad de cada organización, está diseñado y sin construir.

Lo que queda

Un agente que investiga incidentes es tan bueno como los incidentes que le rompes a propósito. El método es corto de contar: rompo algo como se rompe de verdad y le hago a Kobi la pregunta de un operador. Lo que decide si la respuesta vale es la lista que escribí antes de empezar, con los créditos que costó pasarla.

Cuando los conectores salgan, saldrán con este laboratorio detrás y con cada escenario que añadamos hasta entonces.