From 9d63b000bcbd6300af2d98b713e2cea381b13320 Mon Sep 17 00:00:00 2001 From: AlexeerCT Date: Fri, 24 Apr 2026 12:53:11 -0500 Subject: [PATCH] Refactor Docker entrypoints and remove unused scripts - Removed custom entrypoint scripts for backend, frontend, and PostgreSQL services from docker-compose files. - Added a new entrypoint script in the backend and frontend Dockerfiles to handle initialization without relying on host-mounted scripts. - Updated Dockerfiles to ensure proper permissions for the new entrypoint scripts. - Enhanced database initialization logic by moving schema and extension creation to the Alembic migration script. --- backend/Dockerfile | 6 ++ .../versions/4ad64605fad2_first_migration.py | 7 +++ backend/docker-entrypoint.sh | 36 +++++++++++ docker-compose.prod.yml | 7 --- docker-compose.yml | 6 -- frontend/Dockerfile | 8 ++- frontend/Dockerfile.prod | 7 +++ frontend/docker-entrypoint.sh | 40 ++++++++++++ scripts/backend-entrypoint.sh | 62 ------------------- scripts/frontend-entrypoint.sh | 51 --------------- scripts/postgres-app-entrypoint.sh | 31 ---------- scripts/postgres-keycloak-entrypoint.sh | 14 ----- 12 files changed, 102 insertions(+), 173 deletions(-) create mode 100644 backend/docker-entrypoint.sh create mode 100644 frontend/docker-entrypoint.sh delete mode 100755 scripts/backend-entrypoint.sh delete mode 100755 scripts/frontend-entrypoint.sh delete mode 100755 scripts/postgres-app-entrypoint.sh delete mode 100755 scripts/postgres-keycloak-entrypoint.sh diff --git a/backend/Dockerfile b/backend/Dockerfile index 84d0d41d..c60f0bbe 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -42,6 +42,10 @@ COPY requirements.txt . # Instalar dependencias Python RUN pip install --no-cache-dir -r requirements.txt +# Entrypoint (espera Postgres/Keycloak; no montar desde el host) +COPY docker-entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + # Copiar código COPY . . @@ -52,5 +56,7 @@ ENV APP_VERSION=${APP_VERSION} # Exponer puerto EXPOSE 8000 +ENTRYPOINT ["/entrypoint.sh"] + # Comando por defecto CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"] diff --git a/backend/alembic/versions/4ad64605fad2_first_migration.py b/backend/alembic/versions/4ad64605fad2_first_migration.py index 9f0e1130..b685a8e0 100644 --- a/backend/alembic/versions/4ad64605fad2_first_migration.py +++ b/backend/alembic/versions/4ad64605fad2_first_migration.py @@ -20,6 +20,13 @@ depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: """Upgrade schema.""" + # Requisito previo (antes estaba en scripts de initdb de Docker): extensiones y esquemas + # para tablas creadas debajo (schema=public/core/a76/…). + op.execute('CREATE EXTENSION IF NOT EXISTS "uuid-ossp"') + op.execute("CREATE EXTENSION IF NOT EXISTS pg_trgm") + for _schema in ("core", "a76", "a22", "a24", "a30"): + op.execute(f"CREATE SCHEMA IF NOT EXISTS {_schema}") + # ### commands auto generated by Alembic - please adjust! ### op.create_table('inv_aphis_catalog', sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), diff --git a/backend/docker-entrypoint.sh b/backend/docker-entrypoint.sh new file mode 100644 index 00000000..69805452 --- /dev/null +++ b/backend/docker-entrypoint.sh @@ -0,0 +1,36 @@ +#!/bin/bash +set -e + +# Arranque del contenedor: espera a dependencias, luego ejecuta CMD (uvicorn, gunicorn, celery, …) + +# Función para esperar a un puerto TCP usando Python +wait_for_tcp() { + local host=$1 + local port=$2 + local service=$3 + local max_attempts=30 + local attempt=1 + + echo "Esperando a que $service esté disponible en ${host}:${port}..." + + while [ $attempt -le $max_attempts ]; do + if python3 -c "import socket; s = socket.socket(); s.settimeout(3); s.connect(('$host', $port)); s.close()" 2>/dev/null; then + echo "✓ $service está listo y accesible" + return 0 + fi + + echo "$service no está listo aún... (intento $attempt/$max_attempts)" + attempt=$((attempt + 1)) + sleep 2 + done + + echo "⚠ WARNING: $service no estuvo disponible después de $max_attempts intentos" + echo " Continuando de todas formas..." + return 0 +} + +wait_for_tcp "${CORE_DB_HOST:-postgres-a76}" "${CORE_DB_PORT:-5432}" "PostgreSQL" +wait_for_tcp "keycloak" "8080" "Keycloak" + +echo "Iniciando proceso: $*" +exec "$@" diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index cceace5d..90840164 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -12,7 +12,6 @@ services: - "5939:5432" volumes: - postgres_app_data:/var/lib/postgresql/data - - ./scripts/postgres-app-entrypoint.sh:/docker-entrypoint-initdb.d/init-app.sh:ro networks: - backend-net restart: unless-stopped @@ -48,7 +47,6 @@ services: - "5233:5432" volumes: - postgres_keycloak_data:/var/lib/postgresql/data - - ./scripts/postgres-keycloak-entrypoint.sh:/docker-entrypoint-initdb.d/init-keycloak.sh:ro networks: - auth-net - backend-net @@ -201,12 +199,10 @@ services: volumes: - backend_uploads:/app/uploads - backend_layouts:/app/layouts - - ./scripts/backend-entrypoint.sh:/entrypoint.sh:ro networks: - backend-net - frontend-net restart: unless-stopped - entrypoint: [ "/entrypoint.sh" ] command: [ "gunicorn", "main:app", "-k", "uvicorn.workers.UvicornWorker", "-w", "${WEB_CONCURRENCY:-1}", "-b", "0.0.0.0:8000", "--log-level", "info", "--forwarded-allow-ips", "*" ] healthcheck: test: [ "CMD-SHELL", "curl -f http://localhost:8000/api/health || exit 1" ] @@ -354,9 +350,6 @@ services: depends_on: backend: condition: service_healthy - entrypoint: [ "/frontend-entrypoint.sh" ] - volumes: - - ./scripts/frontend-entrypoint.sh:/frontend-entrypoint.sh:ro networks: - frontend-net - backend-net diff --git a/docker-compose.yml b/docker-compose.yml index 3e6485ef..33cef99f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,7 +12,6 @@ services: - "5432:5432" volumes: - postgres_app_data:/var/lib/postgresql - - ./scripts/postgres-app-entrypoint.sh:/docker-entrypoint-initdb.d/init-app.sh:ro networks: - backend-net restart: unless-stopped @@ -48,7 +47,6 @@ services: - "5433:5432" volumes: - postgres_keycloak_data:/var/lib/postgresql - - ./scripts/postgres-keycloak-entrypoint.sh:/docker-entrypoint-initdb.d/init-keycloak.sh:ro networks: - auth-net - backend-net @@ -206,12 +204,10 @@ services: - ./backend:/app - backend_cache:/app/__pycache__ - backend_uploads:/app/uploads - - ./scripts/backend-entrypoint.sh:/entrypoint.sh:ro networks: - backend-net - frontend-net restart: unless-stopped - entrypoint: [ "/entrypoint.sh" ] command: [ "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--reload", "--log-level", "info" ] healthcheck: test: [ "CMD-SHELL", "curl -f http://localhost:8000/api/health || exit 1" ] @@ -257,11 +253,9 @@ services: depends_on: backend: condition: service_healthy - entrypoint: [ "/frontend-entrypoint.sh" ] volumes: - ./frontend:/app - frontend_node_modules:/app/node_modules - - ./scripts/frontend-entrypoint.sh:/frontend-entrypoint.sh:ro networks: - frontend-net - auth-net diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 8ccfa4e2..c5d6a7d7 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -8,8 +8,6 @@ RUN apk update && apk add --no-cache ca-certificates wget && update-ca-certifica # Copiar package files COPY package.json pnpm-lock.yaml ./ - - # Instalar pnpm RUN npm config set strict-ssl false RUN npm install -g pnpm @@ -17,6 +15,10 @@ RUN npm install -g pnpm # Instalar dependencias RUN pnpm install +# Entrypoint (espera API backend en dev; no montar desde el host) +COPY docker-entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + # Copiar código COPY . . @@ -26,5 +28,7 @@ COPY . . # Exponer puerto EXPOSE 5173 +ENTRYPOINT ["/entrypoint.sh"] + # Comando por defecto (desarrollo) CMD ["pnpm", "run", "dev", "--", "--host", "0.0.0.0"] diff --git a/frontend/Dockerfile.prod b/frontend/Dockerfile.prod index 5d7ea7a6..8c3cc1bd 100644 --- a/frontend/Dockerfile.prod +++ b/frontend/Dockerfile.prod @@ -39,6 +39,8 @@ FROM node:22-alpine AS runtime WORKDIR /app +RUN apk add --no-cache wget + RUN npm config set strict-ssl false && \ npm install -g pnpm @@ -46,6 +48,9 @@ RUN npm config set strict-ssl false && \ RUN addgroup -g 1001 -S nodejs RUN adduser -S svelte -u 1001 +COPY docker-entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + # Copiar solo archivos necesarios para producción y aplicar propietario en la copia COPY --from=build --chown=svelte:nodejs /app/build ./build COPY --from=build --chown=svelte:nodejs /app/package.json ./ @@ -65,5 +70,7 @@ ENV HOST=0.0.0.0 # pero necesitamos valores por defecto para el build ENV INTERNAL_API_URL=http://backend:8000/api/ +ENTRYPOINT ["/entrypoint.sh"] + # Ejecutar aplicación con Node.js CMD ["pnpm", "start"] diff --git a/frontend/docker-entrypoint.sh b/frontend/docker-entrypoint.sh new file mode 100644 index 00000000..dfb1e28d --- /dev/null +++ b/frontend/docker-entrypoint.sh @@ -0,0 +1,40 @@ +#!/bin/sh +set -e + +# Arranque del contenedor: opcionalmente espera al health del backend, luego ejecuta CMD (pnpm dev / start, …) + +wait_for_backend() { + local url=$1 + local max_attempts=30 + local attempt=1 + + echo "Esperando a que el backend esté disponible en ${url}..." + + while [ $attempt -le $max_attempts ]; do + if wget -q -O /dev/null "${url}/health" 2>/dev/null; then + echo "✓ Backend está listo" + return 0 + fi + + echo "Backend no está listo aún... (intento $attempt/$max_attempts)" + attempt=$((attempt + 1)) + sleep 3 + done + + echo "⚠ WARNING: Backend no estuvo disponible, continuando de todas formas" + return 0 +} + +# compose usa INTERNAL_API_URL; alias opcional BACKEND_INTERNAL_URL +_api_base="${INTERNAL_API_URL:-${BACKEND_INTERNAL_URL:-http://backend:8000/api}}" +_api_base="${_api_base%/}" +wait_for_backend "${_api_base}/health" + +# En desarrollo (volumen montado) reinstala deps si cambia package.json +if [ "$NODE_ENV" = "development" ]; then + echo "Instalando dependencias (development)..." + CI=true pnpm install +fi + +echo "Iniciando: $*" +exec "$@" diff --git a/scripts/backend-entrypoint.sh b/scripts/backend-entrypoint.sh deleted file mode 100755 index 85cb5432..00000000 --- a/scripts/backend-entrypoint.sh +++ /dev/null @@ -1,62 +0,0 @@ -#!/bin/bash -set -e - -# Script de inicialización para el Backend FastAPI -# Espera a las dependencias y ejecuta migraciones antes de iniciar - -echo "==========================================" -echo "Backend FastAPI - Inicialización" -echo "==========================================" - -# Función para esperar a un puerto TCP usando Python -wait_for_tcp() { - local host=$1 - local port=$2 - local service=$3 - local max_attempts=30 - local attempt=1 - - echo "Esperando a que $service esté disponible en ${host}:${port}..." - - while [ $attempt -le $max_attempts ]; do - if python3 -c "import socket; s = socket.socket(); s.settimeout(3); s.connect(('$host', $port)); s.close()" 2>/dev/null; then - echo "✓ $service está listo y accesible" - return 0 - fi - - echo "$service no está listo aún... (intento $attempt/$max_attempts)" - attempt=$((attempt + 1)) - sleep 2 - done - - echo "⚠ WARNING: $service no estuvo disponible después de $max_attempts intentos" - echo " Continuando de todas formas..." - return 0 -} - -# Esperar a PostgreSQL -wait_for_tcp "${CORE_DB_HOST:-postgres-a76}" "${CORE_DB_PORT:-5432}" "PostgreSQL" - -# Esperar a Keycloak (HTTP por defecto usa puerto 8080) -wait_for_tcp "keycloak" "8080" "Keycloak" - -# Ejecutar migraciones de Alembic -#if [ -d "/app/alembic" ]; then -# echo "Ejecutando migraciones de Alembic..." -# alembic upgrade head || { -# echo "⚠ WARNING: Error al ejecutar migraciones" -# echo " Verificando estado de la base de datos..." -# alembic current || echo " No se pudo determinar la versión actual" -# } -# echo "✓ Migraciones completadas" -#else -# echo "⚠ WARNING: Directorio /app/alembic no encontrado" -# echo " Las migraciones de base de datos no se ejecutaron" -#fi - -echo "==========================================" -echo "Iniciando aplicación FastAPI..." -echo "==========================================" - -# Ejecutar el comando que se pasó al contenedor -exec "$@" diff --git a/scripts/frontend-entrypoint.sh b/scripts/frontend-entrypoint.sh deleted file mode 100755 index 9a431440..00000000 --- a/scripts/frontend-entrypoint.sh +++ /dev/null @@ -1,51 +0,0 @@ -#!/bin/sh -set -e - -# Script de inicialización para el Frontend SvelteKit -# Espera a que el backend esté disponible antes de iniciar - -echo "==========================================" -echo "Frontend SvelteKit - Inicialización" -echo "==========================================" - -# Función para esperar al backend -wait_for_backend() { - local url=$1 - local max_attempts=30 - local attempt=1 - - echo "Esperando a que el Backend esté disponible en ${url}..." - - while [ $attempt -le $max_attempts ]; do - if wget -q -O /dev/null "${url}/health" 2>/dev/null; then - echo "✓ Backend está listo" - return 0 - fi - - echo "Backend no está listo aún... (intento $attempt/$max_attempts)" - attempt=$((attempt + 1)) - sleep 3 - done - - echo "⚠ WARNING: Backend no estuvo disponible, continuando de todas formas" - return 0 -} - -# Esperar al backend -# En Docker, usamos el nombre del servicio. En desarrollo local, VITE_API_URL apunta a localhost -BACKEND_HEALTH_URL="${BACKEND_INTERNAL_URL:-http://backend:8000/api}" -wait_for_backend "${BACKEND_HEALTH_URL}" - -echo "==========================================" -echo "Iniciando aplicación SvelteKit..." -echo "==========================================" - -# Instalar dependencias nuevas si package.json ha cambiado -if [ "$NODE_ENV" = "development" ]; then - echo "Instalando dependencias (development mode)..." - # CI=true evita el error ERR_PNPM_ABORTED_REMOVE_MODULES_DIR_NO_TTY - CI=true pnpm install -fi - -# Ejecutar el comando que se pasó al contenedor -exec "$@" diff --git a/scripts/postgres-app-entrypoint.sh b/scripts/postgres-app-entrypoint.sh deleted file mode 100755 index 8380bc0c..00000000 --- a/scripts/postgres-app-entrypoint.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash -set -e - -echo "==========================================" -echo "PostgreSQL App - Inicialización" -echo "==========================================" - -# Este script es ejecutado por docker-entrypoint-initdb.d -# PostgreSQL ya está iniciado por el contenedor padre - -echo "✓ PostgreSQL está listo (iniciado por contenedor)" - -# La base de datos anexo76_core ya está creada por POSTGRES_DB -echo "✓ Base de datos 'anexo76_core' ya configurada" - -# Crear extensiones y esquemas -echo "Creando extensiones y esquemas..." -psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL - CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; - CREATE EXTENSION IF NOT EXISTS "pg_trgm"; - CREATE SCHEMA IF NOT EXISTS core; - CREATE SCHEMA IF NOT EXISTS a76; - CREATE SCHEMA IF NOT EXISTS a22; - CREATE SCHEMA IF NOT EXISTS a24; - CREATE SCHEMA IF NOT EXISTS a30; -EOSQL - -echo "✓ Extensiones y esquemas creados correctamente" -echo "==========================================" -echo "PostgreSQL App - Inicialización completada" -echo "==========================================" diff --git a/scripts/postgres-keycloak-entrypoint.sh b/scripts/postgres-keycloak-entrypoint.sh deleted file mode 100755 index 68b0de27..00000000 --- a/scripts/postgres-keycloak-entrypoint.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash -set -e - -# Este script se ejecuta automáticamente en la primera inicialización de PostgreSQL -# cuando se coloca en /docker-entrypoint-initdb.d/ - -echo "Inicializando base de datos keycloak..." - -psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" <<-EOSQL - -- Verificar que la base de datos existe - SELECT 'Base de datos keycloak lista' AS status; -EOSQL - -echo "✓ Base de datos keycloak inicializada correctamente"