From 140ece8080603c9efa00e995dc8e5d826063bcc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Zieli=C5=84ski?= Date: Sun, 12 Oct 2025 20:17:33 +0200 Subject: [PATCH] WIP: build production images --- .dockerignore | 63 +++++++++++++++++++++++ .gitea/workflows/build.yml | 53 +++++++++++++++++++ .github/workflows/build.yml | 53 ------------------- BimAI.API/Dockerfile | 45 ++++++++++++++++ BimAI.API/Program.cs | 8 ++- BimAI.API/appsettings.Development.json | Bin 1047 -> 1191 bytes BimAI.API/appsettings.Production.json | 38 ++++++++++++++ BimAI.API/appsettings.json | 9 ---- BimAI.UI.Web/Dockerfile | 45 ++++++++++++++++ BimAI.UI.Web/Program.cs | 2 + BimAI.UI.Web/appsettings.Production.json | 22 ++++++++ BimAI.UI.Web/appsettings.json | 9 ---- 12 files changed, 275 insertions(+), 72 deletions(-) create mode 100644 .dockerignore create mode 100644 .gitea/workflows/build.yml delete mode 100644 .github/workflows/build.yml create mode 100644 BimAI.API/Dockerfile create mode 100644 BimAI.API/appsettings.Production.json delete mode 100644 BimAI.API/appsettings.json create mode 100644 BimAI.UI.Web/Dockerfile create mode 100644 BimAI.UI.Web/appsettings.Production.json delete mode 100644 BimAI.UI.Web/appsettings.json diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..ab0818f --- /dev/null +++ b/.dockerignore @@ -0,0 +1,63 @@ +# Build artifacts +**/bin/ +**/obj/ +**/out/ +**/publish/ + +# IDE and editor files +**/.vs/ +**/.vscode/ +**/.idea/ +**/.DS_Store +**/*.user +**/*.suo +**/*.userosscache +**/*.sln.docstates +**/*.userprefs +**/.fleet/ + +# Database files +**/*.dbmdl +**/*.jfm +**/*.mdf +**/*.ldf + +# Temp and swap files +**/*.swp +**/*.swo +**/*~ +**/*.tmp +**/*.temp + +# Logs +**/*.log + +# Node modules (if any frontend dependencies) +**/node_modules/ + +# Git files +.git/ +.gitignore +.gitattributes +.git-crypt/ + +# Documentation +README.md +**/*.md +LICENSE + +# Docker files +docker-compose.yml +docker-compose.*.yml +**/Dockerfile +**/.dockerignore + +# Development databases +docker/ + +# Test results +**/TestResults/ +**/*.trx + +# macOS +.DS_Store \ No newline at end of file diff --git a/.gitea/workflows/build.yml b/.gitea/workflows/build.yml new file mode 100644 index 0000000..3d03aab --- /dev/null +++ b/.gitea/workflows/build.yml @@ -0,0 +1,53 @@ +name: Build Docker Images + +on: + push: + branches: + - main + +concurrency: + group: build-${{ github.ref }} + cancel-in-progress: false + +jobs: + build-and-push: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: https://github.com/actions/checkout@v4 + + - name: Set up Docker Buildx + uses: https://github.com/docker/setup-buildx-action@v3 + + - name: Log in to Gitea Container Registry + run: | + echo "${{ secrets.REGISTRY_TOKEN }}" | docker login code.bim-it.pl -u "${{ secrets.REGISTRY_USER }}" --password-stdin + + - name: Build and push API image (build artifacts) + run: | + docker buildx build \ + --platform linux/amd64 \ + -f BimAI.API/Dockerfile \ + -t code.bim-it.pl/bimai/bimai-api:build-${{ github.run_id }} \ + --push \ + . + + - name: Build and push UI image (build artifacts) + run: | + docker buildx build \ + --platform linux/amd64 \ + -f BimAI.UI.Web/Dockerfile \ + -t code.bim-it.pl/bimai/bimai-ui:build-${{ github.run_id }} \ + --push \ + . + + - name: Output build info + run: | + echo "## 🏗️ Docker Images Built" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Build ID:** ${{ github.run_id }}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "Images pushed with tag: \`build-${{ github.run_id }}\`" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "Use **Release** workflow to tokenize and tag as \`:prod\`" >> $GITHUB_STEP_SUMMARY \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 1f61a82..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: Build Bimix - -on: - push: - branches: - - main - -jobs: - build: - name: Build WebAPI and WebUI - runs-on: ubuntu-latest - - env: - DOTNET_VERSION: '8.0.x' - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Setup .NET - uses: actions/setup-dotnet@v4 - with: - dotnet-version: ${{ env.DOTNET_VERSION }} - - - name: Restore WebAPI - run: dotnet restore Bimix.API/Bimix.API.csproj - - - name: Restore WebUI - run: dotnet restore Bimix.UI.Web/Bimix.UI.Web.csproj - - - name: Build WebAPI - run: dotnet build Bimix.API/Bimix.API.csproj --configuration Release --no-restore - - - name: Build WebUI - run: dotnet build Bimix.UI.Web/Bimix.UI.Web.csproj --configuration Release --no-restore - - - name: Publish WebAPI - run: | - dotnet publish Bimix.API/Bimix.API.csproj \ - --configuration Release \ - --output ./publish/Bimix-WebAPI - - - name: Publish Web (Blazor Server) - run: | - dotnet publish Bimix.UI.Web/Bimix.UI.Web.csproj \ - --configuration Release \ - --output ./publish/Bimix-Web - - - name: Upload publish artifact - uses: actions/upload-artifact@v4 - with: - name: bimix-artifacts - path: ./publish diff --git a/BimAI.API/Dockerfile b/BimAI.API/Dockerfile new file mode 100644 index 0000000..2733730 --- /dev/null +++ b/BimAI.API/Dockerfile @@ -0,0 +1,45 @@ +# Stage 1: Build +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +WORKDIR /src + +# Copy solution and all project files for restore +COPY BimAI.sln ./ +COPY BimAI.API/BimAI.API.csproj BimAI.API/ +COPY BimAI.Domain/BimAI.Domain.csproj BimAI.Domain/ +COPY BimAI.Application/BimAI.Application.csproj BimAI.Application/ +COPY BimAI.Infrastructure/BimAI.Infrastructure.csproj BimAI.Infrastructure/ + +# Restore dependencies +RUN dotnet restore BimAI.API/BimAI.API.csproj + +# Copy all source code +COPY . . + +# Build and publish +WORKDIR /src/BimAI.API +RUN dotnet publish -c Release -o /app/publish --no-restore + +# Stage 2: Runtime +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime +WORKDIR /app + +# Set timezone +ENV TZ=Europe/Warsaw +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +# Copy published files +COPY --from=build /app/publish . + +# Set environment variables +ENV ASPNETCORE_ENVIRONMENT=Production +ENV ASPNETCORE_URLS=http://0.0.0.0:7142 + +# Expose port +EXPOSE 7142 + +# Health check +HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://localhost:7142/health || exit 1 + +# Run the application +ENTRYPOINT ["dotnet", "BimAI.API.dll"] \ No newline at end of file diff --git a/BimAI.API/Program.cs b/BimAI.API/Program.cs index 1c72fed..a5ad58a 100644 --- a/BimAI.API/Program.cs +++ b/BimAI.API/Program.cs @@ -100,13 +100,19 @@ app.UseAuthorization(); app.UseAuthorization(); app.MapControllers(); +app.MapGet("/health", () => Results.Ok(new { status = "OK", timestamp = DateTime.UtcNow })) + .AllowAnonymous(); + RecurringJob.AddOrUpdate( "product-sync", job => job.ExecuteAsync(), Cron.Daily(2, 0), // Every day at 2:00 AM new RecurringJobOptions { - TimeZone = TimeZoneInfo.Local + TimeZone = TimeZoneInfo.Local, + MisfireHandling = app.Environment.IsDevelopment() + ? MisfireHandlingMode.Relaxed + : MisfireHandlingMode.Strict }); app.Run(); \ No newline at end of file diff --git a/BimAI.API/appsettings.Development.json b/BimAI.API/appsettings.Development.json index 4030be7e98736f35e2f7fe3c3fc3e559e2b5fded..fedb42c0b7742db42819f99bf8f2032499a3ab29 100644 GIT binary patch literal 1191 zcmV;Y1X%k3M@dveQdv+`0Pv(OXo|kr5NZ!0LJbT5%ddqpfb|zxu-UgpsNrI_Yd(Et zBr3IJ1Sd^4(mASaIUmr57F&%eY2sxFm)FGrg}PvCB}9yH8B&+Fl}MOM-l;J_6s8ybGRAb=<=(CD-TPS;Wz5vi zRtQme?*I3t?%&x3ner0P#sdkY)dG6)`HV|j?{I?4^y#}rsCO3}B4EWLpql+BcHB=Jwoob<- zdo+!$xNzXARE#YGCvxAuu9%{9^h0+EI)I?P*yJzs1i`yrt^ieZca~~`7Hlu$o zPC&dEre0sC9z`|&Denv^`eFq4O0EBxQ?rpvY`#{A`}bi)*nW^niap;n`!~{QdniC& zWLoz_P5*|0oYQMTycty`>}?0_@j#h-b{poJDq1@dBI1oMdXL*KfM5_xuxbYxv|aEB zqkM_jCGR=?P8ybZ25-8$Ip@Y57ap9jfguyPFav4PkSQ3fh%Y4)Cl}by{%a(2faIs* zFD?Rsr@ij>xC=-DWX%~1tFqyY=%m8B&2a=`%M~Rq5IHC*yyJbSL1nM`lLP3mZ0-hTsbh?T1Cx7UM7h1IpC8^! z<_!LaY@9`+=e>*-<9m;L4vBSXT1=?TJyf~0dQ6=2-Xq4_PdL7GdY{kozFMr(9p@WR zvHhGeu`fW*jzt<$MakJ$t;vc_V(}_4HAHOgT4d zcX=m(CM&mFN4tT*V5tZZ!zObM`P%=M(%*SD(^KJ637A-U|C`M@Om&c&NuEL4wo!G;txa3| z$+cbSl4{SZt-g`z_#q5Cgmt%;Mm|U2!zXx(v`rPf54wrT6%c&kAS;pV#+?093cgri z;_@*q4z({byEHhc4lI^;oL4PV7xR!+m^X#+2=n5z9V^D^HL7W!U-j}OHv86^nfzI% z+*vVmXVjp}czhcPgH8(5q|ATF9AcVFh1vE z+$prwWCZ$8R3wki-Vv^wF?)4uo#=_jsCF~0!?}dn^9xjUG%w(y1%kMG|4wdRzsIJ3fkyF}*ti|DpOJzRj0vXu0@1rd@;RKrVWkyc ziptC}Io#v5hzro*l$aXcA$1`|Nw+^DgZ>qaL_>F~-9&sSCwb!k+r>+yptCSc zQ=)$f&L#vVu9?I`TmxWGMJzs8;h6Zh|Jwvx53A=uuuF)zjDmXooBiH`829Z|d$RO5 zQO{Z93!mBL0BhX^rE5>^;gB;G-6nVsM!ppY?w2>Av^$Hcpx33nxHUb$)BiMf&%?YS z3$tpLmo+==4%?1i)M;2o&mB)(1x)!WqjhLJ=%z3m^8MVM=6)$kfdsQ*hbV!(dav+q zf5+uHcjt&4ekH>9UQ#ts3=6@@s^qq31L1Zaq&9&okf?+Inq`;?~s=xqD3tl6k9+Hp4z=;ZzN@Hcr4 z@HsG}z7Z7~eg?vuUekP{*a+SnD*@xa!^s>vhZ$*N$`lh%QyhaI>Cdpb47z^}vTj>A zu;YxwlWQE_PS{igM-KKvXzVxLL%4M?oP>n3OV;>XGaM;c(v>T5e2^#bQb4*6V=JD! z;ng2;0W-fW2)wNBQP>$r@J=`mf_S2$-%`la{>)kzC|s}E)Wjjt?61ixoHlLD>+9&Un zn(_yh9~Si%6U^}MKODF8M+n0mp@<%@+IW(MmoZz1#;Aiw=c^>sC$!&^6?o%0w8N<| RShk*u(Xv+t{C~@ee%$qQ3t#{M diff --git a/BimAI.API/appsettings.Production.json b/BimAI.API/appsettings.Production.json new file mode 100644 index 0000000..25a1fd0 --- /dev/null +++ b/BimAI.API/appsettings.Production.json @@ -0,0 +1,38 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning", + "Microsoft.EntityFrameworkCore": "Warning" + } + }, + "AllowedHosts": "*", + "ConnectionStrings": { + "DefaultConnection": "#{db-connection-string}#", + "HangfireConnection": "#{hangfire-connection-string}#" + }, + "E5_CRM": { + "ApiKey": "#{e5-crm-api-key}#" + }, + "GoogleAuth": { + "ClientId": "#{google-auth-client-id}#" + }, + "JwtSettings": { + "SecretKey": "#{jwt-secret-key}#", + "Issuer": "#{jwt-issuer}#", + "Audience": "#{jwt-audience}#", + "ExpiryDays": 7 + }, + "Hangfire": { + "ServerName": "#{hangfire-server-name}#", + "WorkerCount": 5, + "DashboardPath": "/hangfire" + }, + "Kestrel": { + "Endpoints": { + "Http": { + "Url": "http://0.0.0.0:7142" + } + } + } +} \ No newline at end of file diff --git a/BimAI.API/appsettings.json b/BimAI.API/appsettings.json deleted file mode 100644 index 10f68b8..0000000 --- a/BimAI.API/appsettings.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } - }, - "AllowedHosts": "*" -} diff --git a/BimAI.UI.Web/Dockerfile b/BimAI.UI.Web/Dockerfile new file mode 100644 index 0000000..24a0ca4 --- /dev/null +++ b/BimAI.UI.Web/Dockerfile @@ -0,0 +1,45 @@ +# Stage 1: Build +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +WORKDIR /src + +# Copy solution and all project files for restore +COPY BimAI.sln ./ +COPY BimAI.UI.Web/BimAI.UI.Web.csproj BimAI.UI.Web/ +COPY BimAI.UI.Shared/BimAI.UI.Shared.csproj BimAI.UI.Shared/ +COPY BimAI.Domain/BimAI.Domain.csproj BimAI.Domain/ +COPY BimAI.Application/BimAI.Application.csproj BimAI.Application/ + +# Restore dependencies +RUN dotnet restore BimAI.UI.Web/BimAI.UI.Web.csproj + +# Copy all source code +COPY . . + +# Build and publish +WORKDIR /src/BimAI.UI.Web +RUN dotnet publish -c Release -o /app/publish --no-restore + +# Stage 2: Runtime +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime +WORKDIR /app + +# Set timezone +ENV TZ=Europe/Warsaw +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +# Copy published files +COPY --from=build /app/publish . + +# Set environment variables +ENV ASPNETCORE_ENVIRONMENT=Production +ENV ASPNETCORE_URLS=http://0.0.0.0:7143 + +# Expose port +EXPOSE 7143 + +# Health check +HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \ + CMD wget --no-verbose --tries=1 --spider http://localhost:7143/health || exit 1 + +# Run the application +ENTRYPOINT ["dotnet", "BimAI.UI.Web.dll"] \ No newline at end of file diff --git a/BimAI.UI.Web/Program.cs b/BimAI.UI.Web/Program.cs index 8174e38..75501c4 100644 --- a/BimAI.UI.Web/Program.cs +++ b/BimAI.UI.Web/Program.cs @@ -30,6 +30,8 @@ app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseAntiforgery(); +app.MapGet("/health", () => Results.Ok(new { status = "OK", timestamp = DateTime.UtcNow })); + app.MapRazorComponents() .AddInteractiveServerRenderMode() .AddAdditionalAssemblies(typeof(MainLayout).Assembly); diff --git a/BimAI.UI.Web/appsettings.Production.json b/BimAI.UI.Web/appsettings.Production.json new file mode 100644 index 0000000..b2c34ee --- /dev/null +++ b/BimAI.UI.Web/appsettings.Production.json @@ -0,0 +1,22 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*", + "ApiSettings": { + "BaseUrl": "#{api-base-url}#" + }, + "GoogleAuth": { + "ClientId": "#{google-auth-client-id}#" + }, + "Kestrel": { + "Endpoints": { + "Http": { + "Url": "http://0.0.0.0:7143" + } + } + } +} \ No newline at end of file diff --git a/BimAI.UI.Web/appsettings.json b/BimAI.UI.Web/appsettings.json deleted file mode 100644 index 10f68b8..0000000 --- a/BimAI.UI.Web/appsettings.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } - }, - "AllowedHosts": "*" -}