Containerize Customer service: hardened Dockerfile + /health & /ready probes#81
Containerize Customer service: hardened Dockerfile + /health & /ready probes#81devin-ai-integration[bot] wants to merge 1 commit into
Conversation
…dpoints, externalized config
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
| }, | ||
| "ConnectionStrings": { | ||
| "DefaultConnection": "Host=localhost;Database=customerdb;Username=postgres;Password=postgres" | ||
| } |
There was a problem hiding this comment.
🔍 Connection string removed only from Customer service, breaking local-dev parity with other services
The DefaultConnection string was removed from appsettings.json, but all four other services (Identity, Order, Product, Notification) still have theirs in their respective appsettings.json files. Running the Customer service locally without Docker (e.g. dotnet run) will pass null to UseNpgsql() at src/Services/Customer/Customer.API/Program.cs:14, causing a runtime exception on first DB access. The docker-compose.yml at src/docker-compose.yml:43 provides the value for containerized runs, so this only affects local development. If the intent is to externalize config, consider doing it consistently across all services or adding an appsettings.Development.json with a local fallback.
Was this helpful? React with 👍 or 👎 to provide feedback.
There was a problem hiding this comment.
This removal is intentional: the containerization playbook this PR follows externalizes config, so the connection string comes only from the ConnectionStrings__DefaultConnection env var (which docker-compose.yml already supplies). The trade-off you note — bare dotnet run without Docker now needs the env var or an appsettings.Development.json fallback — is accepted, and applying the same treatment to the other four services is deliberately out of scope to keep this PR to Customer only. That consistency cleanup would be a good follow-up.
Summary
Containerizes the Customer service into a hardened, config-externalized image with liveness/readiness probes, wired into the existing compose stack. Scoped to Customer only.
Dockerfile (
Services/Customer/Customer.API/Dockerfile) — replaces the previous basic single-stage file with a hardened multi-stage build:sdk:10.0build stage restores from per-project.csprojCOPYs (layer-cached) thendotnet publish.aspnet:10.0runtime stage installscurl(not in the aspnet image, needed by HEALTHCHECK), runs as non-rootUSER $APP_UID, and adds aHEALTHCHECKprobing/health.5002(ENV ASPNETCORE_URLS=http://+:5002); remap externally via-p. Not build-time interpolated (avoids the healthcheck-probes-wrong-port pitfall).Health endpoints (
Program.cs):/healthzis preserved as a liveness alias. HEALTHCHECK targets/health(liveness), not/ready, to avoid restart loops on transient DB outages.csproj — adds
Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore(10.*) forAddDbContextCheck.Config — removes the hardcoded
ConnectionStrings:DefaultConnection(Host=localhost;...;Password=postgres) fromappsettings.json; the connection string comes only from theConnectionStrings__DefaultConnectionenv var that compose already supplies..dockerignore — added at the build-context root (
src/) to keep localbin//obj//secrets out of the image.compose —
customer-serviceblock already present and correct (port 5002,depends_onpostgres+rabbitmq, connection string via env); verified, no edit needed.The pre-existing
..\..\Shared\*project references are left as-is (they build with only an MSB9008 warning) to keep this PR scoped.Verification (real Docker)
docker build— succeeds, image built.GET /health→ 200 Healthy,GET /healthz→ 200,GET /ready→ 503 Unhealthy.GET /ready→ 200 Healthy.docker inspecthealth status → healthy.docker exec ... id→uid=1654(app)(non-root).Link to Devin session: https://partner-workshops.devinenterprise.com/sessions/0e1be058efc4489ba39fc83d84d720e3
Requested by: @mbatchelor81