-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathDockerfile
More file actions
89 lines (79 loc) · 3.73 KB
/
Copy pathDockerfile
File metadata and controls
89 lines (79 loc) · 3.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
# syntax=docker/dockerfile:1.7
# Multi-stage build for Azure Container Apps. Produces an image that runs
# Next's standalone `node server.js` with a sidecar `cron` daemon for
# scheduled tasks (Azure has no platform-side cron facility). The cron
# daemon `curl`s the same `/api/cron/*` HTTP routes that exist on every
# deploy target.
#
# Vercel ignores this file entirely and uses its own build pipeline. Vercel
# also no longer fires the cron routes — `vercel.json` is intentionally
# empty of `crons` entries. The /api/cron/* routes still exist and are
# `Bearer ${CRON_SECRET}`-authenticated, so they can be hit by anyone with
# the secret if a future Vercel-side scheduler ever wants to.
ARG NODE_VERSION=22-slim
# ---- deps: install with the lockfile, cache the pnpm store --------------
FROM node:${NODE_VERSION} AS deps
RUN corepack enable
WORKDIR /app
COPY package.json pnpm-lock.yaml .npmrc* ./
RUN --mount=type=cache,id=pnpm,target=/root/.local/share/pnpm/store \
pnpm install --frozen-lockfile
# ---- build: compile Next + upload Sentry source maps --------------------
FROM node:${NODE_VERSION} AS build
RUN corepack enable
WORKDIR /app
ENV NEXT_TELEMETRY_DISABLED=1
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Build-time Sentry source-map upload. Pass via --build-arg in CI; left
# unset = no upload (Sentry's plugin silently skips).
ARG SENTRY_AUTH_TOKEN
ARG SENTRY_ORG
ARG SENTRY_PROJECT
ENV SENTRY_AUTH_TOKEN=${SENTRY_AUTH_TOKEN}
ENV SENTRY_ORG=${SENTRY_ORG}
ENV SENTRY_PROJECT=${SENTRY_PROJECT}
ENV CI=1
RUN pnpm build
# ---- runtime: minimal Node + Next standalone output + system cron -------
FROM node:${NODE_VERSION} AS runtime
WORKDIR /app
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
ENV PORT=3000
ENV HOSTNAME=0.0.0.0
# `cron` provides the daemon + crontab tooling; `curl` fires the per-tick
# HTTP requests against the local Next server; `gettext-base` provides
# `envsubst`, used by entrypoint.sh to inject CRON_SECRET into the crontab
# at boot. `ca-certificates` so curl can talk to https targets if any cron
# task ever needs to. --no-install-recommends keeps the image lean.
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
cron curl gettext-base ca-certificates \
&& rm -rf /var/lib/apt/lists/*
# Create a non-root user for the Next runtime. The cron daemon needs root
# (to read /etc/cron.d and switch to the user listed per line), so the
# CMD entrypoint runs as root and the crontab itself targets `nextjs` for
# each command.
RUN groupadd --system --gid 1001 nodejs \
&& useradd --system --uid 1001 --gid nodejs nextjs
# Standalone output already contains the minimal node_modules needed at
# runtime, plus the server entrypoint. Static assets and the public dir are
# copied separately per the Next docs. Owned by nextjs so the unprivileged
# user can actually read what it needs to serve.
COPY --from=build --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=build --chown=nextjs:nodejs /app/.next/static ./.next/static
COPY --from=build --chown=nextjs:nodejs /app/public ./public
# Cron pieces: entrypoint script + crontab template. Both stay root-owned;
# the entrypoint runs as root long enough to materialise the crontab and
# launch the cron daemon, then `exec node` becomes PID 1 (still root,
# because dropping privileges between `cron -f &` and `exec node` would
# orphan the daemon and complicate signal handling — accepted trade-off
# for an image that's not otherwise exposed).
COPY docker/entrypoint.sh ./entrypoint.sh
COPY docker/crontab.template /etc/cron.d/un-cron.template
RUN chmod +x ./entrypoint.sh
EXPOSE 3000
# Container Apps health probe hits /api/health (returns 200 + DB ping).
# entrypoint.sh stages the crontab, starts cron, then execs `node server.js`.
CMD ["./entrypoint.sh"]