-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathDockerfile
More file actions
97 lines (90 loc) · 4.46 KB
/
Copy pathDockerfile
File metadata and controls
97 lines (90 loc) · 4.46 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
# syntax=docker/dockerfile:1
# =============================================================================
# SafeOS Guardian - container build
#
# Backend: the package is ESM ("type":"module") with bundler-style extensionless
# imports (tsconfig moduleResolution: "bundler"), so the compiled dist/ is NOT
# directly runnable by `node` (it throws ERR_MODULE_NOT_FOUND on the first
# relative import). The supported runtime path is `tsx`, which is exactly what
# `npm run dev` uses. The backend image runs the TypeScript sources through tsx.
#
# Frontend: apps/guardian-ui is a Next.js static export (output: 'export'), so
# `next build` emits out/ and it is served by nginx. `next start` does not serve
# an exported app and is not used here.
# =============================================================================
# -----------------------------------------------------------------------------
# base: Node 20 + toolchain for native modules (better-sqlite3, sharp)
# -----------------------------------------------------------------------------
FROM node:20-alpine AS base
RUN apk add --no-cache python3 make g++ sqlite-dev
WORKDIR /app
# -----------------------------------------------------------------------------
# deps: install backend (root) dependencies, including devDeps (tsx, typescript)
# Do not set NODE_ENV=production here, or npm would prune tsx and the backend
# would have no runtime.
# -----------------------------------------------------------------------------
FROM base AS deps
COPY package.json package-lock.json* ./
RUN npm install --legacy-peer-deps
# -----------------------------------------------------------------------------
# backend: runtime image - runs src/ via tsx
# -----------------------------------------------------------------------------
FROM node:20-alpine AS backend
WORKDIR /app
# Runtime libraries for the better-sqlite3 / sharp native bindings
RUN apk add --no-cache sqlite-libs libstdc++
COPY --from=deps /app/node_modules ./node_modules
COPY package.json tsconfig.json ./
COPY src ./src
RUN mkdir -p /app/db_data
ENV NODE_ENV=production \
SAFEOS_PORT=3001 \
SAFEOS_DB_PATH=/app/db_data/safeos.sqlite3
EXPOSE 3001
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=5 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3001/health || exit 1
# tsx runs the ESM TypeScript directly. Run the API server entry, which
# self-starts via its import.meta main-guard. Compose sets `init: true` so tini
# forwards SIGTERM to the process for the server's graceful-shutdown handler.
CMD ["npx", "tsx", "src/api/server.ts"]
# -----------------------------------------------------------------------------
# builder-frontend: build the Next.js static export (out/)
# -----------------------------------------------------------------------------
FROM base AS builder-frontend
WORKDIR /app/apps/guardian-ui
COPY apps/guardian-ui/package.json apps/guardian-ui/package-lock.json* ./
RUN npm install --legacy-peer-deps
# NEXT_PUBLIC_* are inlined at build time, so the API/WS URLs the browser uses
# must be passed as build args (not runtime env).
ARG NEXT_PUBLIC_API_URL=http://localhost:3001
ARG NEXT_PUBLIC_WS_URL=ws://localhost:3001
ENV NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL \
NEXT_PUBLIC_WS_URL=$NEXT_PUBLIC_WS_URL \
NEXT_TELEMETRY_DISABLED=1 \
NODE_ENV=production
COPY apps/guardian-ui ./
RUN npm run build
# -----------------------------------------------------------------------------
# frontend: nginx serving the static export on :3000
# -----------------------------------------------------------------------------
FROM nginx:alpine AS frontend
RUN rm -f /etc/nginx/conf.d/default.conf
COPY docker/nginx-guardian-ui.conf /etc/nginx/conf.d/guardian-ui.conf
COPY --from=builder-frontend /app/apps/guardian-ui/out /usr/share/nginx/html
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/ || exit 1
# -----------------------------------------------------------------------------
# development: full stack with hot reload (api + ui via concurrently)
# -----------------------------------------------------------------------------
FROM base AS development
WORKDIR /app
COPY package.json package-lock.json* ./
RUN npm install --legacy-peer-deps
COPY apps/guardian-ui/package.json ./apps/guardian-ui/
RUN cd apps/guardian-ui && npm install --legacy-peer-deps
COPY . .
ENV NODE_ENV=development \
SAFEOS_PORT=3001
EXPOSE 3000 3001
CMD ["npm", "run", "dev"]