diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f7221bb --- /dev/null +++ b/Dockerfile @@ -0,0 +1,69 @@ +# ========================================================================= +# STAGE 1: Build & Compile Tailwind CSS (Node.js + Yarn) +# ========================================================================= +FROM node:20-alpine AS tailwind-builder +WORKDIR /src + +# Copy package descriptors first to leverage Docker layer caching +COPY Tmt.SaqaTravel/package.json Tmt.SaqaTravel/yarn.lock ./Tmt.SaqaTravel/ + +# Install Node dependencies using Yarn with frozen lockfile for deterministic builds +WORKDIR /src/Tmt.SaqaTravel +RUN yarn install --frozen-lockfile + +# Copy the minimum files required for Tailwind CSS compilation. +# Tailwind scans Razor components and pages to identify and compile used utility classes. +WORKDIR /src +COPY Tmt.SaqaTravel/Components/ ./Tmt.SaqaTravel/Components/ +COPY Tmt.SaqaTravel/Styles/ ./Tmt.SaqaTravel/Styles/ +COPY Tmt.SaqaTravel/tailwind.config.js* ./Tmt.SaqaTravel/ + +# Run the Tailwind CSS build script to output the compiled app.min.css inside wwwroot +WORKDIR /src/Tmt.SaqaTravel +RUN mkdir -p wwwroot && \ + (yarn run build || npx tailwindcss -i Styles/app.css -o wwwroot/app.min.css --minify) + +# ========================================================================= +# STAGE 2: Restore, Build, & Publish .NET 10 Application +# ========================================================================= +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS dotnet-builder +WORKDIR /src + +# Copy the XML-based solution (.slnx) and project file for package restoration +COPY Tmt.SaqaTravel.slnx ./ +COPY Tmt.SaqaTravel/Tmt.SaqaTravel.csproj ./Tmt.SaqaTravel/ + +# Restore NuGet dependencies +RUN dotnet restore Tmt.SaqaTravel/Tmt.SaqaTravel.csproj + +# Copy the full C# source code +COPY Tmt.SaqaTravel/ ./Tmt.SaqaTravel/ + +# Overwrite / insert the pre-compiled, minified Tailwind CSS stylesheet from Stage 1 +COPY --from=tailwind-builder /src/Tmt.SaqaTravel/wwwroot/app.min.css ./Tmt.SaqaTravel/wwwroot/app.min.css + +# Compile and publish the release-ready Blazor app (No AppHost, single-file DLL bundle) +WORKDIR /src/Tmt.SaqaTravel +RUN dotnet publish Tmt.SaqaTravel.csproj -c Release -o /app/publish /p:UseAppHost=false + +# ========================================================================= +# STAGE 3: Slim, Secure, and Lightweight Runtime Container +# ========================================================================= +FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine AS final +WORKDIR /app + +# Expose standard web traffic ports +EXPOSE 8080 +EXPOSE 8081 + +# Copy the published C# binaries and static wwwroot files +COPY --from=dotnet-builder /app/publish . + +# Configure ASP.NET Core URL bindings to listen on non-privileged port +ENV ASPNETCORE_URLS=http://+:8080 +ENV ASPNETCORE_ENVIRONMENT=Production + +# Leverage the default .NET non-root user ($APP_UID is 1654 in alpine) for secure container execution +USER $APP_UID + +ENTRYPOINT ["dotnet", "Tmt.SaqaTravel.dll"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..7cf7496 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,14 @@ +services: + web: + image: tmt-saqatravel:latest + build: + context: . + dockerfile: Dockerfile + container_name: tmt_saqatravel_app + ports: + - "8070:8080" + - "8071:8081" + environment: + - ASPNETCORE_ENVIRONMENT=Production + - ASPNETCORE_URLS=http://+:8080 + restart: always