diff --git a/.env.example b/.env.example index 9cc2c67..3b10f62 100644 --- a/.env.example +++ b/.env.example @@ -34,6 +34,7 @@ DB_PORT=3306 DB_DATABASE=holos-backend DB_USERNAME=notsoweb DB_PASSWORD= +DB_ROOT_PASSWORD= PMA_PORT=8081 # Puerto para phpMyAdmin NGINX_PORT=8080 # Puerto para Nginx diff --git a/docker-compose.yml b/Docker/Dev/docker-compose.yml similarity index 72% rename from docker-compose.yml rename to Docker/Dev/docker-compose.yml index ff73ec7..ac54701 100644 --- a/docker-compose.yml +++ b/Docker/Dev/docker-compose.yml @@ -1,18 +1,20 @@ +name: repuve-backend-dev services: repuve-backend: build: - context: . - dockerfile: dockerfile + context: ../../ + dockerfile: Docker/Dev/dockerfile working_dir: /var/www/repuve-backend-v1 environment: + - APP_ENV=development + - APP_DEBUG=true - DB_HOST=mysql - DB_USERNAME=${DB_USERNAME} - DB_PASSWORD=${DB_PASSWORD} - DB_DATABASE=${DB_DATABASE} - DB_PORT=${DB_PORT} volumes: - - ./:/var/www/repuve-backend-v1 - - ./vendor:/var/www/repuve/vendor + - storage_data:/var/www/repuve-backend-v1/storage networks: - repuve-network mem_limit: 512M @@ -24,11 +26,11 @@ services: nginx: image: nginx:alpine ports: - - "${NGINX_PORT}:80" + - "127.0.0.1:${NGINX_PORT}:80" volumes: - - ./public:/var/www/repuve-backend-v1/public - - ./storage:/var/www/repuve-backend-v1/storage - - ./Docker/nginx/nginx.conf:/etc/nginx/nginx.conf + - ../../public:/var/www/repuve-backend-v1/public + - ../../storage:/var/www/repuve-backend-v1/storage + - ../../Docker/nginx/nginx.conf:/etc/nginx/nginx.conf - /var/log/nginx:/var/log/nginx logging: driver: "local" @@ -46,11 +48,9 @@ services: image: mysql:8.0 environment: MYSQL_DATABASE: ${DB_DATABASE} - MYSQL_ROOT_PASSWORD: ${DB_PASSWORD} + MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD} MYSQL_PASSWORD: ${DB_PASSWORD} MYSQL_USER: ${DB_USERNAME} - ports: - - ${DB_PORT}:3306 volumes: - mysql_data:/var/lib/mysql networks: @@ -63,10 +63,10 @@ services: retries: 10 volumes: - nginx_data: - driver: local mysql_data: driver: local + storage_data: + driver: local networks: repuve-network: diff --git a/dockerfile b/Docker/Dev/dockerfile similarity index 98% rename from dockerfile rename to Docker/Dev/dockerfile index a2ad44c..8bc2b49 100644 --- a/dockerfile +++ b/Docker/Dev/dockerfile @@ -34,7 +34,6 @@ RUN chown -R www-data:www-data /var/www/repuve-backend-v1/storage /var/www/repuv RUN chmod -R 775 /var/www/repuve-backend-v1/storage /var/www/repuve-backend-v1/bootstrap/cache EXPOSE 9000 -EXPOSE 3306 ENTRYPOINT ["/usr/local/bin/entrypoint-dev.sh"] CMD ["php-fpm"] diff --git a/Docker/Prod/docker-compose.yml b/Docker/Prod/docker-compose.yml new file mode 100644 index 0000000..549aff5 --- /dev/null +++ b/Docker/Prod/docker-compose.yml @@ -0,0 +1,73 @@ +name: repuve-backend-prod +services: + repuve-backend: + build: + context: ../../ + dockerfile: Docker/Prod/dockerfile + working_dir: /var/www/repuve-backend-v1 + environment: + - APP_ENV=production + - APP_DEBUG=false + - DB_HOST=mysql + - DB_USERNAME=${DB_USERNAME} + - DB_PASSWORD=${DB_PASSWORD} + - DB_DATABASE=${DB_DATABASE} + - DB_PORT=${DB_PORT} + volumes: + - storage_data:/var/www/repuve-backend-v1/storage + networks: + - repuve-network + mem_limit: 512M + restart: unless-stopped + depends_on: + mysql: + condition: service_healthy + + nginx: + image: nginx:alpine + ports: + - "127.0.0.1:${NGINX_PORT}:80" + volumes: + - ../../public:/var/www/repuve-backend-v1/public + - storage_data:/var/www/repuve-backend-v1/storage + - ../../Docker/nginx/nginx.conf:/etc/nginx/nginx.conf + - /var/log/nginx:/var/log/nginx + logging: + driver: "local" + options: + max-size: "50m" + max-file: "10" + networks: + - repuve-network + mem_limit: 256m + restart: unless-stopped + depends_on: + - repuve-backend + + mysql: + image: mysql:8.0 + environment: + MYSQL_DATABASE: ${DB_DATABASE} + MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD} + MYSQL_PASSWORD: ${DB_PASSWORD} + MYSQL_USER: ${DB_USERNAME} + volumes: + - mysql_data:/var/lib/mysql + networks: + - repuve-network + mem_limit: 512m + restart: unless-stopped + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] + timeout: 15s + retries: 10 + +volumes: + mysql_data: + driver: local + storage_data: + driver: local + +networks: + repuve-network: + driver: bridge diff --git a/Docker/Prod/dockerfile b/Docker/Prod/dockerfile new file mode 100644 index 0000000..1daeb80 --- /dev/null +++ b/Docker/Prod/dockerfile @@ -0,0 +1,36 @@ +FROM php:8.3-fpm-alpine + +WORKDIR /var/www/repuve-backend-v1 + +RUN apk add --no-cache \ + curl \ + libpng-dev \ + oniguruma-dev \ + libxml2-dev \ + zip \ + unzip \ + libzip-dev \ + openssl \ + bash \ + && docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd zip + +COPY --from=composer:latest /usr/bin/composer /usr/bin/composer + +COPY composer.json composer.lock ./ + +RUN composer install --optimize-autoloader --no-interaction --no-scripts --no-dev + +COPY . . + +COPY entrypoint-prod.sh /usr/local/bin/entrypoint-prod.sh +RUN chmod +x /usr/local/bin/entrypoint-prod.sh + +RUN mkdir -p storage/app/keys storage/logs bootstrap/cache + +RUN chown -R www-data:www-data /var/www/repuve-backend-v1/storage /var/www/repuve-backend-v1/bootstrap/cache +RUN chmod -R 775 /var/www/repuve-backend-v1/storage /var/www/repuve-backend-v1/bootstrap/cache + +EXPOSE 9000 + +ENTRYPOINT ["/usr/local/bin/entrypoint-prod.sh"] +CMD ["php-fpm"] diff --git a/composer.json b/composer.json index b0729a1..0be11af 100644 --- a/composer.json +++ b/composer.json @@ -120,6 +120,18 @@ "services:status": [ "composer run jobs:status", "composer run broadcast:status" + ], + "docker:dev:up": [ + "docker compose -f Docker/Dev/docker-compose.yml --env-file .env up -d --build" + ], + "docker:dev:down": [ + "docker compose -f Docker/Dev/docker-compose.yml --env-file .env down" + ], + "docker:prod:up": [ + "docker compose -f Docker/Prod/docker-compose.yml --env-file .env up -d --build" + ], + "docker:prod:down": [ + "docker compose -f Docker/Prod/docker-compose.yml --env-file .env down" ] }, "extra": { diff --git a/entrypoint-prod.sh b/entrypoint-prod.sh new file mode 100644 index 0000000..3ca6a8e --- /dev/null +++ b/entrypoint-prod.sh @@ -0,0 +1,106 @@ +#!/bin/bash +set -e + +echo "=== Iniciando entrypoint PRODUCCIÓN ===" + +chown -R www-data:www-data /var/www/repuve-backend-v1/storage /var/www/repuve-backend-v1/bootstrap/cache +chmod -R 775 /var/www/repuve-backend-v1/storage /var/www/repuve-backend-v1/bootstrap/cache + +# Variables desde Docker environment +DB_HOST=${DB_HOST:-mysql} +DB_USERNAME=${DB_USERNAME:-root} +DB_PASSWORD=${DB_PASSWORD:-} +DB_DATABASE=${DB_DATABASE:-laravel} +MAX_RETRIES=30 +RETRY_COUNT=0 + +echo "Configuración de BD: Host=${DB_HOST}, Usuario=${DB_USERNAME}, Base=${DB_DATABASE}" + +# Función para verificar conectividad con MySQL usando PHP +check_mysql() { + php -r " + try { + \$pdo = new PDO('mysql:host=${DB_HOST};port=3306', '${DB_USERNAME}', '${DB_PASSWORD}'); + \$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + exit(0); + } catch (Exception \$e) { + exit(1); + } + " +} + +# Esperar a que MySQL esté disponible +echo "Esperando conexión a MySQL..." +until check_mysql; do + RETRY_COUNT=$((RETRY_COUNT + 1)) + if [ $RETRY_COUNT -ge $MAX_RETRIES ]; then + echo "ERROR: No se pudo conectar a MySQL después de $MAX_RETRIES intentos" + exit 1 + fi + echo "Intento $RETRY_COUNT/$MAX_RETRIES - Esperando a MySQL..." + sleep 2 +done + +echo "✓ MySQL está disponible" + +echo "Ejecutando comandos de inicialización de PRODUCCIÓN..." + +# Instalar dependencias sin paquetes de desarrollo +echo "Instalando dependencias de producción..." +composer install --no-dev --optimize-autoloader --no-interaction + +echo "Ejecutando package:discover..." +php artisan package:discover --ansi + +echo "Creando enlaces simbólicos..." +php artisan storage:link --force || true + +echo "Ejecutando configuración de producción..." +composer run env:prod + +# Cachear configuración, rutas y vistas para máximo rendimiento +echo "Generando caché de configuración..." +php artisan config:cache + +echo "Generando caché de rutas..." +php artisan route:cache + +echo "Generando caché de vistas..." +php artisan view:cache + +echo "Generando caché de eventos..." +php artisan event:cache + +echo "Creando directorio de claves Passport..." +mkdir -p storage/app/keys + +if [ ! -f "storage/app/keys/oauth-private.key" ] || [ ! -f "storage/app/keys/oauth-public.key" ]; then + echo "Claves de Passport no encontradas, generando..." + php artisan passport:keys || { + echo "Artisan falló, generando con OpenSSL..." + openssl genrsa -out storage/app/keys/oauth-private.key 4096 + openssl rsa -in storage/app/keys/oauth-private.key -pubout -out storage/app/keys/oauth-public.key + } + echo "✓ Claves de Passport generadas" +else + echo "✓ Claves de Passport ya existen, omitiendo generación" +fi + +# Establecer permisos correctos para las claves +chmod 600 storage/app/keys/oauth-private.key +chmod 644 storage/app/keys/oauth-public.key +chown www-data:www-data storage/app/keys/oauth-*.key + +echo "✓ Claves de Passport verificadas" + +echo "=== VERIFICANDO BASE DE DATOS PRODUCCIÓN ===" + +echo "Ejecutando migraciones pendientes..." +php artisan migrate --force + +echo "✓ Configuración de producción completada" + +echo "=== Iniciando PHP-FPM PRODUCCIÓN ===" + +# Iniciar PHP-FPM +exec "$@"