67 lines
2.3 KiB
Text
67 lines
2.3 KiB
Text
|
|
# syntax=docker/dockerfile:1
|
||
|
|
#
|
||
|
|
# Vinterliste — single-image container.
|
||
|
|
# Build stage compiles the frontend with Vite; runtime image runs Bun.
|
||
|
|
|
||
|
|
ARG BUN_VERSION=1.3
|
||
|
|
ARG BUILD_DATE
|
||
|
|
ARG GIT_REVISION
|
||
|
|
|
||
|
|
# ---- Builder ---------------------------------------------------------------
|
||
|
|
FROM docker.io/oven/bun:${BUN_VERSION} AS builder
|
||
|
|
WORKDIR /app
|
||
|
|
|
||
|
|
# Install dependencies first so they cache independently of source.
|
||
|
|
COPY package.json bun.lockb* ./
|
||
|
|
RUN bun install --frozen-lockfile || bun install
|
||
|
|
|
||
|
|
# Copy the rest of the source and build the frontend bundle.
|
||
|
|
COPY tsconfig.json ./
|
||
|
|
COPY shared ./shared
|
||
|
|
COPY server ./server
|
||
|
|
COPY frontend ./frontend
|
||
|
|
RUN bun run build:frontend
|
||
|
|
|
||
|
|
# ---- Runtime ---------------------------------------------------------------
|
||
|
|
FROM docker.io/oven/bun:${BUN_VERSION}-slim
|
||
|
|
WORKDIR /app
|
||
|
|
|
||
|
|
ARG BUILD_DATE
|
||
|
|
ARG GIT_REVISION
|
||
|
|
|
||
|
|
# OCI labels keep the image traceable even when tagged :latest.
|
||
|
|
LABEL org.opencontainers.image.title="vinterliste" \
|
||
|
|
org.opencontainers.image.description="End-to-end encrypted winter activity list" \
|
||
|
|
org.opencontainers.image.source="https://example.invalid/vinterliste" \
|
||
|
|
org.opencontainers.image.created="${BUILD_DATE}" \
|
||
|
|
org.opencontainers.image.revision="${GIT_REVISION}"
|
||
|
|
|
||
|
|
# Bake the same info into /etc/build-info so a running container can report it.
|
||
|
|
RUN printf 'build_date=%s\ngit_revision=%s\n' "${BUILD_DATE:-unknown}" "${GIT_REVISION:-unknown}" > /etc/build-info
|
||
|
|
|
||
|
|
# Copy production artefacts only. node_modules is reproducible from package.json,
|
||
|
|
# but we install fresh to keep the runtime image small and unambiguous.
|
||
|
|
COPY package.json bun.lockb* ./
|
||
|
|
RUN bun install --frozen-lockfile --production || bun install --production
|
||
|
|
|
||
|
|
COPY --from=builder /app/shared ./shared
|
||
|
|
COPY --from=builder /app/server ./server
|
||
|
|
COPY --from=builder /app/frontend/dist ./frontend/dist
|
||
|
|
|
||
|
|
# SQLite WAL files live in /app/data, which is the documented mount point.
|
||
|
|
RUN mkdir -p /app/data && chown -R bun:bun /app/data
|
||
|
|
VOLUME /app/data
|
||
|
|
|
||
|
|
ENV NODE_ENV=production \
|
||
|
|
PORT=3000 \
|
||
|
|
VINTERLISTE_DB=/app/data/vinterliste.db \
|
||
|
|
BUILD_DATE=${BUILD_DATE} \
|
||
|
|
GIT_REVISION=${GIT_REVISION}
|
||
|
|
|
||
|
|
EXPOSE 3000
|
||
|
|
USER bun
|
||
|
|
|
||
|
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||
|
|
CMD bun -e "fetch('http://localhost:3000/api/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"
|
||
|
|
|
||
|
|
CMD ["bun", "run", "server/index.ts"]
|