71 lines
3.6 KiB
Docker
71 lines
3.6 KiB
Docker
# ─────────────────────────────────────────────────────────────────────────────
|
|
# Stage 1 — npm install (Tailwind CLI)
|
|
# Uses node:24-alpine for a small image. npm ci is used for reproducible,
|
|
# fast installs from the lockfile.
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
FROM node:24-alpine AS npm-install
|
|
|
|
WORKDIR /npm
|
|
COPY Htmx.ApiDemo/package.json Htmx.ApiDemo/package-lock.json* ./
|
|
RUN npm ci
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────────
|
|
# Stage 2 — AOT publish
|
|
# 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-alpine AS publish
|
|
|
|
# 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 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 -r linux-musl-x64
|
|
|
|
# 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 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 (~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-alpine AS runtime
|
|
|
|
WORKDIR /app
|
|
COPY --from=publish /publish .
|
|
|
|
# Cloud Run injects PORT (default 8080).
|
|
# ASP.NET Core reads ASPNETCORE_HTTP_PORTS directly — no entrypoint script needed.
|
|
ENV ASPNETCORE_HTTP_PORTS=8080
|
|
|
|
# Use the built-in non-root user provided by the official .NET Alpine image.
|
|
USER $APP_UID
|
|
|
|
EXPOSE 8080
|
|
|
|
ENTRYPOINT ["./Htmx.ApiDemo"]
|