Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions src/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Build artifacts
**/bin/
**/obj/
**/out/
**/publish/

# IDE / editor
.vs/
.vscode/
.idea/
*.user
*.suo
*.swp

# Version control
.git/
.gitignore
**/.gitkeep

# Docker
**/Dockerfile*
**/.dockerignore
docker-compose*.yml

# Local config & secrets (never bake into the image)
**/appsettings.*.local.json
**/.env
**/.env.local
*.pfx
*.key

# Logs & misc
**/*.log
**/*.md
35 changes: 25 additions & 10 deletions src/Services/Product/Product.API/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,24 +1,39 @@
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
WORKDIR /app
EXPOSE 5004
# syntax=docker/dockerfile:1

# ---- Build stage ----
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src

# Restore first (leverages layer caching) — copy only project files.
COPY ["Services/Product/Product.API/Product.API.csproj", "Services/Product/Product.API/"]
COPY ["Services/Product/Product.Domain/Product.Domain.csproj", "Services/Product/Product.Domain/"]
COPY ["Services/Product/Product.Infrastructure/Product.Infrastructure.csproj", "Services/Product/Product.Infrastructure/"]
COPY ["Shared/Shared.Contracts/Shared.Contracts.csproj", "Shared/Shared.Contracts/"]
COPY ["Shared/Shared.Infrastructure/Shared.Infrastructure.csproj", "Shared/Shared.Infrastructure/"]
RUN dotnet restore "Services/Product/Product.API/Product.API.csproj"

# Copy the rest of the sources and publish.
COPY . .
WORKDIR "/src/Services/Product/Product.API"
RUN dotnet build -c Release -o /app/build
RUN dotnet publish "Product.API.csproj" -c Release -o /app/publish /p:UseAppHost=false

FROM build AS publish
RUN dotnet publish -c Release -o /app/publish /p:UseAppHost=false

FROM base AS final
# ---- Runtime stage ----
FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENV ASPNETCORE_URLS=http://+:5004

# Config is externalized via environment variables. Sensible container defaults:
# - listen on 8080 inside the container (override with ASPNETCORE_HTTP_PORTS/ASPNETCORE_URLS)
# - production environment unless overridden
# No hosts, credentials, or connection strings are baked into the image.
ENV ASPNETCORE_ENVIRONMENT=Production \
ASPNETCORE_HTTP_PORTS=8080 \
DOTNET_RUNNING_IN_CONTAINER=true

EXPOSE 8080

COPY --from=build /app/publish .

# Run as the non-root user provided by the base image.
USER $APP_UID

ENTRYPOINT ["dotnet", "Product.API.dll"]
1 change: 1 addition & 0 deletions src/Services/Product/Product.API/Product.API.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="10.*" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="10.*" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.*" />
</ItemGroup>
</Project>
18 changes: 16 additions & 2 deletions src/Services/Product/Product.API/Program.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
using Product.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Diagnostics.HealthChecks;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddHealthChecks();

builder.Services.AddDbContext<ProductDbContext>(options =>
options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));

builder.Services.AddHealthChecks()
.AddDbContextCheck<ProductDbContext>("database", tags: new[] { "ready" });

var app = builder.Build();

if (app.Environment.IsDevelopment())
Expand All @@ -20,6 +23,17 @@
}

app.MapControllers();
app.MapHealthChecks("/healthz");

// Liveness: process is up and able to serve requests. No dependency checks.
app.MapHealthChecks("/health", new HealthCheckOptions
{
Predicate = _ => false
});

// Readiness: dependencies (database) are reachable.
app.MapHealthChecks("/ready", new HealthCheckOptions
{
Predicate = check => check.Tags.Contains("ready")
});

app.Run();
2 changes: 1 addition & 1 deletion src/Services/Product/Product.API/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
}
},
"ConnectionStrings": {
"DefaultConnection": "Host=localhost;Database=productdb;Username=postgres;Password=postgres"
"DefaultConnection": ""
}
}
3 changes: 2 additions & 1 deletion src/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,13 @@ services:
context: .
dockerfile: Services/Product/Product.API/Dockerfile
ports:
- "5004:5004"
- "5004:8080"
depends_on:
- postgres
- rabbitmq
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_HTTP_PORTS=8080
- ConnectionStrings__DefaultConnection=Host=postgres;Database=productdb;Username=postgres;Password=postgres

notification-service:
Expand Down