GCR deployment testing in progress - content type issue still remaining.

This commit is contained in:
2026-05-05 14:42:03 +05:00
parent 40fe69ed65
commit f8112f897e
22 changed files with 348 additions and 2431 deletions
+30 -58
View File
@@ -1,98 +1,70 @@
# ─────────────────────────────────────────────────────────────────────────────
# Stage 1 — npm install (Tailwind CLI)
# The .NET SDK stage needs node_modules present before running dotnet publish
# because the MSBuild Tailwind target calls `npx @tailwindcss/cli` during build.
#
# We use the official node:24-slim image here. This means the npm that ships
# with Node 24 (npm 10.x) is used as-is — we deliberately do NOT run
# `npm install -g npm@latest` anywhere. Running a global npm self-upgrade
# inside a Debian container is a known reliability hazard: npm replaces its
# own running binaries mid-flight, which can cause EBUSY / ENOENT failures
# that corrupt the install. The bundled npm is current enough.
# Uses node:24-alpine for a small image. npm ci is used for reproducible,
# fast installs from the lockfile.
# ─────────────────────────────────────────────────────────────────────────────
FROM node:24-slim AS npm-install
FROM node:24-alpine AS npm-install
WORKDIR /npm
COPY Htmx.ApiDemo/package.json .
# npm ci requires package-lock.json; if it doesn't exist yet, run
# `npm install` locally first to generate it, then commit it to the repo.
COPY Htmx.ApiDemo/package-lock.json* ./
# ci is preferred over install in CI/Docker contexts: respects package-lock,
# clean installs, and is faster.
COPY Htmx.ApiDemo/package.json Htmx.ApiDemo/package-lock.json* ./
RUN npm ci
# ─────────────────────────────────────────────────────────────────────────────
# Stage 2 — AOT publish
# Uses the full .NET 10 SDK image. Node/npx must also be present here so the
# Tailwind MSBuild target can run. We install Node 24 from NodeSource using
# the official setup script and then immediately install nodejs via apt — no
# subsequent `npm install -g npm` step, for the same reason as above.
# Uses the Alpine SDK image so the binary is linked against musl libc,
# making it compatible with the Alpine runtime image in Stage 3.
#
# Alpine packages are cached via BuildKit mount cache — after the first build
# `apk add` is near-instant because the package index and downloads are
# reused from the local cache rather than re-fetched from the network.
# ─────────────────────────────────────────────────────────────────────────────
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS publish
FROM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS publish
# Install Node.js 24 (required by the Tailwind MSBuild target at publish time).
# We download the NodeSource setup script to a file first so we can inspect it
# if needed, then run it. Using `| bash -` directly is convenient but hides
# the script from audit — the two-step form is safer in CI/CD contexts.
RUN apt-get update && \
apt-get install -y --no-install-recommends curl ca-certificates && \
curl -fsSL https://deb.nodesource.com/setup_24.x -o /tmp/nodesource_setup.sh && \
bash /tmp/nodesource_setup.sh && \
apt-get install -y --no-install-recommends nodejs && \
rm /tmp/nodesource_setup.sh && \
rm -rf /var/lib/apt/lists/*
# Intentionally no `npm install -g npm` — see Stage 1 note above.
# Install AOT linker tools and Node.js (for the Tailwind MSBuild target).
# --mount=type=cache keeps the apk package cache between builds on this machine.
RUN --mount=type=cache,target=/var/cache/apk \
apk add --no-cache clang lld musl-dev build-base nodejs npm
WORKDIR /src
# Copy solution and project files first so NuGet restore is cached separately
# Copy project files first NuGet restore layer is cached until these change.
COPY Htmx.slnx .
COPY Htmx.ApiDemo/Htmx.ApiDemo.csproj Htmx.ApiDemo/
COPY Htmx.SourceGenerator/Htmx.SourceGenerator.csproj Htmx.SourceGenerator/
RUN dotnet restore Htmx.ApiDemo/Htmx.ApiDemo.csproj
RUN dotnet restore Htmx.ApiDemo/Htmx.ApiDemo.csproj -r linux-musl-x64
# Bring in the pre-installed node_modules from Stage 1.
# These were installed with `npm ci` on Node 24 — no npm upgrade was performed.
# Bring in pre-installed node_modules from Stage 1.
COPY --from=npm-install /npm/node_modules Htmx.ApiDemo/node_modules
# Copy the rest of the source
COPY . .
# AOT publish — output goes to /publish
# AOT publish targeting musl so the binary runs on Alpine.
RUN dotnet publish Htmx.ApiDemo/Htmx.ApiDemo.csproj \
-c Release \
-r linux-musl-x64 \
--no-restore \
--self-contained true \
-o /publish
# ─────────────────────────────────────────────────────────────────────────────
# Stage 3 — Runtime image
# runtime-deps provides the native library dependencies (libc, libssl, libicu)
# that the AOT binary links against at runtime — no .NET runtime needed.
# Stage 3 — Runtime image (~12 MB base vs ~100 MB on Debian)
# runtime-deps:alpine provides only the native libs the AOT binary needs.
# No .NET runtime is included — the binary is fully self-contained.
# ─────────────────────────────────────────────────────────────────────────────
FROM mcr.microsoft.com/dotnet/runtime-deps:10.0 AS runtime
# Run as non-root for security hardening (recommended by Cloud Run docs)
RUN addgroup --system appgroup && adduser --system --ingroup appgroup appuser
FROM mcr.microsoft.com/dotnet/runtime-deps:10.0-alpine AS runtime
WORKDIR /app
COPY --from=publish /publish .
# Ensure the binary is executable
RUN chmod +x ./Htmx.ApiDemo
# Cloud Run injects PORT (default 8080).
# ASP.NET Core reads ASPNETCORE_HTTP_PORTS, not PORT directly, so we set it.
# The entrypoint script below maps $PORT → ASPNETCORE_HTTP_PORTS at startup.
COPY GCR/entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
# ASP.NET Core reads ASPNETCORE_HTTP_PORTS directly — no entrypoint script needed.
ENV ASPNETCORE_HTTP_PORTS=8080
# Transfer ownership so the app can write temp files if needed
RUN chown -R appuser:appgroup /app
USER appuser
# Use the built-in non-root user provided by the official .NET Alpine image.
USER $APP_UID
EXPOSE 8080
ENTRYPOINT ["/entrypoint.sh"]
ENTRYPOINT ["./Htmx.ApiDemo"]