Lab práctico · Semana 9: Fiabilidad y operaciones — Well-Architected, alta disponibilidad, DR, SRE y observabilidad
Observabilidad y SLO de un servicio en Cloud Run
Qué vas a construir
Un servicio pequeño en Cloud Run que responde bien o con error según la ruta. Sobre él montarás la observabilidad de un servicio real: un uptime check desde varias regiones, un SLO de disponibilidad con su alerta por burn rate, logs estructurados y una métrica basada en logs. Al final provocarás errores y verás cómo se consume el presupuesto de errores.
flowchart LR
U["Uptime check (3+ regiones)"] --> CR["Cloud Run: slo-demo"]
T["Tu tráfico (bucle curl)"] --> CR
CR -->|"logs JSON"| LOG["Cloud Logging"]
LOG -->|"log-based metric"| MON["Cloud Monitoring"]
CR -->|"métricas de peticiones"| MON
MON --> SLO["SLO 99 % + alerta burn rate"]
SLO --> MAIL["Notificación por correo"]
Antes de empezar
- Lab 1 hecho (proyecto con facturación y alerta de presupuesto). Usa un proyecto dedicado, por ejemplo
pca-lab-18. - Abre Cloud Shell y define las variables:
export PROJECT_ID=$(gcloud config get-value project)
export REGION=europe-southwest1
export SERVICE=slo-demo
gcloud config set run/region $REGION
- Habilita las APIs necesarias (Cloud Run, Cloud Build y Artifact Registry para construir desde código, Monitoring y Logging):
gcloud services enable run.googleapis.com cloudbuild.googleapis.com \
artifactregistry.googleapis.com monitoring.googleapis.com logging.googleapis.com
Coste: Cloud Run escala a cero y el tráfico del lab es mínimo; el uptime check hace unas pocas miles de ejecuciones (el primer millón por proyecto y mes es gratis, septiembre de 2026). El build consume unos minutos de Cloud Build (2.500 gratis al mes por cuenta de facturación).
Paso 1: crea la aplicación
Una aplicación mínima en Python, sin dependencias externas. Escribe logs estructurados: si imprimes una línea JSON por la salida estándar, Cloud Run la convierte en una entrada de Cloud Logging con su severity y sus campos en jsonPayload. La ruta /error devuelve un 500 para simular fallos.
mkdir -p ~/slo-demo && cd ~/slo-demo
cat > main.py <<'EOF'
import json, os, random
from http.server import BaseHTTPRequestHandler, HTTPServer
def log(severity, message, **campos):
print(json.dumps({"severity": severity, "message": message, **campos}), flush=True)
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path.startswith("/error"):
log("ERROR", "Fallo simulado en el pago", ruta=self.path, pedido=random.randint(1000, 9999))
self.send_response(500)
body = b"error simulado\n"
else:
log("INFO", "Peticion atendida", ruta=self.path)
self.send_response(200)
body = b"ok\n"
self.send_header("Content-Type", "text/plain")
self.end_headers()
self.wfile.write(body)
def log_message(self, *args):
pass # evitamos el log por defecto (no estructurado)
HTTPServer(("", int(os.environ.get("PORT", 8080))), Handler).serve_forever()
EOF
cat > Dockerfile <<'EOF'
FROM python:3.12-slim
WORKDIR /app
COPY main.py .
CMD ["python", "main.py"]
EOF
Paso 2: despliega en Cloud Run
--source . sube el código, lo construye con Cloud Build usando el Dockerfile y guarda la imagen en Artifact Registry (te pedirá confirmar la creación del repositorio cloud-run-source-deploy: responde Y).
gcloud run deploy $SERVICE --source . --region $REGION \
--allow-unauthenticated --max-instances 2
--allow-unauthenticated hace el servicio público para que el uptime check pueda llamarlo sin credenciales. Si tu proyecto pertenece a una organización con la política de domain restricted sharing, este paso fallará; en ese caso despliega sin ese parámetro y en el paso 3 marca la opción de autenticación del uptime check (las comprobaciones de disponibilidad pueden autenticarse contra Cloud Run con un agente de servicio).
Guarda la URL y pruébala:
export URL=$(gcloud run services describe $SERVICE --region $REGION --format='value(status.url)')
export HOST=${URL#https://}
curl -s $URL/
curl -s -o /dev/null -w "%{http_code}\n" $URL/error
Debes ver ok y después 500.
Paso 3: uptime check
El uptime check comprueba desde fuera (al menos 3 regiones del mundo) que el servicio responde. Es tu vista «como la ve el usuario».
gcloud monitoring uptime create "slo-demo-uptime" \
--resource-type=uptime-url \
--resource-labels=host=$HOST,project_id=$PROJECT_ID \
--protocol=https --path=/ --period=5
Por consola: Monitoring > Uptime checks > Create uptime check, protocolo HTTPS, tipo de recurso URL, host del servicio, frecuencia 5 minutos.
En unos minutos, en Monitoring > Uptime checks verás las comprobaciones en verde desde varias regiones.
Paso 4: genera tráfico
El SLO necesita peticiones. Lanza en Cloud Shell un bucle con tráfico mayoritariamente bueno (déjalo corriendo en una pestaña aparte con el botón + de Cloud Shell; ahí tendrás que volver a exportar URL):
for i in $(seq 1 600); do curl -s -o /dev/null $URL/; sleep 1; done
Paso 5: crea el servicio y el SLO
Cloud Monitoring reconoce los servicios de Cloud Run como candidatos.
- Ve a Monitoring > SLOs y pulsa Define service.
- Elige el servicio de Cloud Run
slo-demoy guárdalo. - Dentro del servicio, pulsa Create SLO.
- SLI: elige Availability y evaluación Request-based (proporción de peticiones correctas sobre el total). Si la consola no ofrece Availability para tu servicio, elige Other y define un SLI de tipo request-based con la métrica
run.googleapis.com/request_count, contando como buenas las que tienenresponse_code_class = "2xx". - SLO: periodo de cumplimiento Rolling, 7 días; objetivo 99 %. Es un objetivo bajo a propósito para que el efecto del laboratorio sea visible.
- Guárdalo con el nombre
Disponibilidad 99 %.
Piensa en el presupuesto: con un 99 % a 7 días, puedes fallar el 1 % de las peticiones del periodo.
Paso 6: alerta por burn rate
- En el SLO, pulsa Create SLO alert.
- Lookback duration: 60 minutos. Burn rate threshold: 10. Es la alerta de fast burn que recomienda la documentación (umbral 10 veces la tasa base, ventana de 1-2 horas).
- Notification channels: pulsa Manage notification channels, añade un canal de Email con tu correo y selecciónalo.
- En la documentación de la alerta escribe qué debe hacer quien la reciba (un mini runbook): «Revisar la última revisión desplegada en Cloud Run y los logs con severity ERROR; si coincide con un despliegue, revertir el tráfico a la revisión anterior».
- Guarda la política.
Paso 7: métrica basada en logs
Queremos contar los «fallos de pago» a partir de los logs, sin tocar el código. Una log-based metric de tipo contador convierte cada entrada que cumpla el filtro en un punto de una métrica de Monitoring.
gcloud logging metrics create fallos_pago \
--description="Errores de pago registrados por slo-demo" \
--log-filter='resource.type="cloud_run_revision" AND resource.labels.service_name="slo-demo" AND severity>=ERROR AND jsonPayload.message="Fallo simulado en el pago"'
La métrica solo cuenta desde su creación (no es retroactiva). Aparecerá en Metrics Explorer como logging.googleapis.com/user/fallos_pago.
Paso 8: provoca errores y observa
En otra pestaña de Cloud Shell, genera una ráfaga de errores (uno de cada dos peticiones falla, muy por encima del 1 % permitido):
for i in $(seq 1 300); do curl -s -o /dev/null $URL/error; curl -s -o /dev/null $URL/; done
Ahora observa, con paciencia (las métricas tardan unos minutos en llegar):
- Logs Explorer (Logging > Logs Explorer), con la consulta:
resource.type="cloud_run_revision"
resource.labels.service_name="slo-demo"
severity>=ERROR
Abre una entrada y fíjate en jsonPayload.pedido y jsonPayload.ruta: son los campos del log estructurado.
- Error Reporting: no mostrará nada, porque no hay trazas de excepción, solo mensajes. Es un buen recordatorio de que Error Reporting agrupa excepciones.
- Metrics Explorer:
logging.googleapis.com/user/fallos_pagosubiendo. - SLOs: el cumplimiento baja y el error budget restante cae; en la gráfica de burn rate verás que supera 10.
- Tu correo: en unos minutos debería llegar la alerta.
Comprueba que funciona
- El uptime check aparece en verde desde al menos tres regiones.
- El SLO muestra un presupuesto de errores consumido tras la ráfaga.
- Has recibido un correo de la alerta de burn rate (y después, al cesar los errores, el aviso de incidente resuelto; puede tardar hasta la duración de la ventana).
- La métrica
fallos_pagorefleja la ráfaga de errores. - Si tienes tiempo: en Observability Analytics (Logging > Observability Analytics o Log Analytics, según cómo aparezca en tu consola), actualiza el bucket
_Defaultpara usar SQL y cuenta los errores por minuto. Es opcional: la actualización del bucket no se puede deshacer.
Limpieza
Borra todo lo creado (o elimina el proyecto entero con gcloud projects delete $PROJECT_ID, la opción más segura):
# Alerta y canal (sustituye los IDs que te devuelva el list)
gcloud monitoring policies list --format="value(name,displayName)"
gcloud monitoring policies delete POLICY_NAME
gcloud beta monitoring channels list --format="value(name,displayName)"
gcloud beta monitoring channels delete CHANNEL_NAME
# Uptime check
gcloud monitoring uptime list-configs --format="value(name,displayName)"
gcloud monitoring uptime delete UPTIME_CHECK_ID
# Métrica basada en logs
gcloud logging metrics delete fallos_pago
# Servicio de Cloud Run e imágenes
gcloud run services delete $SERVICE --region $REGION
gcloud artifacts repositories delete cloud-run-source-deploy --location $REGION
El SLO y el servicio de Monitoring se borran desde Monitoring > SLOs (menú del servicio > Delete). Borra también el bucket PROJECT_ID_cloudbuild si se creó (gcloud storage rm -r gs://${PROJECT_ID}_cloudbuild).
Preguntas para pensar como arquitecto
¿Por qué alertar por burn rate del SLO en lugar de «más de 5 errores 500 por minuto»?
Un umbral fijo no tiene en cuenta el volumen: 5 errores por minuto son una catástrofe con 10 peticiones por minuto y ruido con 100.000. El burn rate mide la proporción de errores respecto al objetivo pactado y cuánto tardarías en agotar el presupuesto, así que alerta solo cuando el impacto en usuarios es real. Además, combinar fast burn (página) y slow burn (ticket) reduce la fatiga de alertas.
El uptime check estaba en verde mientras la mitad de las peticiones a /error fallaban. ¿Es un problema?
Muestra sus límites: el uptime check solo prueba una ruta y cada pocos minutos. Es útil para detectar caídas completas y problemas de red o DNS desde fuera, pero no mide la experiencia real de todos los usuarios. Por eso el SLO se basa en las peticiones reales (request-based) y el uptime check es un complemento. Para recorridos críticos (login, pago), usa synthetic monitors o comprueba rutas representativas.
¿Cuándo usarías una métrica basada en logs frente a instrumentar una métrica propia con OpenTelemetry?
La métrica basada en logs es ideal cuando la información ya está en los logs y no quieres (o no puedes) tocar el código, por ejemplo en una aplicación de terceros. Tiene un coste: dependes del volumen de logs (que pagas) y de que el formato no cambie. Si controlas el código y la métrica es importante o de alto volumen, instrumentarla con OpenTelemetry es más eficiente y robusto.
El equipo pide un SLO del 100 % para el servicio de pagos. ¿Qué respondes?
Que el 100 % es inalcanzable y contraproducente: dejaría un presupuesto de errores de cero, impediría cualquier cambio y costaría muchísimo en redundancia. Además los usuarios no lo perciben, porque su red y sus dispositivos fallan más. Se elige un SLO según lo que el usuario necesita y lo que el negocio está dispuesto a pagar (por ejemplo 99,95 %), por encima del SLA que se promete a los clientes.