93462b799c
Closes the three operational blockers from the production readiness review. deploy.sh now takes a database backup before it builds, stops or replaces anything, and aborts the deploy if the backup fails — so no deploy proceeds without a restore point. Dumps are gzipped and timestamped into /opt/job-tracker/backups (override with BACKUP_DIR), so one deploy never overwrites an earlier backup. Credentials come from the existing connection string and travel via MYSQL_PWD, never on the command line, so they cannot reach the process list or the deploy log. A dump that is empty or missing CREATE TABLE is rejected, because a truncated file that looks like a restore point is worse than none. SQLite deployments get their data volume tarred instead. Nothing is ever deleted automatically; retention is documented as manual. deploy/README.md documents backup creation, location, retention, database restore, application rollback, and when to use which — restore and rollback kept distinct, because a bad deploy usually needs only the rollback and restoring would discard everything written since the dump. Health checks now cover backend and frontend, which previously had none. GET /health is anonymous, cheap, and deliberately does not touch the database: a health check that queried MariaDB would restart a healthy backend whenever the database blipped, and would hand out an unauthenticated way to probe database availability. The backend image gains curl on the existing chromium apt layer, since the aspnet runtime ships neither curl nor wget. frontend now waits for backend to be healthy rather than merely started, because nginx proxies /api and refuses to start when the upstream cannot be resolved. Verified against real containers, no production data: backup from a seeded MariaDB 11; restore into a clean MariaDB 11 with rows identical; bad credentials and a missing connection string both abort non-zero and leave no partial file; SQLite volume backup produces a readable archive; backend and frontend both reach healthy; and a backend pointed at an unreachable database exits and is reported unhealthy, so a broken deploy cannot present as a running stack. Incidentally confirmed the earlier authorization work: with Auth:Require unset, /health returns 200 while /api/jobapplications returns 401. 393 backend tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
41 lines
1.4 KiB
Docker
41 lines
1.4 KiB
Docker
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
|
|
|
|
WORKDIR /src
|
|
|
|
COPY JobTrackerApi/JobTrackerApi.csproj JobTrackerApi/
|
|
COPY JobTrackerBackend/JobTrackerBackend.csproj JobTrackerBackend/
|
|
COPY Data/ Data/
|
|
COPY Models/ Models/
|
|
COPY JobTrackerApi/ JobTrackerApi/
|
|
COPY JobTrackerBackend/ JobTrackerBackend/
|
|
|
|
# Retry once after clearing NuGet caches. Transient download corruption on the
|
|
# build host can trip NU3008 ("package integrity check failed / has changed since
|
|
# it was signed") while restoring a transitive package; clearing the caches and
|
|
# re-downloading resolves it.
|
|
RUN dotnet publish JobTrackerApi/JobTrackerApi.csproj -c Release -o /app/publish /p:UseAppHost=false \
|
|
|| ( echo "Publish failed — clearing NuGet caches and retrying once..." \
|
|
&& dotnet nuget locals all --clear \
|
|
&& dotnet publish JobTrackerApi/JobTrackerApi.csproj -c Release -o /app/publish /p:UseAppHost=false )
|
|
|
|
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS runtime
|
|
|
|
WORKDIR /app
|
|
|
|
ENV ASPNETCORE_URLS=http://+:8080
|
|
ENV CV_PDF_BROWSER_PATH=/usr/bin/chromium
|
|
|
|
# curl is here for the container health check (/health). The aspnet runtime image ships
|
|
# neither curl nor wget, and this layer already exists for chromium.
|
|
RUN apt-get update \
|
|
&& apt-get install -y --no-install-recommends chromium curl \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
RUN mkdir -p /data
|
|
|
|
COPY --from=build /app/publish .
|
|
|
|
EXPOSE 8080
|
|
|
|
ENTRYPOINT ["dotnet","JobTrackerApi.dll"]
|