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<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
|
||||
builder.Services.AddCors(options =>
|
||||
{
|
||||
options.AddPolicy("AllowReactApp", builder =>
|
||||
options.AddPolicy("AllowReactApp", policyBuilder =>
|
||||
{
|
||||
builder.WithOrigins("http://localhost:5173")
|
||||
policyBuilder.WithOrigins(allowedOrigins)
|
||||
.AllowAnyHeader()
|
||||
.AllowAnyMethod()
|
||||
.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": "*",
|
||||
"AllowedOrigins": "http://localhost:5173",
|
||||
"ConnectionStrings": {
|
||||
"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,
|
||||
"CantidadTitularesAScrapear": 4,
|
||||
"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 * 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
|
||||
export type ConnectionStatus = 'Connecting' | 'Connected' | 'Disconnected' | 'Reconnecting';
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
import axios from 'axios';
|
||||
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({
|
||||
baseURL: API_URL,
|
||||
// Construimos la URL completa para las llamadas a la API REST
|
||||
baseURL: `${API_BASE_URL}/api`,
|
||||
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