Simplificar configuración de PostgreSQL con cadena de conexión única
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 16s
All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 16s
Eliminados hacks de autenticación md5 y configuración manual de pg_hba.conf. Ahora usa NUXT_POSTGRES_URL como secret de Gitea para conexión directa.
This commit is contained in:
@@ -1,32 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "Configurando autenticación de PostgreSQL..."
|
||||
|
||||
POSTGRES_USER="${POSTGRES_USER:-seguidor}"
|
||||
POSTGRES_PASSWORD="${POSTGRES_PASSWORD:-seguidor_password}"
|
||||
POSTGRES_DB="${POSTGRES_DB:-$POSTGRES_USER}"
|
||||
|
||||
# Eliminar configuración scram-sha-256 y agregar md5
|
||||
# Esto asegura que las conexiones remotas funcionen correctamente
|
||||
sed -i '/scram-sha-256/d' "$PGDATA/pg_hba.conf"
|
||||
|
||||
# Agregar configuración para conexiones md5 si no existe
|
||||
if ! grep -q "host all all all md5" "$PGDATA/pg_hba.conf"; then
|
||||
echo "host all all all md5" >> "$PGDATA/pg_hba.conf"
|
||||
fi
|
||||
|
||||
# Forzar que las contraseñas se guarden en md5 (no scram) y
|
||||
# reescribir la contraseña para asegurar que coincide con las env vars.
|
||||
ESCAPED_PASSWORD=${POSTGRES_PASSWORD//\'/\'\'}
|
||||
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
|
||||
ALTER SYSTEM SET password_encryption = 'md5';
|
||||
ALTER ROLE "$POSTGRES_USER" WITH PASSWORD '${ESCAPED_PASSWORD}';
|
||||
SELECT pg_reload_conf();
|
||||
EOSQL
|
||||
|
||||
echo "✓ Configuración de autenticación aplicada (md5 + password sincronizada)"
|
||||
|
||||
# Nota: No es necesario recargar aquí porque este script corre ANTES
|
||||
# de que PostgreSQL termine su inicialización. Los cambios se aplican
|
||||
# automáticamente cuando PostgreSQL termina de iniciarse.
|
||||
@@ -6,7 +6,7 @@ Este directorio contiene los scripts SQL para inicializar y gestionar la base de
|
||||
|
||||
- [Archivos SQL](#archivos-sql)
|
||||
- [⚠️ Peculiaridades de Implementación](#️-peculiaridades-de-implementación)
|
||||
- [Autenticación PostgreSQL](#autenticación-postgresql)
|
||||
- [Conexión de la app](#conexión-de-la-app)
|
||||
- [Inicialización de la Base de Datos](#inicialización-de-la-base-de-datos)
|
||||
- [Persistencia de Datos](#persistencia-de-datos)
|
||||
- [Conexión desde Node.js](#conexión-desde-nodejs)
|
||||
@@ -19,12 +19,6 @@ Este directorio contiene los scripts SQL para inicializar y gestionar la base de
|
||||
|
||||
## Archivos SQL
|
||||
|
||||
### `00_configure_auth.sh`
|
||||
Script Bash que configura la autenticación de PostgreSQL:
|
||||
- Elimina configuración `scram-sha-256` (incompatible con driver `pg` de Node.js)
|
||||
- Configura método `md5` en `pg_hba.conf`
|
||||
- Se ejecuta automáticamente durante inicialización de PostgreSQL
|
||||
|
||||
### `01_schema.sql`
|
||||
Crea el esquema completo de la base de datos:
|
||||
- Tablas: `lotes`, `operaciones`, `operacion_lotes`
|
||||
@@ -52,51 +46,11 @@ Datos de ejemplo que representan un flujo completo de trazabilidad:
|
||||
|
||||
Esta sección documenta los desafíos técnicos encontrados y las soluciones implementadas durante el desarrollo.
|
||||
|
||||
### Autenticación PostgreSQL
|
||||
### Conexión de la app
|
||||
|
||||
#### ❌ Problema: Incompatibilidad scram-sha-256
|
||||
|
||||
**Contexto**: PostgreSQL 16 usa por defecto el método de autenticación `scram-sha-256`, pero el driver `pg` de Node.js tiene problemas de compatibilidad que resultan en:
|
||||
|
||||
```
|
||||
Error code: 28P01
|
||||
FATAL: password authentication failed for user "seguidor"
|
||||
```
|
||||
|
||||
#### ✅ Solución: Script de configuración automática
|
||||
|
||||
**Archivo**: `00_configure_auth.sh`
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "Configurando autenticación de PostgreSQL..."
|
||||
|
||||
# Eliminar configuración scram-sha-256
|
||||
sed -i '/scram-sha-256/d' "$PGDATA/pg_hba.conf"
|
||||
|
||||
# Agregar configuración md5
|
||||
if ! grep -q "host all all all md5" "$PGDATA/pg_hba.conf"; then
|
||||
echo "host all all all md5" >> "$PGDATA/pg_hba.conf"
|
||||
fi
|
||||
|
||||
# Forzar md5 para almacenamiento de passwords y reescribir contraseña
|
||||
psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL
|
||||
ALTER SYSTEM SET password_encryption = 'md5';
|
||||
ALTER ROLE "$POSTGRES_USER" WITH PASSWORD '${POSTGRES_PASSWORD}';
|
||||
SELECT pg_reload_conf();
|
||||
EOSQL
|
||||
|
||||
echo "✓ Configuración de autenticación aplicada (md5)"
|
||||
```
|
||||
|
||||
**Notas importantes**:
|
||||
- El script se ejecuta **antes** de que PostgreSQL termine su inicialización
|
||||
- Los cambios en `pg_hba.conf` se aplican automáticamente al finalizar el inicio
|
||||
- No es necesario ejecutar `pg_ctl reload` manualmente
|
||||
- El método `md5` es compatible con el driver `pg` de Node.js
|
||||
- Cada deploy vuelve a aplicar `password_encryption=md5` y resetea la contraseña vía Gitea Action para curar volúmenes antiguos
|
||||
- Se usa una **cadena de conexión única** (`NUXT_POSTGRES_URL`) consumida desde `runtimeConfig.postgresUrl`.
|
||||
- Formato recomendado: `postgres://seguidor:seguidor_password@postgres:5432/seguidor_lotes`.
|
||||
- El driver `pg` soporta `scram-sha-256` (default de Postgres 16), no se toca `pg_hba.conf`.
|
||||
|
||||
---
|
||||
|
||||
@@ -106,9 +60,8 @@ echo "✓ Configuración de autenticación aplicada (md5)"
|
||||
|
||||
Los scripts se ejecutan **solo si el volumen de datos está vacío** (primera vez):
|
||||
|
||||
1. **`00_configure_auth.sh`** - Configura autenticación md5
|
||||
2. **`01_schema.sql`** - Crea estructura (tablas, funciones, vistas)
|
||||
3. **`02_seed.sql`** - Inserta datos de ejemplo
|
||||
1. **`01_schema.sql`** - Crea estructura (tablas, funciones, vistas)
|
||||
2. **`02_seed.sql`** - Inserta datos de ejemplo
|
||||
|
||||
**Orden de ejecución**: Los archivos se ejecutan en orden alfabético/numérico.
|
||||
|
||||
@@ -216,42 +169,19 @@ git commit --allow-empty -m "Trigger reinit DB" && git push
|
||||
**Configuración en `server/utils/db.ts`**:
|
||||
|
||||
```typescript
|
||||
const config = {
|
||||
user: process.env.POSTGRES_USER || 'seguidor',
|
||||
password: process.env.POSTGRES_PASSWORD || 'seguidor_password',
|
||||
database: process.env.POSTGRES_DB || 'seguidor_lotes',
|
||||
host: process.env.POSTGRES_HOST || 'postgres',
|
||||
port: parseInt(process.env.POSTGRES_PORT || '5432'),
|
||||
max: 20, // Máximo de conexiones en el pool
|
||||
idleTimeoutMillis: 30000, // 30s timeout para conexiones idle
|
||||
connectionTimeoutMillis: 10000, // 10s timeout para establecer conexión
|
||||
}
|
||||
const config = useRuntimeConfig()
|
||||
const pool = new Pool({
|
||||
connectionString: config.postgresUrl, // Ej: postgres://user:pass@host:5432/db
|
||||
max: 10,
|
||||
idleTimeoutMillis: 30000,
|
||||
connectionTimeoutMillis: 10000,
|
||||
})
|
||||
```
|
||||
|
||||
**Peculiaridades**:
|
||||
|
||||
1. **Timeout de 10 segundos**: Necesario porque PostgreSQL puede tardar en aplicar configuración de autenticación
|
||||
|
||||
2. **Retry Logic Automático**:
|
||||
```typescript
|
||||
// Verifica conexión inicial con 5 reintentos
|
||||
let retries = 5
|
||||
const tryConnect = async () => {
|
||||
try {
|
||||
const client = await pool!.connect()
|
||||
console.log('✅ Conexión inicial a PostgreSQL exitosa')
|
||||
client.release()
|
||||
} catch (err: any) {
|
||||
retries--
|
||||
if (retries > 0) {
|
||||
console.log(`⚠️ Conexión falló, reintentando... (${retries} intentos)`)
|
||||
setTimeout(tryConnect, 2000) // Reintentar en 2s
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3. **Logs solo en desarrollo**:
|
||||
1. **Cadena única**: evita discrepancias entre host/puerto/usuario/contraseña.
|
||||
2. **Logs solo en desarrollo**:
|
||||
```typescript
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
pool.on('connect', () => {
|
||||
@@ -262,20 +192,7 @@ const config = {
|
||||
|
||||
#### ⚡ Race Condition: App vs PostgreSQL
|
||||
|
||||
**Problema**: Aunque docker-compose tiene `depends_on` con `service_healthy`, el healthcheck solo verifica que PostgreSQL **responde**, no que terminó de ejecutar los scripts de inicialización.
|
||||
|
||||
**Timeline Real**:
|
||||
```
|
||||
T+0s: PostgreSQL inicia
|
||||
T+2s: PostgreSQL responde a pg_isready → healthcheck ✅
|
||||
T+2s: App Nuxt inicia e intenta conectarse
|
||||
T+3s: PostgreSQL ejecuta 00_configure_auth.sh (cambia auth)
|
||||
T+4s: Primera conexión de app FALLA (todavía usa scram-sha-256)
|
||||
T+5s: Script termina, auth está configurado
|
||||
T+7s: Retry logic de app conecta exitosamente ✅
|
||||
```
|
||||
|
||||
**Solución**: El retry logic compensa esta race condition automáticamente.
|
||||
Aunque docker-compose tiene `depends_on` con `service_healthy`, el healthcheck solo verifica que PostgreSQL responde. Si necesitas máxima robustez puedes añadir un pequeño retry en la app o un `pg_isready` antes de exponer el servicio, pero con la cadena de conexión única y el pool el arranque es estable.
|
||||
|
||||
---
|
||||
|
||||
@@ -380,12 +297,11 @@ curl -X POST https://lotes.nucleoriofrio.com/api/debug/seed-database
|
||||
**Causas posibles**:
|
||||
|
||||
1. **Primera carga del sistema** (normal)
|
||||
- PostgreSQL todavía está configurando autenticación
|
||||
- Solución: Esperar ~5 segundos, el retry logic se encarga
|
||||
- Logs: `⚠️ Conexión falló, reintentando...` seguido de `✅ Conexión exitosa`
|
||||
- PostgreSQL todavía está terminando de iniciar
|
||||
- Solución: Esperar unos segundos y reintentar
|
||||
|
||||
2. **Volumen de postgres de un deploy anterior con scram-sha-256**
|
||||
- Solución: Eliminar volumen y redeploy
|
||||
2. **Volumen con contraseña diferente a la actual**
|
||||
- Solución: Eliminar volumen y redeploy para reinicializar
|
||||
```bash
|
||||
docker-compose --project-name lotes down -v
|
||||
git commit --allow-empty -m "Reinit DB" && git push
|
||||
@@ -393,7 +309,7 @@ curl -X POST https://lotes.nucleoriofrio.com/api/debug/seed-database
|
||||
|
||||
3. **Variables de entorno incorrectas**
|
||||
- Verificar en Gitea > Settings > Actions > Secrets/Variables
|
||||
- Variables requeridas: `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_DB`
|
||||
- Variables requeridas: `NUXT_POSTGRES_URL`, `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_DB`
|
||||
|
||||
### ❌ Error: "relation 'lotes' does not exist"
|
||||
|
||||
@@ -529,7 +445,6 @@ ORDER BY total DESC;
|
||||
↓
|
||||
4. Ejecuta /docker-entrypoint-initdb.d/ en orden:
|
||||
│
|
||||
├─ 00_configure_auth.sh → Cambia pg_hba.conf a md5
|
||||
├─ 01_schema.sql → Crea tablas, funciones, vistas
|
||||
└─ 02_seed.sql → Inserta 10 lotes, 7 ops, 16 rels
|
||||
↓
|
||||
@@ -600,9 +515,9 @@ docker exec -i lotes-postgres psql -U seguidor -d seguidor_lotes < backup.sql
|
||||
|
||||
| Decisión | Razón | Alternativa Descartada |
|
||||
|----------|-------|------------------------|
|
||||
| md5 en lugar de scram-sha-256 | Compatibilidad con driver pg de Node.js | Actualizar driver (requiere cambios mayores) |
|
||||
| Retry logic en pool | Compensa race condition de inicialización | depends_on custom healthcheck (complejo) |
|
||||
| Timeout de 10s | PostgreSQL puede tardar en configurar auth | 2s (insuficiente) |
|
||||
| Cadena de conexión única (`NUXT_POSTGRES_URL`) | Evita discrepancias entre host/puerto/usuario/contraseña | Variables sueltas (`POSTGRES_*`) en el runtime de la app |
|
||||
| No tocar `pg_hba.conf` (usa scram por defecto) | Menos acoplamiento a la imagen y a volúmenes existentes | Forzar md5 en init scripts |
|
||||
| Timeout de 10s en el pool | PostgreSQL puede tardar unos segundos en aceptar conexiones | Timeout bajo (más falsos negativos) |
|
||||
| DROP TABLE en reset | Workflow detecta ausencia y reinicializa | TRUNCATE (deja tablas vacías) |
|
||||
| seed ejecuta schema primero | Funciona después de borrar BD | Solo seed (falla si no hay tablas) |
|
||||
| Scripts SQL en app container | Permite endpoint de seed | Solo en postgres (no accesible desde app) |
|
||||
|
||||
Reference in New Issue
Block a user