-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDockerfile
More file actions
135 lines (124 loc) · 6.73 KB
/
Copy pathDockerfile
File metadata and controls
135 lines (124 loc) · 6.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# StackAlchemist Multi-Component Dockerfile
# This file uses multi-stage builds and targets to build the Web, Engine, and Worker.
# ==========================================
# STAGE 1: NEXT.JS FRONTEND (WEB)
# ==========================================
FROM node:26-alpine AS web-builder
RUN apk add --no-cache git
WORKDIR /app
# Accept public env vars at build time so Next.js bakes them into the bundle.
# NEXT_PUBLIC_* vars are read at module scope (e.g. layout.tsx `isTestSite`)
# which means they must be present during `next build`, not just at runtime.
# Missing IS_TEST_SITE here is what historically broke the test-mirror noindex.
ARG NEXT_PUBLIC_APP_URL=https://test.stackalchemist.app
ARG NEXT_PUBLIC_IS_TEST_SITE=false
ENV NEXT_PUBLIC_APP_URL=$NEXT_PUBLIC_APP_URL
ENV NEXT_PUBLIC_IS_TEST_SITE=$NEXT_PUBLIC_IS_TEST_SITE
ARG NEXT_PUBLIC_SUPABASE_URL
ARG NEXT_PUBLIC_SUPABASE_ANON_KEY
ARG NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY
ARG NEXT_PUBLIC_PLAUSIBLE_DOMAIN
ENV NEXT_PUBLIC_SUPABASE_URL=$NEXT_PUBLIC_SUPABASE_URL
ENV NEXT_PUBLIC_SUPABASE_ANON_KEY=$NEXT_PUBLIC_SUPABASE_ANON_KEY
ENV NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=$NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY
ENV NEXT_PUBLIC_PLAUSIBLE_DOMAIN=$NEXT_PUBLIC_PLAUSIBLE_DOMAIN
# Copy manifests first so the install layer is cached independently of source.
COPY src/StackAlchemist.Web/package.json src/StackAlchemist.Web/package-lock.json ./
# Install all dependencies. --ignore-scripts skips postinstall (setup-env-safe.mjs)
# which requires the full scripts/ dir that isn't copied until the next step.
RUN npm install --include=dev --ignore-scripts
COPY src/StackAlchemist.Web/ .
# Docs, blog, compare, and solutions pages resolve their markdown via
# process.cwd()/../../<folder> at build time. CWD is /app, so these trees must
# live at /docs and /content for generateStaticParams + generateMetadata to read.
COPY docs/ /docs/
COPY content/ /content/
# Build the Next.js app and clean build cache.
# We invoke next build directly because the npm script wrapper
# (scripts/build-wrapper.mjs) is only needed on Windows+pnpm.
# --webpack opts out of Turbopack (Next 16 default); the custom webpack hook
# in next.config.ts (resolve.symlinks=false) only runs under webpack and is
# load-bearing for static prerendering on Windows local dev — keep webpack
# everywhere so Linux CI and Windows local stay in sync.
RUN npx next build --webpack \
&& rm -rf /root/.npm /tmp/*
FROM node:26-alpine AS web
# Install wget for production health checks
RUN apk add --no-cache wget
WORKDIR /app
ENV NODE_ENV=production
ENV HOSTNAME=0.0.0.0
ENV PORT=3000
COPY --from=web-builder /app/.next/standalone ./
COPY --from=web-builder /app/.next/static ./.next/static
COPY --from=web-builder /app/public ./public
EXPOSE 3000
CMD ["node", "server.js"]
# ==========================================
# STAGE 2: .NET ENGINE (API)
# ==========================================
FROM mcr.microsoft.com/dotnet/sdk:10.0-resolute AS engine-builder
WORKDIR /src
COPY src/StackAlchemist.Engine/*.csproj ./StackAlchemist.Engine/
RUN dotnet restore ./StackAlchemist.Engine/StackAlchemist.Engine.csproj
COPY src/StackAlchemist.Engine/ ./StackAlchemist.Engine/
RUN dotnet publish ./StackAlchemist.Engine/StackAlchemist.Engine.csproj -c Release -o /app/publish
# NOTE: this used to be the slim `aspnet` runtime image. CompileWorkerService runs
# in-process here (promoted from Worker in Phase 4) and shells out to `dotnet build`,
# `npm`/`npx`, and — for PythonReact generations — `python`/pip/flake8/pytest. None of
# that exists on the aspnet runtime image, so every paid Tier-2/3 generation failed at
# the build step in production. Base on the SDK image (mirrors the worker stage below)
# and install the same Node + Python toolchain the build strategies invoke. Tradeoff:
# meaningfully larger image (SDK vs aspnet runtime) in exchange for generations that
# actually compile.
FROM mcr.microsoft.com/dotnet/sdk:10.0-resolute AS engine
RUN apt-get update && apt-get install -y --no-install-recommends \
wget \
python3 \
python3-pip \
&& ln -sf /usr/bin/python3 /usr/bin/python \
&& rm -rf /var/lib/apt/lists/*
# Node.js — PythonReactBuildStrategy runs `npm install`, `npm run lint`, and `npx tsc`
# against generated React frontends.
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && apt-get install -y nodejs
# flake8 + pytest are invoked directly by PythonReactBuildStrategy (not declared in the
# generated project's requirements.txt), so they must be preinstalled in the image.
RUN python3 -m pip install --no-cache-dir --break-system-packages flake8 pytest
ENV ASPNETCORE_URLS=http://+:80
WORKDIR /app
COPY --from=engine-builder /app/publish .
# Handlebars template sets are loaded from disk at runtime and are NOT part of the
# published DLL output. Copy them next to the entrypoint — TemplatesRootResolver probes
# <BaseDirectory>/StackAlchemist.Templates first, which is /app here. Without this the
# engine reports "Template set ... not found. Available: none" and all codegen fails.
COPY src/StackAlchemist.Templates/ ./StackAlchemist.Templates/
EXPOSE 80
EXPOSE 443
ENTRYPOINT ["dotnet", "StackAlchemist.Engine.dll"]
# ==========================================
# STAGE 3: .NET WORKER (COMPILE GUARANTEE)
# ==========================================
FROM mcr.microsoft.com/dotnet/sdk:10.0-resolute AS worker-builder
WORKDIR /src
# Worker references Engine — copy both .csproj files before restore so the
# dependency graph can be resolved, then copy full source for both projects.
COPY src/StackAlchemist.Engine/*.csproj ./StackAlchemist.Engine/
COPY src/StackAlchemist.Worker/*.csproj ./StackAlchemist.Worker/
RUN dotnet restore ./StackAlchemist.Worker/StackAlchemist.Worker.csproj
COPY src/StackAlchemist.Engine/ ./StackAlchemist.Engine/
COPY src/StackAlchemist.Worker/ ./StackAlchemist.Worker/
RUN dotnet publish ./StackAlchemist.Worker/StackAlchemist.Worker.csproj -c Release -o /app/publish
FROM mcr.microsoft.com/dotnet/sdk:10.0-resolute AS worker
# Note: Worker needs SDK to run 'dotnet build' on generated repos
WORKDIR /app
COPY --from=worker-builder /app/publish .
# Install Node.js in the worker container so it can run 'npm build' on generated repos
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && apt-get install -y nodejs
# Not currently deployed (see docker-compose.*.yml — compile pipeline runs in-process
# in the engine stage above), but kept buildable as a future scale-out host, so it
# needs the same Python toolchain PythonReactBuildStrategy invokes.
RUN apt-get update && apt-get install -y --no-install-recommends python3 python3-pip \
&& ln -sf /usr/bin/python3 /usr/bin/python \
&& rm -rf /var/lib/apt/lists/*
RUN python3 -m pip install --no-cache-dir --break-system-packages flake8 pytest
ENTRYPOINT ["dotnet", "StackAlchemist.Worker.dll"]