El problema real#
Hace poco mi contenedor PostgreSQL empezó a tirar errores de corrupción en tablas críticas. El error típico: ERROR: invalid page header in block. No podía permitirme downtime, así que tuve que idear una estrategia de recuperación sin afectar la producción.
La solución no es mágica, pero es metódica. Te cuento exactamente qué hice.
Paso 1: Verificar la corrupción#
Primero, necesitas saber qué está roto. Accede al contenedor:
docker exec -it mi_postgres psql -U usuario -d mi_base_de_datosDentro de psql, ejecuta:
REINDEX DATABASE mi_base_de_datos;Si esto falla con errores de página corrupta, confirmaste el problema. Anota qué tablas afecta.
Paso 2: Hacer un dump limpio (sin la corrupción)#
Aquí va lo importante: pg_dump puede saltarse las páginas corruptas si usas la opción correcta:
docker exec mi_postgres pg_dump \
-U usuario \
-d mi_base_de_datos \
--no-acl \
--no-owner \
-F c \
> /backup/dump_limpio.dumpEl -F c genera un formato comprimido binario. Es más eficiente y te da más control en el restore.
Paso 3: Verificar la integridad del dump#
No confíes en que todo se copió bien. Valida el archivo:
docker exec mi_postgres pg_restore --list /backup/dump_limpio.dump | head -20Esto lista el contenido sin restaurar. Revisa que las tablas críticas estén presentes. También puedes verificar el tamaño:
ls -lh /backup/dump_limpio.dumpSi es significativamente más pequeño que esperabas, algo va mal.
Paso 4: Restore selectivo en un contenedor temporal#
Nunca restauras directamente en producción. Levanta un contenedor de test:
docker run --name pg_test \
-e POSTGRES_USER=usuario \
-e POSTGRES_PASSWORD=temporal \
-e POSTGRES_DB=test_db \
-d postgres:15Copia el dump al contenedor:
docker cp /backup/dump_limpio.dump pg_test:/Restaura:
docker exec pg_test pg_restore \
-U usuario \
-d test_db \
--data-only \
/dump_limpio.dumpEl --data-only omite la creación de esquema. Si tienes esquemas rotos, restauras solo datos en una estructura sana.
Paso 5: Validar datos en el contenedor test#
Conecta al contenedor test y verifica:
docker exec -it pg_test psql -U usuario -d test_dbEjecuta queries críticas:
SELECT COUNT(*) FROM tabla_critica;
SELECT * FROM tabla_critica LIMIT 5;
VACUUM ANALYZE;Si todo anda bien, procede. Si hay problemas, tienes un sandbox donde jugar.
Paso 6: Migración a producción#
Opción A (si tienes replica o puedes afectar):
docker exec mi_postgres_prod pg_dump \
-U usuario \
-d mi_base_de_datos \
--schema-only \
> /backup/esquema.sqlRestauras esquema limpio, luego datos desde tu dump verificado.
Opción B (si necesitas zero downtime):
Usas pg_upgrade o replicación física. Sincronizas el contenedor test como replica, promueves y switcheas.
Paso 7: Limpieza y documentación#
Una vez que producción está estable:
docker stop pg_test
docker rm pg_testArchiva los dumps:
gzip /backup/dump_limpio.dumpY documenta qué tablas tuvieron problemas. Esto avisa si hay un patrón de hardware o configuración.
Lecciones aprendidas#
- No confíes en un solo backup. Haz dumps regulares.
- Siempre valida en un entorno de test antes de tocar producción.
pg_restorecon opciones selectivas es tu aliado. Lee su manual.- Si ves corrupción repetida, revisa el filesystem del host. Puede ser síntoma de hardware defectuoso.
Este proceso me salvó horas de downtime. No es complejo, solo requiere disciplina y no apresurarse.