build: skip container npm, ship prebuilt dist for portainer showcase
The Portainer host keeps failing on `npm ci` inside the build stage (both Alpine+libc6-compat and Debian slim exited 1 without ever surfacing the real error to us). For a dev showcase this isn't worth chasing — the dev machine is the source of truth for the built output anyway. - Dockerfile: drop the Node build stage. Image is just nginx:1.27.3-alpine with /dist copied in. No npm inside the container. - docker-compose.yml: drop the production hardening (read_only, tmpfs, security_opt, resource caps) and the container_name. Dev-only, don't inhibit things. - .gitignore / .dockerignore: stop ignoring dist/ — it's committed now. - README: document the `npm run build && commit && push` release flow and note what to reinstate when this graduates to real production. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
36
Dockerfile
36
Dockerfile
@@ -1,35 +1,21 @@
|
||||
# syntax=docker/dockerfile:1.7
|
||||
# Multi-stage build: Node builds the Vite SPA, Nginx serves the static output.
|
||||
# Pinned tags only — no :latest, no floating minors.
|
||||
# Dev-showcase image for the Portainer stack. No container-side build —
|
||||
# the `dist/` directory is built locally (`npm run build`) and committed,
|
||||
# then copied straight into nginx. This sidesteps the Node/native-binding
|
||||
# fights that kept breaking `npm ci` on the Portainer host.
|
||||
#
|
||||
# Not how the site should ship to real production, but fine for a showcase
|
||||
# stack where the dev machine is the source of truth for the built output.
|
||||
|
||||
# ── 1. Build ───────────────────────────────────────────────────────────────
|
||||
# Debian slim (glibc) for the build stage. Alpine/musl works in theory with
|
||||
# libc6-compat, but Tailwind v4 oxide + lightningcss + rolldown prebuilt
|
||||
# .node bindings keep finding new ways to fail there. Debian slim is the
|
||||
# known-good path and the build stage is thrown away after COPY --from.
|
||||
FROM node:24.15.0-bookworm-slim AS build
|
||||
WORKDIR /app
|
||||
FROM nginx:1.27.3-alpine
|
||||
|
||||
# Copy lockfile first so `npm ci` layer caches when only source changes.
|
||||
COPY package.json package-lock.json ./
|
||||
RUN npm ci --no-audit --no-fund
|
||||
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
|
||||
# ── 2. Serve ───────────────────────────────────────────────────────────────
|
||||
FROM nginx:1.27.3-alpine AS serve
|
||||
|
||||
# Strip the default site; our config owns /etc/nginx/conf.d/default.conf.
|
||||
# Our site config owns the default server block.
|
||||
RUN rm /etc/nginx/conf.d/default.conf
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
# Drop the built SPA into the document root.
|
||||
COPY --from=build /app/dist /usr/share/nginx/html
|
||||
# Prebuilt Vite output.
|
||||
COPY dist /usr/share/nginx/html
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
# Alpine ships busybox wget — avoids pulling curl just for healthchecks.
|
||||
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
||||
CMD wget -q -O- http://127.0.0.1/health || exit 1
|
||||
|
||||
Reference in New Issue
Block a user