La solicitud de cambio es pequeña. «Solo un ajuste de configuración.» La compilación está en verde. Los paneles parecen tranquilos. Es viernes, 18:12, y alguien pronuncia la frase maldita:
«Enviémoslo antes de que se nos olvide.»
Dos horas después, tu teléfono se convierte en instrumento de percusión. El canal de on-call se llena de capturas de pantalla con gráficos rojos y un pánico muy educado. Los planes del fin de semana se evaporan como una caché mal configurada.
Por qué los despliegues los viernes por la noche siguen ocurriendo
Los despliegues del viernes no son un misterio. Son un resultado predecible de incentivos, la física del calendario y el optimismo humano.
Los equipos pasan la semana construyendo funciones, persiguiendo plazos de producto y coleccionando «arreglos rápidos» como si fueran pelusas en un bolsillo.
Llega el viernes y de repente surge una fuerte necesidad de «vaciar la cola» e irse a casa con la pizarra limpia.
Mientras tanto, el sistema de producción tiene su propio calendario: tráfico pico, trabajos por lotes, retrasos de replicación, backups, tormentas de cron y ventanas de mantenimiento de terceros que nunca se coordinan con las tuyas. La noche del viernes rara vez es «tranquila» en un negocio distribuido globalmente.
Es solo tranquila para las personas que quieren irse.
Los impulsores reales (y qué hacer al respecto)
- Compresión de plazos: Un sprint termina el viernes, no porque la física lo exija, sino porque así lo hacen las reuniones. Mueve la cadencia de lanzamientos fuera de los límites del sprint.
- Ansiedad por la cola: Los equipos temen una acumulación creciente de cambios. Soluciona con cambios más pequeños, no con lanzamientos más tardíos. Envía menos por cambio.
- Analfabetismo de riesgo: La gente confunde «diff pequeño» con «radio de impacto pequeño». Requiere declaraciones explícitas del radio de impacto.
- Cultura del héroe: Los incidentes del viernes producen «salvadas» e historias épicas. Recompensa la prevención en su lugar: menos páginas vale más que recuperaciones dramáticas.
- On-call insuficiente: «Puedes» desplegar el viernes porque alguien está técnicamente de guardia. Eso no es un plan; es un sacrificio.
Si quieres un principio operativo único: no programes riesgo cuando tu capacidad de respuesta es la más baja. La noche del viernes es cuando
la dotación, el contexto y la disponibilidad de proveedores son peores. Eso no es un fallo moral; es matemáticas.
Broma #1: Un deploy de viernes es como hacer malabares con motosierras en la oscuridad — impresionante hasta que necesitas una venda y la tienda ya cerró a las 6.
Un poco de historia: cómo llegamos hasta aquí (hechos, no folklore)
«Nunca desplegar el viernes» a menudo se trata como una superstición. No lo es. Es una heurística cruda construida a partir de décadas de
experiencia operacional—especialmente de épocas en que hacer rollback significaba restaurar cintas, reconstruir servidores o esperar a que un DBA despertara.
Hechos y puntos de contexto (cortos, concretos)
- Control de cambios en empresas tempranas (1980s–1990s) a menudo usaba ventanas de mantenimiento semanales, comúnmente en fines de semana, porque se asumía tiempo de inactividad y los usuarios estaban «offline».
- Gestión de cambios estilo ITIL ganó popularidad en grandes organizaciones para reducir fallos, pero muchas implementaciones optimizaron el papeleo sobre el aprendizaje y la automatización.
- Empresas a escala web en los 2000 normalizaron el despliegue continuo porque el tiempo de inactividad era pérdida de ingresos, no «mantenimiento aceptable». Liberar más rápido exigió mejores rollback y observabilidad.
- Despliegues blue/green se volvieron comunes para reducir el riesgo de corte al cambiar tráfico entre dos entornos en lugar de mutar producción en sitio.
- Releases canarios crecieron con arquitecturas de servicios: enviar a un pequeño porcentaje, medir y luego ampliar. Eso es un experimento controlado, no un salto de fe.
- Feature flags evolucionaron de «interruptores de emergencia» a controles completos de lanzamiento, permitiendo desacoplar deploy y release—útil cuando tu deploy ocurre antes de estar seguro.
- Orquestación de contenedores (especialmente Kubernetes) facilitó los rollouts, pero también aceleró el fallo: una mala configuración puede propagarse globalmente en minutos.
- Observabilidad maduró desde gráficos de hosts hasta trazas distribuidas y alertas basadas en SLO, permitiendo lanzamientos más seguros—pero solo si los equipos la usan para validar cambios, no para decorar dashboards.
El arco histórico es consistente: cuanto más seguro quieras enviar, más necesitas automatización, retroalimentación rápida y la capacidad de deshacer.
Los despliegues del viernes no están «prohibidos» por tradición; están desaconsejados por la realidad de que deshacer y obtener feedback es más lento cuando todos se han ido.
Qué hacen los cambios del viernes por la noche a los sistemas (y a los equipos)
Modos de fallo técnicos que el viernes empeora
Los sistemas fallan igual el martes que el viernes. La diferencia es el tiempo hasta la verdad. El viernes aumenta el tiempo para notar,
tiempo para decidir y tiempo para recuperarse.
- Fallos de combustión lenta: fugas de memoria, acumulación en colas, contención de bloqueos y tormentas de compactación suelen tardar horas en hacerse obvios—convenientemente después de que todos se desconectan.
- Opacidad en dependencias: el único ingeniero que entiende el comportamiento de timeout del proveedor de pagos está cenando. La documentación está «en la wiki». La wiki está «en mantenimiento».
- Riesgo de rollback: cambios de esquema, migraciones con estado y jobs en background convierten el rollback en arqueología.
- Acantilados de capacidad: los patrones de tráfico del viernes pueden ser extraños: emails promocionales, picos de uso de fin de semana o trabajos por lotes que chocan con backups.
- Latencia humana: incluso los respondedores competentes son más lentos a las 2 a. m. Eso es biología, no incompetencia.
El lado organizacional: el viernes es donde se oculta el mal proceso
Los despliegues del viernes suelen ser un olor de proceso: no hay un tren real de releases, no hay propiedad clara, no hay clasificación explícita del riesgo,
no hay rollback ensayado y no hay una «definición de hecho» que incluya operaciones.
El objetivo no es «prohibir el viernes». El objetivo es «hacer el viernes aburrido». Si puedes desplegar el viernes por la noche y dormir, te lo has ganado con
disciplina: cambios pequeños, fuerte automatización, rollback rápido y el hábito de verificar la realidad en lugar de confiar en checks verdes.
Guía de diagnóstico rápido: encuentra el cuello de botella pronto
Cuando un despliegue del viernes se tuerce, lo peor que puedes hacer es revolver sin rumbo. Lo segundo peor es abrir cinco paneles y
declarar: «Todo se ve raro.»
Este playbook está diseñado para los primeros 15 minutos: reducir el espacio del problema, estabilizar y luego elegir rollback vs. roll-forward.
0) Primero: deja de empeorar las cosas
- Pausa más rollouts. Congela merges nuevos. Para el «un último arreglo rápido».
- Anuncia un canal de incidente y un único líder de incidente.
- Decide tu acción de seguridad: rechazar carga, desactivar la nueva función, drenar tráfico o hacer rollback.
1) Comprueba los síntomas hacia el usuario (2 minutos)
- ¿Es disponibilidad o corrección? 500s vs. datos incorrectos vs. timeouts.
- ¿Es global o regional? Una zona, una región, un tenant, una cohorte.
- ¿Está correlacionado con la hora del deploy? Compara la tasa de errores/latencia con el inicio del rollout, no con «más o menos cuando lo enviamos».
2) Decide qué capa está fallando (5 minutos)
- Borde: TLS, DNS, CDN, comprobaciones de salud del balanceador de carga.
- App: bucles de crash, timeouts de dependencias, agotamiento de hilos/conexiones.
- Datos: bloqueos en BD, lag de replicación, latencia de almacenamiento, acumulación en colas.
- Plataforma: presión en nodos, red, autoscaling, límites de cuota.
3) Encuentra el cuello de botella con «un número por capa» (8 minutos)
Elige una métrica o log «indicador» por capa para evitar ahogarte:
- Borde: tasa de 5xx en ingress, latencia p95 en LB, retransmisiones SYN.
- App: latencia por endpoint, conteos por tipo de error, número de reinicios.
- Datos: sesiones activas en BD, consultas lentas, lag de replicación, await del disco.
- Plataforma: CPU steal, presión de memoria, evictions de pods en kube, errores de red.
4) Elige rollback vs. roll-forward (y sé explícito)
- Rollback cuando el radio de impacto es alto, el modo de fallo es desconocido o la solución no es trivial.
- Roll-forward cuando tienes un arreglo quirúrgico y confianza de no empeorar el incidente.
Idea parafraseada (no literal): Werner Vogels ha argumentado que «todo falla, todo el tiempo», por lo que los sistemas resilientes asumen el fallo y se recuperan rápido.
Tareas prácticas: comandos, salidas y decisiones (12+)
Estos son los chequeos toscos que transforman «creo que es la base de datos» en «el primario está saturado en I/O de escritura y la replicación va con lag».
Cada tarea incluye: un comando, una salida de ejemplo, qué significa y la decisión que tomas.
1) Confirma qué cambió realmente (Git)
cr0x@server:~$ git show --name-status --oneline HEAD
8c2f1a7 prod: enable async indexer; tune pool size
M app/config/prod.yaml
M app/indexer/worker.py
M db/migrations/20260202_add_index.sql
Qué significa: No enviaste «solo configuración». Enviaste código + configuración + una migración. Eso son tres superficies de fallo.
Decisión: Trátalo como alto riesgo. Si los síntomas tocan BD o jobs en background, prioriza rollback/desactivar por feature flag sobre «ajustar un parámetro».
2) Comprueba el estado del despliegue (Kubernetes rollout)
cr0x@server:~$ kubectl -n prod rollout status deploy/api --timeout=30s
Waiting for deployment "api" rollout to finish: 3 of 24 updated replicas are available...
Qué significa: Los nuevos pods no están pasando a ready. Podría ser crash loops, chequeos de readiness fallando o timeouts de dependencias.
Decisión: Pausa el rollout inmediatamente para evitar un radio de impacto mayor; inspecciona eventos y logs de pods a continuación.
3) Pausar un rollout para detener la hemorragia
cr0x@server:~$ kubectl -n prod rollout pause deploy/api
deployment.apps/api paused
Qué significa: No se actualizarán más pods hasta que reanudes.
Decisión: Si los errores se correlacionan solo con los pods actualizados, mantenlo en pausa y considera escalar el ReplicaSet antiguo.
4) Identificar crash loops y su razón
cr0x@server:~$ kubectl -n prod get pods -l app=api -o wide
NAME READY STATUS RESTARTS AGE IP NODE
api-7f6cf4c8c8-2qkds 0/1 CrashLoopBackOff 6 12m 10.42.1.17 node-a
api-7f6cf4c8c8-9s1bw 1/1 Running 0 2h 10.42.3.22 node-c
Qué significa: Algunos pods son inestables; el problema puede depender de la configuración o del nodo.
Decisión: Extrae logs de un pod que falla; compara configuración y entorno con un pod sano.
5) Leer los últimos logs del contenedor que falla
cr0x@server:~$ kubectl -n prod logs api-7f6cf4c8c8-2qkds --previous --tail=50
ERROR: cannot connect to postgres: connection refused
ERROR: exiting after 30s startup timeout
Qué significa: La app no puede alcanzar la BD (o la BD está rechazando conexiones). Puede ser política de red, DNS, endpoint incorrecto o BD sobrecargada.
Decisión: Comprueba descubrimiento de servicio y conectividad a la BD desde dentro del cluster; también verifica la salud de la BD y conteo de conexiones.
6) Validar DNS y enrutamiento desde un pod de depuración
cr0x@server:~$ kubectl -n prod run netdebug --rm -it --image=busybox:1.36 -- sh -c "nslookup postgres.prod.svc.cluster.local; nc -zv postgres.prod.svc.cluster.local 5432"
Server: 10.96.0.10
Address: 10.96.0.10:53
Name: postgres.prod.svc.cluster.local
Address: 10.96.34.21
postgres.prod.svc.cluster.local (10.96.34.21:5432) open
Qué significa: DNS funciona y el puerto está abierto. La conectividad existe; la negativa en los logs puede venir del proceso de BD, no de la red.
Decisión: Cambia el foco a carga en BD, conexiones máximas, autenticación o estado de failover.
7) Comprobar conexiones y presión de bloqueos en la base de datos (PostgreSQL)
cr0x@server:~$ psql -h db-primary -U app -d appdb -c "select count(*) as conns, sum(case when wait_event_type is not null then 1 else 0 end) as waiting from pg_stat_activity;"
conns | waiting
-------+---------
497 | 183
(1 row)
Qué significa: Muchas sesiones, muchas esperando. Aquí nacen la latencia y los timeouts.
Decisión: Identifica en qué esperan; considera reducir nuevos workers, desactivar una nueva vía de código o aumentar límites de pool solo si la BD tiene capacidad.
8) Encontrar los principales eventos de espera (PostgreSQL)
cr0x@server:~$ psql -h db-primary -U app -d appdb -c "select wait_event_type, wait_event, count(*) from pg_stat_activity where wait_event_type is not null group by 1,2 order by 3 desc limit 5;"
wait_event_type | wait_event | count
-----------------+--------------------+-------
Lock | relation | 122
IO | DataFileRead | 44
Client | ClientRead | 17
(3 rows)
Qué significa: Contención de locks más esperas de IO. Probablemente hay una migración o una consulta caliente.
Decisión: Si se ejecutó una migración, considera abortar/retroceder el despliegue y tratar el estado de la migración; si es por consultas, identifica la fuente y aplica throttling.
9) Verificar si una migración está en curso y bloqueando
cr0x@server:~$ psql -h db-primary -U app -d appdb -c "select pid, state, query from pg_stat_activity where query ilike '%alter table%' limit 3;"
pid | state | query
------+--------+----------------------------------------
8121 | active | ALTER TABLE orders ADD COLUMN foo text;
(1 row)
Qué significa: Un ALTER TABLE está activo; dependiendo de la operación, puede bloquear y detener el tráfico.
Decisión: Decide si terminar la query y aceptar un estado de migración parcial, o continuar y rechazar carga; si no puedes completarla de forma segura, revierte el comportamiento de la app que depende de ella.
10) Comprobar latencia de disco en el host de BD (iostat)
cr0x@server:~$ iostat -xz 1 3
avg-cpu: %user %nice %system %iowait %steal %idle
18.44 0.00 6.21 22.17 0.00 53.18
Device r/s w/s rkB/s wkB/s await svctm %util
nvme0n1 320.0 810.0 51200.0 104000.0 24.7 0.8 92.5
Qué significa: Alto iowait y alta utilización del disco; await promedio ~25ms es duro para una BD caliente.
Decisión: Identifica la fuente de I/O (migración, vacuum, índice nuevo). Limita jobs en background; considera revertir cambios que aumentaron la amplificación de escritura.
11) Comprobar espacio de sistema de ficheros y presión de inodos
cr0x@server:~$ df -h /var/lib/postgresql
Filesystem Size Used Avail Use% Mounted on
/dev/md0 1.8T 1.7T 62G 97% /var/lib/postgresql
Qué significa: 97% lleno. Eso no es «está bien». Eso es «a un autovacuum de la tristeza».
Decisión: Detén tareas opcionales intensivas en escritura; libera espacio (archivos WAL antiguos, backups viejos) de forma segura; considera expansión de emergencia. No sigas desplegando escrituras.
12) Comprobar memoria del sistema y riesgo de OOM
cr0x@server:~$ free -h
total used free shared buff/cache available
Mem: 62Gi 57Gi 1.2Gi 1.1Gi 3.8Gi 1.7Gi
Swap: 4.0Gi 3.9Gi 128Mi
Qué significa: Estás viviendo en swap. La latencia se disparará; el kernel está ocupándose de paginación en vez de servir.
Decisión: Reduce workers que consumen memoria; considera revertir un cambio que aumentó el tamaño de la caché; si es necesario, mueve tráfico o añade capacidad.
13) Comprobar tráfico y errores en vivo de un servicio rápidamente (logs de nginx)
cr0x@server:~$ sudo tail -n 5 /var/log/nginx/access.log
10.20.1.14 - - [02/Feb/2026:18:21:10 +0000] "GET /api/orders HTTP/1.1" 502 173 "-" "mobile/1.9"
10.20.1.15 - - [02/Feb/2026:18:21:10 +0000] "GET /api/orders HTTP/1.1" 502 173 "-" "mobile/1.9"
Qué significa: 502s en el borde suelen significar fallo en upstream: app que cae, timeouts o agotamiento de conexiones.
Decisión: Correlaciona los picos de 502 con reinicios de pods y esperas en la BD; si hay fuerte correlación con el deploy, está justificado el rollback.
14) Comprobar eventos de kube por problemas de scheduling/salud
cr0x@server:~$ kubectl -n prod get events --sort-by=.lastTimestamp | tail -n 8
Warning Unhealthy kubelet Readiness probe failed: HTTP probe failed with statuscode: 500
Warning BackOff kubelet Back-off restarting failed container
Warning Failed kubelet Error: context deadline exceeded
Qué significa: Chequeos de salud fallando y reinicios. «context deadline exceeded» sugiere dependencias lentas o nodos sobrecargados.
Decisión: Si las probes son demasiado estrictas, no «arregles» desactivándolas; arregla la dependencia o haz rollback. Los chequeos de salud son mensajeros, no enemigos.
15) Confirmar qué versión está sirviendo tráfico (tag de imagen)
cr0x@server:~$ kubectl -n prod get deploy/api -o jsonpath='{.spec.template.spec.containers[0].image}{"\n"}'
registry.internal/prod/api:8c2f1a7
Qué significa: Ahora puedes alinear «incidente iniciado» con «versión en producción». No más discutir por sensaciones.
Decisión: Si solo la nueva versión se correlaciona con errores, revierte al tag conocido bueno anterior.
16) Revertir el despliegue (Kubernetes)
cr0x@server:~$ kubectl -n prod rollout undo deploy/api
deployment.apps/api rolled back
Qué significa: Kubernetes vuelve al spec del ReplicaSet anterior. No deshace migraciones de BD ni efectos secundarios.
Decisión: Si el problema involucró esquema o jobs en background, mantiene la app estable tras el rollback y luego aborda la limpieza de la capa de datos con deliberación.
Tres microhistorias de la vida corporativa
Microhistoria 1: El incidente causado por una suposición equivocada
Una empresa mediana ejecutaba un servicio de analítica de clientes en Kubernetes. El equipo quería reducir la latencia de cold-start para un endpoint popular.
Añadieron un cache warmer que se ejecutaba al inicio: ejecutar unas consultas comunes, precargar la caché y estar listo para el tráfico pico.
Funcionó en staging. Funcionó en una prueba de producción tranquila.
La suposición era simple: «unas pocas consultas comunes» serían baratas. Pero «comunes» implicaba hacer joins entre dos tablas grandes y escanear particiones recientes.
El warmer se ejecutó en cada nuevo pod, y el despliegue del viernes aumentó el recuento de réplicas para manejar el tráfico del fin de semana.
A las 19:00 comenzó el rollout. Los nuevos pods arrancaron, ejecutaron el warmer y golpearon la base de datos como un equipo de natación sincronizada hecho de martillos.
La CPU de la BD subió, luego el I/O, luego las esperas por locks. La app empezó a hacer timeouts, lo que disparó reintentos, que multiplicaron el tráfico, que activó el autoscaling,
que lanzó más pods, que ejecutaron más warmers. Un bucle cerrado. Ordenado.
El ingeniero de guardia vio «connection refused» y asumió un problema de red. Reinició el proxy de BD.
Eso lo empeoró: tormentas de reconexión además de la carga ya alta. Solo tras revisar los eventos de espera vieron contención de locks y esperas de I/O,
y los warmers estaban por todas las trazas de consultas.
La solución no fue ingeniosa. Enviaron una feature flag: calentamiento de caché desactivado por defecto en producción, y activable solo tras verificar headroom en BD.
Más tarde lo rediseñaron para precalentar desde un dataset precomputado, no desde joins en vivo. También añadieron una regla: cualquier job de arranque que toque una dependencia compartida
debe tener limitación de tasa y probarse bajo condiciones de rollout escalado.
Microhistoria 2: La optimización que salió mal
Otra organización tenía un gateway de almacenamiento de objetos interno delante de un clúster de almacenamiento. Su problema: latencia de escritura bajo cargas pico.
La optimización propuesta: aumentar la concurrencia. Más hilos de trabajo, colas más profundas, lotes más grandes. El viernes parecía «seguro» porque el tráfico era moderado.
El cambio se envió con un ajuste de configuración: el pool de workers se duplicó y el gateway empezó a acumular fragmentos más grandes en memoria antes de flush.
Las métricas mejoraron inmediatamente en un benchmark sintético. En producción, la primera hora se vio bien: throughput arriba, p95 abajo.
La gente publicó gráficos de celebración. Alguien sugirió aplicarlo en todas las regiones.
Entonces la presión de memoria comenzó a crecer. El gateway ahora retenía más escrituras en vuelo por conexión, y los clientes estaban más dispuestos a reintentar
porque todo se sentía rápido. Las pausas de garbage collection se alargaron. El kernel comenzó a recuperar memoria agresivamente. Finalmente el gateway
entró en un bucle de OOM-kill, pero solo en un subconjunto de nodos con tuning de kernel antiguo. El viernes garantizó que la única persona que recordaba esos nodos
no estaba despierta.
La «optimización» redujo la latencia hasta que se transformó en colapso. El rollback restauró la estabilidad pero dejó un desorden: uploads multipart parcialmente escritos,
clientes confundidos y una cola que tardó horas en vaciarse.
La lección no fue «nunca optimizar». Fue «optimiza con guardarraíles». Añadieron límites por tenant, topes duros en bytes en vuelo
y requirieron una prueba de carga que igualara la concurrencia de producción, no un benchmark de laboratorio. También crearon una pequeña «pool canaria» de nodos que siempre
recibe cambios de configuración primero, con monitorización extra sobre memoria y tiempo de pausa de GC.
Microhistoria 3: La práctica aburrida pero correcta que salvó el día
Un servicio relacionado con pagos tenía el hábito estricto: cada despliegue incluía una validación post-deploy scriptada que se ejecutaba desde un host neutral.
No desde el portátil de un desarrollador. No desde dentro del cluster. Desde una caja de validación con bloqueo en la misma red que los clientes reales.
Verificaba DNS, TLS, algunos endpoints críticos y un flujo de compra sintético que nunca tocaba dinero real.
Una tarde de viernes, un despliegue rutinario actualizó la configuración de terminación TLS. Todo «parecía» bien: pods sanos, CPU normal, baja tasa de errores.
Pero en minutos, soporte al cliente empezó a ver fallos dispersos desde ciertos clientes móviles.
La validación aburrida lo detectó antes que los gráficos: fallos de handshake TLS para una suite de cifrado de clientes específicos. El despliegue había eliminado accidentalmente
un cifrado necesario para dispositivos más antiguos. Como el script de validación fijaba múltiples perfiles de cliente, señaló la regresión de inmediato.
Revirtieron en menos de diez minutos. Sin heroísmos. Sin llamadas largas. La parte más dramática fue que alguien se quedó en silencio para masticar.
La victoria real: evitaron un incidente de movimiento lento que habría goteado como «fallos de pago aleatorios» durante un fin de semana.
Ese equipo fue objeto de bromas por ser anticuado. También fueron el único equipo que regularmente disfrutaba fines de semana sin interrupciones.
Aburrido era el objetivo.
Broma #2: La forma más rápida de descubrir dependencias no documentadas es desplegar un viernes y esperar a que se presenten.
Errores comunes: síntoma → causa raíz → solución
Los incidentes de viernes por la noche tienen patrones. Aquí están los que siguen apareciendo, con correcciones específicas que cambian los resultados.
1) Síntoma: p95 de latencia se dispara, CPU parece normal
- Causa raíz: espera de I/O o contención de locks; la app está inactiva porque espera disco o locks de BD.
- Solución: Revisa iowait y eventos de espera en BD; limita jobs en background; evita «simplemente agregar hilos». Revierte migraciones que introdujeron escrituras pesadas.
2) Síntoma: 502/504 en el balanceador después del deploy
- Causa raíz: pods no listos, crash looping o timeouts upstream por sobrecarga de dependencias.
- Solución: Pausa el rollout, inspecciona fallos de readiness, compara pods nuevos vs antiguos. Revierte si la regresión de la dependencia no está clara en 10–15 minutos.
3) Síntoma: la tasa de errores aumenta lentamente en 30–90 minutos
- Causa raíz: fuga de memoria, crecimiento de colas, agotamiento de pools de conexión o amplificación por reintentos.
- Solución: Revisa memoria, reinicios, profundidad de colas y conteos de reintentos. Apaga la nueva vía de código con feature flag; reduce reintentos y añade jitter.
4) Síntoma: base de datos «connection refused» o «too many clients»
- Causa raíz: tormenta de conexiones tras rollout, desajuste de tamaños de pool, max_connections de BD alcanzado o proxy sobrecargado.
- Solución: Limita tamaños de pool en la app; añade un pooler de conexiones; realiza rollouts lentos; asegura que las liveness probes no desencadenen tormentas de reinicios.
5) Síntoma: solo una región está caída
- Causa raíz: configuración específica de la región, secreto faltante, DNS malo o capacidad desigual.
- Solución: Diff de configuración y secretos entre regiones; valida resolución DNS desde esa región; no hagas «rollback global» si el problema es localizado.
6) Síntoma: revertir no lo arregla
- Causa raíz: efectos colaterales irreversibles: cambio de esquema, corrupción de datos, jobs encolados, cache envenenada o backlog en colas.
- Solución: Ten pasos de «rollback más remediación»: parar runners que escriben, drenar colas, restaurar caches o ejecutar migraciones compensatorias.
7) Síntoma: alertas ruidosas pero los usuarios dicen que está bien
- Causa raíz: alertas basadas en errores internos sin contexto de SLO; canaries no excluidos; explosiones de cardinalidad en métricas.
- Solución: Vincula alertas al impacto de usuario; mantén señales separadas para canary y baseline; limita la cardinalidad de etiquetas.
8) Síntoma: nuevos pods sanos, pero el throughput cae
- Causa raíz: throttling a nivel de nodo (límites de CPU), vecino ruidoso en IO o cambios en políticas de red que aumentan latencia.
- Solución: Revisa throttling y presión de nodos; mueve cargas; verifica throttling de cgroup; revisa diffs de políticas de red.
Listas de verificación / plan paso a paso (despliega con seguridad o no lo hagas)
Decisión previa al viernes: ¿debería ocurrir este despliegue?
- Clasifica el cambio: sin estado vs con estado; toca esquema vs no; cambia dependencias vs no.
- Pregunta «¿cuál es el radio de impacto?» Nombra los sistemas y el peor impacto al usuario en un párrafo.
- Chequeo de realidad de rollback: ¿Puedes deshacerlo en menos de 15 minutos? Si no, no es un despliegue de viernes; estás programando un incidente.
- Chequeo de dotación: ¿Hay un segundo ingeniero disponible? No «localizable». Disponible.
- Chequeo de dependencias de proveedores: ¿Estás cambiando algo que necesita soporte externo? Si sí, no lo envíes tarde el viernes.
Paso a paso: un flujo de despliegue más seguro
- Congelar alcance: no commits de última hora. Taggea el candidato de release.
- Verificar artefactos: confirma que los digests/tags de imágenes coinciden con lo que probaste.
- Ejecutar checks preflight: salud de BD, espacio en disco, lag de replicación, profundidad de colas, presupuestos de error.
- Habilitar un interruptor de corte: feature flag o toggle de configuración que desactive el comportamiento nuevo sin redeploy.
- Canary primero: 1–5% del tráfico. Observa señales clave durante 10–20 minutos, no 60 segundos.
- Escalar con cuidado: ritmo de rollout lento; evita reinicios sincronizados; condiciona cada etapa a métricas.
- Validación post-deploy: checks scriptados desde una perspectiva externa.
- Declarar «hecho» explícitamente: cuando las métricas estén estables y la ventana de rollback aún abierta.
- Escribir la nota: qué cambió, cómo desactivar y qué vigilar—mientras los detalles están frescos.
Lista de verificación de rollback (porque algún día la necesitarás)
- Detener el rollout: pausa despliegues y auto-scalers si amplifican el problema.
- Desactivar nuevo comportamiento primero: feature flag off. Esto es más rápido que redeploy.
- Revertir componentes sin estado: revertir pods/servicios de la app.
- Estabilizar la capa de datos: detener migraciones y job runners que escriben.
- Drenar colas deliberadamente: no desatar un backlog sobre una BD enferma.
- Confirmar recuperación: checks sintéticos hacia el usuario, tasa de error, latencia y tendencia del backlog.
Políticas que funcionan realmente (sin convertir a los ingenieros en burócratas)
La mayoría de las políticas de «no desplegar el viernes» fallan porque son reglas morales que se hacen pasar por ingeniería.
Los ingenieros sortearán reglas morales. Especialmente cuando la presión de producto aparece con fecha límite.
1) Reemplaza «no viernes» por «cambios por nivel de riesgo»
Permite despliegues de bajo riesgo en cualquier momento: cambios sin estado con rollback probado, sin esquema, sin nuevas dependencias y con buena cobertura canaria.
Restringe cambios de alto riesgo (esquemas, almacenamiento, auth, redes, flujos de pago) a ventanas con personal completo y soporte de proveedores.
2) Haz del rollback un requisito de producto
Si la función no puede desactivarse rápidamente, no está lista para producción. Eso no es una preferencia de ops; es un requisito de seguridad del usuario.
Las feature flags no son solo para experimentación. Son disyuntores para la latencia organizacional.
3) Vincula derechos de despliegue a observabilidad y runbooks
Si no puedes responder «¿qué debería ver en las métricas si esto funciona?» no estás listo para enviar.
Cada deploy debe llevar sus propios pasos de verificación: qué gráficos, qué logs, qué señal de presupuesto de error.
4) Trata las migraciones como desplegables separados
Los cambios de esquema deben ser escalonados, retrocompatibles y desacoplados del comportamiento de la aplicación.
Despliega código que pueda funcionar en estados pre y post-migración. Luego migra. Luego cambia el comportamiento.
La noche del viernes no es momento para descubrir que tu ORM generó una DDL que bloquea.
5) Normaliza «parar» como un resultado exitoso
Necesitas una cultura donde cancelar un despliegue se considere competente, no cobarde.
Si alguien dice «no me gustan las señales», paras. Si el liderazgo castiga eso, tendrás más incidentes de viernes.
Eso no es una predicción. Es un estado de cuenta.
Preguntas frecuentes
1) ¿»Nunca desplegar el viernes» es realmente buen consejo?
Como regla general es tosca pero protectora. La mejor regla es: no despliegues cuando no puedas responder.
Los equipos maduros pueden desplegar cualquier día porque han construido rollback rápido, canaries y verificación. La mayoría de equipos aún no están ahí.
2) ¿Qué cuenta como un cambio «seguro para viernes»?
Cambios sin estado con un camino de rollback probado, sin cambios de esquema, sin actualizaciones de dependencias, sin nuevos jobs en background y con feature flag para desactivar comportamiento.
Además: debes tener un script de validación post-deploy que realmente ejecutarás.
3) ¿Los despliegues canarios son suficientes para hacer el viernes seguro?
Solo si tu canario es representativo y tus señales son significativas. Si el tráfico canario no ejercita las rutas de código riesgosas,
solo estás retrasando la caída hasta que aumentes el tráfico.
4) ¿Por qué a veces los rollbacks no ayudan?
Porque muchos fallos no están en la capa sin estado. Migraciones de datos, cache envenenada, jobs encolados y escrituras parciales persisten tras el rollback.
Necesitas acciones compensatorias: parar escritores, drenar con seguridad y reparar el estado.
5) ¿Debemos preferir rollback o roll-forward?
Haz rollback cuando el modo de fallo es oscuro o el impacto al usuario es alto. Roll-forward cuando tienes una corrección pequeña, bien entendida y confianza de no ampliar el incidente.
El error es decidir por orgullo en lugar de por radio de impacto.
6) ¿Cuál es la mejor inversión única para reducir incidentes de viernes?
Un validation post-deploy scriptado y repetible más un interruptor de corte. Ese par convierte «esperamos» en «verificamos» y acorta drásticamente los incidentes.
7) ¿Cómo detener las excepciones de «solo por esta vez»?
Haz las excepciones costosas de forma visible: requiere un escrito de riesgo explícito, un líder de incidente nombrado en espera y un plan de rollback revisado antes de enviar.
Las excepciones deben sentirse como programar una operación, no pedir comida a domicilio.
8) ¿Y si el negocio exige releases los viernes?
Entonces trata el viernes como una ventana de release dotada: on-call más un segundo ingeniero, decisores disponibles y congelamiento de otros trabajos riesgosos.
Si el negocio quiere releases los viernes pero no financiar la capacidad de respuesta, no es una demanda. Es una apuesta.
9) ¿Las feature flags crean sus propios riesgos?
Sí: deriva de configuración, flags olvidadas y complejidad. Gestiona flags con propiedad, fechas de vencimiento y logs de auditoría.
Pero el beneficio operativo es enorme: las flags convierten outages en toggles.
10) ¿Cómo sabemos que estamos «lo suficientemente maduros» para desplegar el viernes?
Cuando tus incidentes por despliegues son raros, breves y aburridos: detección rápida, rollback claro y recuperación verificada.
Si tu tiempo medio de recuperación se mide en horas y tus postmortems mencionan «no teníamos acceso», no estás allí.
Conclusión: siguientes pasos que puedes hacer esta semana
Los despliegues los viernes por la noche no son malvados. Son honestos. Revelan lo que tu proceso ha estado fingiendo no saber:
el rollback no es real, la validación es ad hoc, las migraciones dan miedo y el conocimiento operativo del equipo está atrapado en pocas cabezas.
Si quieres menos fines de semana devorados por «cambios pequeños», haz estos pasos:
- Crea una política de niveles de riesgo que restrinja cambios con estado/alto radio de impacto a ventanas con personal.
- Añade un interruptor de corte para cada comportamiento nuevo y riesgoso, y pruébalo como una función real.
- Escribe un script de validación post-deploy que se ejecute fuera del cluster y compruebe el recorrido del usuario.
- Practica rollback a pleno día: mídelo, documéntalo y arregla lo que sea lento.
- Haz las migraciones aburridas desacoplándolas: retrocompatibles, escalonadas y observables.
La meta no es «no desplegar los viernes». Es «no tener sorpresas los viernes». Eso se gana con disciplina, no con suerte.