diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..52b97f1 --- /dev/null +++ b/.drone.yml @@ -0,0 +1,82 @@ +kind: pipeline +type: docker +name: Build y Deploy + +trigger: + branch: + - main + event: + - push + +steps: +- name: build-and-publish-backend + image: plugins/kaniko + settings: + repo: host.docker.internal:5000/${DRONE_REPO_OWNER}/${DRONE_REPO_NAME,,}-backend + tags: + - latest + - ${DRONE_COMMIT_SHA:0:8} + dockerfile: Backend/GestionIntegral.Api/Dockerfile + context: . + username: + from_secret: GITEA_USER + password: + from_secret: ACTIONS_PAT + insecure: true + +- name: build-and-publish-frontend + image: plugins/kaniko + settings: + repo: host.docker.internal:5000/${DRONE_REPO_OWNER}/${DRONE_REPO_NAME,,}-frontend + tags: + - latest + - ${DRONE_COMMIT_SHA:0:8} + dockerfile: Frontend/Dockerfile + context: . + username: + from_secret: GITEA_USER + password: + from_secret: ACTIONS_PAT + insecure: true + depends_on: + - build-and-publish-backend + +- name: deploy-to-production + image: alpine:latest + environment: + SSH_KEY: + from_secret: PROD_SERVER_SSH_KEY + PROD_HOST: + from_secret: PROD_SERVER_HOST + PROD_USER: + from_secret: PROD_SERVER_USER + DB_PASSWORD: + from_secret: DB_SA_PASSWORD_SECRET + JWT_KEY: + from_secret: JWT_KEY_SECRET + REGISTRY: + from_secret: REGISTRY_URL + GITEA_USER: + from_secret: GITEA_USER + GITEA_PAT: + from_secret: ACTIONS_PAT + commands: + - apk add --no-cache openssh-client + - mkdir -p ~/.ssh + - echo "$SSH_KEY" > ~/.ssh/id_rsa + - chmod 600 ~/.ssh/id_rsa + - ssh-keyscan -H $PROD_HOST >> ~/.ssh/known_hosts + - | + ssh $PROD_USER@$PROD_HOST << 'EOF' + echo "--- CONECTADO AL SERVIDOR DE PRODUCCIÓN ---" + cd /opt/gestion-integral + export DB_SA_PASSWORD="${DB_PASSWORD}" + export JWT_KEY="${JWT_KEY}" + docker login ${REGISTRY} -u ${GITEA_USER} -p ${GITEA_PAT} + docker compose pull + docker compose up -d + docker image prune -af + echo "--- DESPLIEGUE COMPLETADO ---" + EOF + depends_on: + - build-and-publish-frontend \ No newline at end of file diff --git a/Backend/GestionIntegral.Api/Dockerfile b/Backend/GestionIntegral.Api/Dockerfile new file mode 100644 index 0000000..4a9f1db --- /dev/null +++ b/Backend/GestionIntegral.Api/Dockerfile @@ -0,0 +1,37 @@ +# --- Etapa 1: Build --- +# Usamos el SDK de .NET 9 (o el que corresponda) para compilar. +FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build +WORKDIR /src + +# Copiamos los archivos de proyecto (.sln y .csproj) y restauramos las dependencias. +# Esto es una optimización de caché de Docker. +COPY GestionIntegralWeb.sln . +COPY Backend/GestionIntegral.Api/GestionIntegral.Api.csproj Backend/GestionIntegral.Api/ + +# Restauramos los paquetes NuGet. +RUN dotnet restore "GestionIntegralWeb.sln" + +# Copiamos todo el resto del código fuente. +COPY . . + +# Nos movemos al directorio del proyecto y lo construimos en modo Release. +WORKDIR "/src/Backend/GestionIntegral.Api" +RUN dotnet build "GestionIntegral.Api.csproj" -c Release -o /app/build + +# --- Etapa 2: Publish --- +# Publicamos la aplicación, lo que genera los artefactos listos para producción. +FROM build AS publish +RUN dotnet publish "GestionIntegral.Api.csproj" -c Release -o /app/publish /p:UseAppHost=false + +# --- Etapa 3: Final --- +# Usamos la imagen de runtime de ASP.NET, que es mucho más ligera que el SDK. +FROM mcr.microsoft.com/dotnet/aspnet:9.0 +WORKDIR /app +COPY --from=publish /app/publish . + +# El puerto en el que la API escuchará DENTRO del contenedor. +# Usaremos 8080 para evitar conflictos si en el futuro corres algo en el puerto 80. +EXPOSE 8080 + +# El comando para iniciar la API cuando el contenedor arranque. +ENTRYPOINT ["dotnet", "GestionIntegral.Api.dll"] \ No newline at end of file diff --git a/Backend/GestionIntegral.Api/appsettings.json b/Backend/GestionIntegral.Api/appsettings.json index 2e51861..3fcf26c 100644 --- a/Backend/GestionIntegral.Api/appsettings.json +++ b/Backend/GestionIntegral.Api/appsettings.json @@ -6,7 +6,7 @@ } }, "Jwt": { - "Key": "badb1a38d221c9e23bcf70958840ca7f5a5dc54f2047dadf7ce45b578b5bc3e2", + "Key": "", "Issuer": "GestionIntegralApi", "Audience": "GestionIntegralClient", "DurationInHours": 8 diff --git a/Frontend/Dockerfile b/Frontend/Dockerfile new file mode 100644 index 0000000..81dfe7e --- /dev/null +++ b/Frontend/Dockerfile @@ -0,0 +1,31 @@ +# --- Etapa 1: Build --- +# Usamos una imagen de Node.js para construir los archivos estáticos de React. +FROM node:20-alpine AS build +WORKDIR /app + +# Copiamos los archivos de dependencias y las instalamos. +COPY package.json package-lock.json ./ +RUN npm install + +# Copiamos el resto del código del frontend. +COPY . . + +# Ejecutamos el script de build de Vite, que genera la carpeta 'dist'. +RUN npm run build + +# --- Etapa 2: Serve --- +# Usamos una imagen de Nginx súper ligera para servir los archivos estáticos. +FROM nginx:stable-alpine +WORKDIR /usr/share/nginx/html + +# Eliminamos el index.html por defecto de Nginx. +RUN rm -f index.html + +# Copiamos los archivos construidos desde la etapa anterior a la carpeta que Nginx sirve. +COPY --from=build /app/dist . + +# Nginx por defecto escucha en el puerto 80, así que lo exponemos. +EXPOSE 80 + +# Comando para iniciar Nginx. Esto asegura que se mantenga corriendo. +CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file