53 lines
2.2 KiB
Docker
53 lines
2.2 KiB
Docker
# Standalone image for the management UI — separate from the main app's
|
|
# Dockerfile (see ../Dockerfile) since this needs the Docker CLI itself
|
|
# baked in (it shells out to `docker compose`/`docker exec` against the
|
|
# host's dockerd via the mounted socket — see src/lib/docker.ts), which
|
|
# the main business app never needs.
|
|
#
|
|
# Only one instance of this ever runs (unlike the business image, which
|
|
# is built once and reused across every business — see
|
|
# stacks/blake-heritage/compose.yaml's own note) so a per-deploy `build:`
|
|
# in stacks/manager/compose.yaml, rather than a separately tagged image,
|
|
# is the simpler choice here.
|
|
|
|
FROM node:22-alpine AS deps
|
|
WORKDIR /app
|
|
COPY package.json package-lock.json* ./
|
|
RUN npm install
|
|
|
|
FROM node:22-alpine AS builder
|
|
WORKDIR /app
|
|
COPY --from=deps /app/node_modules ./node_modules
|
|
COPY . .
|
|
RUN npm run build
|
|
|
|
FROM node:22-alpine AS runner
|
|
WORKDIR /app
|
|
ENV NODE_ENV=production
|
|
|
|
# The Docker CLI + compose plugin — this container never runs its own
|
|
# Docker daemon, it only talks to the HOST's via the socket mounted in
|
|
# stacks/infra/compose.yaml's manager service (docker.sock).
|
|
RUN apk add --no-cache docker-cli docker-cli-compose
|
|
|
|
RUN addgroup --system --gid 1001 nodejs && adduser --system --uid 1001 manager
|
|
|
|
COPY --from=builder --chown=manager:nodejs /app/node_modules ./node_modules
|
|
COPY --from=builder --chown=manager:nodejs /app/.next ./.next
|
|
COPY --from=builder --chown=manager:nodejs /app/public ./public
|
|
COPY --from=builder --chown=manager:nodejs /app/package.json ./package.json
|
|
COPY --from=builder --chown=manager:nodejs /app/next.config.ts ./next.config.ts
|
|
|
|
# Deliberately still root at runtime, not the `manager` user created
|
|
# above — this container's whole job is calling the Docker CLI against
|
|
# the host's socket, and on most VPS setups only root (or a user in the
|
|
# `docker` group, which would need to be created with a matching host
|
|
# GID) can use that socket. Worth being explicit about: root inside this
|
|
# container plus the mounted socket effectively means root on the host —
|
|
# this app must stay behind its own login (see src/lib/auth.ts) and never
|
|
# be exposed without that gate.
|
|
EXPOSE 3000
|
|
ENV PORT=3000
|
|
|
|
ENTRYPOINT ["node_modules/.bin/next", "start", "-p", "3000"]
|