Try Docker 1811
This commit is contained in:
		
							
								
								
									
										30
									
								
								backend/src/Titulares.Api/Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								backend/src/Titulares.Api/Dockerfile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | # Etapa 1: Compilación | ||||||
|  | # Usamos la imagen del SDK de .NET 8 para compilar la aplicación | ||||||
|  | FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build | ||||||
|  | WORKDIR /src | ||||||
|  |  | ||||||
|  | # Copiamos el archivo de proyecto y restauramos las dependencias primero | ||||||
|  | # Esto aprovecha el caché de capas de Docker | ||||||
|  | COPY ["Titulares.Api/Titulares.Api.csproj", "Titulares.Api/"] | ||||||
|  | RUN dotnet restore "Titulares.Api/Titulares.Api.csproj" | ||||||
|  |  | ||||||
|  | # Copiamos el resto del código fuente | ||||||
|  | COPY . . | ||||||
|  | WORKDIR "/src/Titulares.Api" | ||||||
|  | # Compilamos la aplicación en modo Release y la publicamos en la carpeta /app/publish | ||||||
|  | RUN dotnet publish "Titulares.Api.csproj" -c Release -o /app/publish --no-restore | ||||||
|  |  | ||||||
|  | # Etapa 2: Imagen Final | ||||||
|  | # Usamos la imagen de runtime de ASP.NET, que es mucho más ligera | ||||||
|  | FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS final | ||||||
|  | WORKDIR /app | ||||||
|  | COPY --from=build /app/publish . | ||||||
|  |  | ||||||
|  | # Exponemos el puerto 8080. El backend escuchará en este puerto dentro del contenedor. | ||||||
|  | EXPOSE 8080 | ||||||
|  |  | ||||||
|  | # Establecemos el entorno a Producción para que se use appsettings.Production.json | ||||||
|  | ENV ASPNETCORE_ENVIRONMENT=Production | ||||||
|  |  | ||||||
|  | # Punto de entrada para ejecutar la aplicación | ||||||
|  | ENTRYPOINT ["dotnet", "Titulares.Api.dll"] | ||||||
| @@ -23,12 +23,15 @@ builder.Services.AddScoped<CsvService>(); | |||||||
| builder.Services.AddSingleton<ConfiguracionRepositorio>(); | builder.Services.AddSingleton<ConfiguracionRepositorio>(); | ||||||
| builder.Services.AddSingleton<EstadoProcesoService>(); | builder.Services.AddSingleton<EstadoProcesoService>(); | ||||||
|  |  | ||||||
|  | // Obtener los orígenes permitidos desde la configuración | ||||||
|  | var allowedOrigins = builder.Configuration.GetValue<string>("AllowedOrigins")?.Split(',') ?? new[] { "http://localhost:5173" }; | ||||||
|  |  | ||||||
| // Añadimos la política de CORS | // Añadimos la política de CORS | ||||||
| builder.Services.AddCors(options => | builder.Services.AddCors(options => | ||||||
| { | { | ||||||
|     options.AddPolicy("AllowReactApp", builder => |     options.AddPolicy("AllowReactApp", policyBuilder => | ||||||
|     { |     { | ||||||
|         builder.WithOrigins("http://localhost:5173") |         policyBuilder.WithOrigins(allowedOrigins) | ||||||
|                .AllowAnyHeader() |                .AllowAnyHeader() | ||||||
|                .AllowAnyMethod() |                .AllowAnyMethod() | ||||||
|                .AllowCredentials(); |                .AllowCredentials(); | ||||||
|   | |||||||
							
								
								
									
										11
									
								
								backend/src/Titulares.Api/appsettings.Production.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								backend/src/Titulares.Api/appsettings.Production.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | { | ||||||
|  |   "ConnectionStrings": { | ||||||
|  |     "DefaultConnection": "Server=db-sqlserver;Database=TitularesDB;User Id=titularesApi;Password=PTP847Titulares;TrustServerCertificate=True;" | ||||||
|  |   }, | ||||||
|  |   "AllowedOrigins": "http://192.168.5.128:8905", | ||||||
|  |   "Logging": { | ||||||
|  |     "LogLevel": { | ||||||
|  |       "Default": "Warning"  | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -6,6 +6,7 @@ | |||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   "AllowedHosts": "*", |   "AllowedHosts": "*", | ||||||
|  |   "AllowedOrigins": "http://localhost:5173", | ||||||
|   "ConnectionStrings": { |   "ConnectionStrings": { | ||||||
|     "DefaultConnection": "Server=TECNICA3;Database=TitularesDB;User Id=titularesApi;Password=PTP847Titulares;Trusted_Connection=True;TrustServerCertificate=True;" |     "DefaultConnection": "Server=TECNICA3;Database=TitularesDB;User Id=titularesApi;Password=PTP847Titulares;Trusted_Connection=True;TrustServerCertificate=True;" | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| { | { | ||||||
|   "RutaCsv": "C:\\temp\\titulares.csv", |   "RutaCsv": "/data/titulares.csv", | ||||||
|   "IntervaloMinutos": 15, |   "IntervaloMinutos": 15, | ||||||
|   "CantidadTitularesAScrapear": 4, |   "CantidadTitularesAScrapear": 4, | ||||||
|   "ScrapingActivo": false |   "ScrapingActivo": false | ||||||
|   | |||||||
							
								
								
									
										41
									
								
								docker-compose.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								docker-compose.yml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | services: | ||||||
|  |   # Servicio del Backend | ||||||
|  |   backend: | ||||||
|  |     build: | ||||||
|  |       context: ./backend/src/Titulares.Api | ||||||
|  |       dockerfile: Dockerfile | ||||||
|  |     container_name: titulares-api | ||||||
|  |     # No exponemos puertos al exterior, el proxy se encarga de eso. | ||||||
|  |     environment: | ||||||
|  |       # Le decimos a ASP.NET Core que escuche en el puerto 8080 en todas las interfaces de red | ||||||
|  |       - ASPNETCORE_URLS=http://+:8080 | ||||||
|  |     networks: | ||||||
|  |       - app-net | ||||||
|  |       - shared-net # Conectamos a la red externa para la DB | ||||||
|  |     restart: unless-stopped | ||||||
|  |  | ||||||
|  |   # Servicio de Nginx (Proxy Inverso + Servidor Frontend) | ||||||
|  |   nginx-proxy: | ||||||
|  |     build: | ||||||
|  |       context: ./frontend # Construimos desde la carpeta del frontend... | ||||||
|  |       dockerfile: Dockerfile # ...usando su Dockerfile para generar los estáticos | ||||||
|  |     container_name: titulares-proxy | ||||||
|  |     # Montamos nuestra configuración personalizada de Nginx | ||||||
|  |     volumes: | ||||||
|  |       - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf | ||||||
|  |     ports: | ||||||
|  |       # Mapeamos el puerto 8905 del host al puerto 80 del contenedor Nginx | ||||||
|  |       - "8905:80" | ||||||
|  |     networks: | ||||||
|  |       - app-net | ||||||
|  |     depends_on: | ||||||
|  |       - backend # Aseguramos que el backend se inicie antes que el proxy | ||||||
|  |     restart: unless-stopped | ||||||
|  |  | ||||||
|  | networks: | ||||||
|  |   # Red interna para la comunicación entre el proxy y el backend | ||||||
|  |   app-net: | ||||||
|  |     driver: bridge | ||||||
|  |   # Definimos la red compartida como externa, ya que fue creada por otro stack | ||||||
|  |   shared-net: | ||||||
|  |     external: true | ||||||
							
								
								
									
										1
									
								
								frontend/.env.development
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								frontend/.env.development
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | VITE_API_BASE_URL=http://localhost:5174 | ||||||
							
								
								
									
										1
									
								
								frontend/.env.production
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								frontend/.env.production
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | VITE_API_BASE_URL= | ||||||
							
								
								
									
										30
									
								
								frontend/Dockerfile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								frontend/Dockerfile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | # Etapa 1: Construcción de la aplicación React | ||||||
|  | # Usamos una imagen de Node.js (versión Alpine por ser ligera) | ||||||
|  | FROM node:20-alpine AS build | ||||||
|  | WORKDIR /app | ||||||
|  |  | ||||||
|  | # Copiamos package.json y package-lock.json para instalar dependencias | ||||||
|  | COPY package*.json ./ | ||||||
|  | RUN npm install | ||||||
|  |  | ||||||
|  | # Copiamos el resto de los archivos del frontend | ||||||
|  | COPY . . | ||||||
|  | # Construimos la aplicación para producción. Los archivos resultantes irán a /app/dist | ||||||
|  | RUN npm run build | ||||||
|  |  | ||||||
|  | # Etapa 2: Servidor Nginx | ||||||
|  | # Usamos la imagen oficial de Nginx (versión Alpine por ser ligera) | ||||||
|  | FROM nginx:stable-alpine | ||||||
|  | WORKDIR /usr/share/nginx/html | ||||||
|  |  | ||||||
|  | # Eliminamos el contenido por defecto de Nginx | ||||||
|  | RUN rm -rf ./* | ||||||
|  |  | ||||||
|  | # Copiamos los archivos estáticos construidos en la etapa anterior | ||||||
|  | COPY --from=build /app/dist . | ||||||
|  |  | ||||||
|  | # Exponemos el puerto 80, que es el puerto por defecto de Nginx | ||||||
|  | EXPOSE 80 | ||||||
|  |  | ||||||
|  | # El comando por defecto de la imagen de Nginx es suficiente para iniciar el servidor | ||||||
|  | # CMD ["nginx", "-g", "daemon off;"] | ||||||
| @@ -3,7 +3,10 @@ | |||||||
| import { useEffect, useRef, useState } from 'react'; | import { useEffect, useRef, useState } from 'react'; | ||||||
| import * as signalR from '@microsoft/signalr'; | import * as signalR from '@microsoft/signalr'; | ||||||
|  |  | ||||||
| const HUB_URL = 'http://localhost:5174/titularesHub'; | // La URL base viene de la variable de entorno | ||||||
|  | const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || ''; | ||||||
|  | // Construimos la URL completa del Hub | ||||||
|  | const HUB_URL = `${API_BASE_URL}/titularesHub`; | ||||||
|  |  | ||||||
| // Definimos un tipo para el estado de la conexión para más claridad | // Definimos un tipo para el estado de la conexión para más claridad | ||||||
| export type ConnectionStatus = 'Connecting' | 'Connected' | 'Disconnected' | 'Reconnecting'; | export type ConnectionStatus = 'Connecting' | 'Connected' | 'Disconnected' | 'Reconnecting'; | ||||||
|   | |||||||
| @@ -3,10 +3,12 @@ | |||||||
| import axios from 'axios'; | import axios from 'axios'; | ||||||
| import type { Configuracion, Titular } from '../types'; | import type { Configuracion, Titular } from '../types'; | ||||||
|  |  | ||||||
| const API_URL = 'http://localhost:5174/api'; | // La URL base viene de la variable de entorno | ||||||
|  | const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || ''; | ||||||
|  |  | ||||||
| const apiClient = axios.create({ | const apiClient = axios.create({ | ||||||
|   baseURL: API_URL, |   // Construimos la URL completa para las llamadas a la API REST | ||||||
|  |   baseURL: `${API_BASE_URL}/api`, | ||||||
|   headers: { 'Content-Type': 'application/json' }, |   headers: { 'Content-Type': 'application/json' }, | ||||||
| }); | }); | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										46
									
								
								nginx/nginx.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								nginx/nginx.conf
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | |||||||
|  | # Define un "upstream" que apunta a nuestro servicio de backend. | ||||||
|  | # 'backend' será el nombre del servicio en docker-compose, y 8080 es el puerto | ||||||
|  | # que expusimos en su Dockerfile. | ||||||
|  | upstream backend_api { | ||||||
|  |     server backend:8080; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | server { | ||||||
|  |     # Nginx escuchará en el puerto 80 DENTRO del contenedor. | ||||||
|  |     listen 80; | ||||||
|  |     server_name 192.168.5.128; # Opcional, puedes usar localhost o tu dominio | ||||||
|  |  | ||||||
|  |     # Ubicación raíz: sirve los archivos de la aplicación React. | ||||||
|  |     location / { | ||||||
|  |         root /usr/share/nginx/html; | ||||||
|  |         try_files $uri /index.html; # Clave para Single Page Applications (SPA) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     # Ubicación para la API REST. | ||||||
|  |     # Todas las peticiones a http://.../api/... serán redirigidas al backend. | ||||||
|  |     location /api { | ||||||
|  |         proxy_pass http://backend_api; | ||||||
|  |         proxy_set_header Host $host; | ||||||
|  |         proxy_set_header X-Real-IP $remote_addr; | ||||||
|  |         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | ||||||
|  |         proxy_set_header X-Forwarded-Proto $scheme; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     # ----------- CONFIGURACIÓN CRÍTICA PARA SIGNALR ----------- | ||||||
|  |     # Ubicación para el Hub de SignalR. | ||||||
|  |     location /titularesHub { | ||||||
|  |         proxy_pass http://backend_api; | ||||||
|  |  | ||||||
|  |         # Requerido para que la conexión WebSocket funcione | ||||||
|  |         proxy_http_version 1.1; | ||||||
|  |         proxy_set_header Upgrade $http_upgrade; | ||||||
|  |         proxy_set_header Connection "Upgrade"; | ||||||
|  |         proxy_set_header Host $host; | ||||||
|  |          | ||||||
|  |         # Aumenta el timeout para conexiones de larga duración | ||||||
|  |         proxy_read_timeout 90s; | ||||||
|  |  | ||||||
|  |         # Evita que el proxy almacene en caché la negociación de WebSockets | ||||||
|  |         proxy_cache_bypass $http_upgrade; | ||||||
|  |     } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user