Repository navigation
Expand file tree
/
Copy pathDockerfile
More file actions
108 lines (97 loc) · 6.98 KB
/
Copy pathDockerfile
File metadata and controls
108 lines (97 loc) · 6.98 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
98
99
100
101
102
103
104
105
106
107
108
# syntax=ghcr.io/k2b-dev/mirror/docker/dockerfile:1.7-labs@sha256:b99fecfe00268a8b556fad7d9c37ee25d716ae08a5d7320e6d51c4dd83246894
# Per-app production image.
#
# docker build --build-arg APP_ID=<id> \
# --build-arg CLOUD_VERSION=<semver> --build-arg CLOUD_RELEASE=<tag> -t cloud-<id> .
#
# `deps` and `deps-dev` are independent of APP_ID and of application sources,
# so the install and the @k2b/ui build are cached across all release apps.
# `build` and `runtime` are app-specific. The image is built natively per
# architecture: the native canvas binary must match the target platform.
# ──────────────────────────────────────────────────────────────────────
# Stage 1: deps — production install (cache-shared, ships to runtime builds).
# ──────────────────────────────────────────────────────────────────────
FROM ghcr.io/k2b-dev/mirror/oven/bun:1.4.4-alpine@sha256:4cf82f5686b196504fe119db3fcd9185b191f82ece82c40680e597228ec6070a AS deps
WORKDIR /app
COPY package.json bun.lock bunfig.toml ./
COPY patches/ patches/
COPY --parents packages/*/package.json pwas/*/package.json fixtures/*/package.json docs-site/package.json ./
# --production keeps CI/dev-only tools (Biome, TypeScript, @types, etc.) out
# of production images. This avoids optional platform binaries in multi-arch
# Docker installs while preserving runtime/build dependencies.
# --ignore-scripts: bun-plugin-tailwind declares `bun` as a peer dep, which
# pulls the npm `bun` package whose postinstall extracts a platform binary
# and fails inside the build sandbox. We don't need it (the base image has bun).
RUN bun install --frozen-lockfile --ignore-scripts --production
# ──────────────────────────────────────────────────────────────────────
# Stage 2: deps-dev — build toolchain + compiled @k2b/ui (cache-shared).
# ──────────────────────────────────────────────────────────────────────
FROM deps AS deps-dev
ENV NODE_ENV=production
# @k2b/ui's stylesheet is compiled in this disposable stage, so install its
# build-time toolchain here. Only packages/ui and the @k2b/ssr source its
# declarations import are copied: this layer must stay identical for every
# APP_ID and for source changes elsewhere.
RUN bun install --frozen-lockfile --ignore-scripts
COPY tsconfig.base.json ./
COPY packages/ssr/src packages/ssr/src
COPY packages/ui packages/ui
RUN bun run --cwd packages/ui build
# ──────────────────────────────────────────────────────────────────────
# Stage 3: build — bundle one app into /app/dist.
# ──────────────────────────────────────────────────────────────────────
FROM deps-dev AS build
ARG APP_ID
ARG CLOUD_VERSION=0.0.0-local
ARG CLOUD_RELEASE=local
ENV APP_ID=${APP_ID} \
CLOUD_VERSION=${CLOUD_VERSION} \
CLOUD_RELEASE=${CLOUD_RELEASE}
COPY packages packages
COPY styles.css ./
RUN bun run packages/cloud/scripts/build.ts
# ──────────────────────────────────────────────────────────────────────
# Stage 4: geoip-snapshot — archived DB-IP gzip files.
# ──────────────────────────────────────────────────────────────────────
# Data only: .github/mirror-images.sh pushes it for linux/amd64, maybe as an
# index with an attestation, so every target platform takes that manifest.
FROM --platform=linux/amd64 ghcr.io/k2b-dev/mirror/dbip-lite:2026-10 AS geoip-snapshot
# ──────────────────────────────────────────────────────────────────────
# Stage 5: geoip — pinned snapshot, independent of application sources.
# ──────────────────────────────────────────────────────────────────────
FROM ghcr.io/k2b-dev/mirror/oven/bun:1.4.4-alpine@sha256:4cf82f5686b196504fe119db3fcd9185b191f82ece82c40680e597228ec6070a AS geoip
ARG APP_ID
# DB-IP Lite, CC BY 4.0; attribution in THIRD_PARTY_NOTICES.md.
# Only Core reads it; every build mounts the snapshot, but only Core checks and unpacks it.
# DB-IP keeps only two months; .github/mirror-images.sh keeps every pinned month in the mirror.
# bun scripts/geoip-snapshot.ts moves the pin.
RUN --mount=type=bind,from=geoip-snapshot,target=/snapshot set -eu; mkdir -p /geoip; \
if [ "$APP_ID" = "core" ]; then \
cd /snapshot; \
echo "c839d407f85a1e0bddba354cef16b2c398182d1c34ed8d985555dce134b36b14 dbip-city-lite.mmdb.gz" | sha256sum -c -; \
echo "6cdde02baa8c1bd619ab84c2e505ecd91d45288b5a87faadf1b7c41525a17a94 dbip-asn-lite.mmdb.gz" | sha256sum -c -; \
gunzip -c dbip-city-lite.mmdb.gz > /geoip/dbip-city-lite.mmdb; \
gunzip -c dbip-asn-lite.mmdb.gz > /geoip/dbip-asn-lite.mmdb; \
fi
# ──────────────────────────────────────────────────────────────────────
# Stage 6: runtime — only the bundled output + bun runtime.
# ──────────────────────────────────────────────────────────────────────
FROM ghcr.io/k2b-dev/mirror/oven/bun:1.4.4-alpine@sha256:4cf82f5686b196504fe119db3fcd9185b191f82ece82c40680e597228ec6070a AS runtime
WORKDIR /app
ARG APP_ID
ARG CLOUD_VERSION=0.0.0-local
ARG CLOUD_RELEASE=local
# Only Assistant needs the server-owned code execution browser.
RUN if [ "$APP_ID" = "assistant" ]; then apk add --no-cache chromium; fi
ENV NODE_ENV=production \
HOME=/home/bun \
CLOUD_VERSION=${CLOUD_VERSION} \
CLOUD_RELEASE=${CLOUD_RELEASE} \
CLOUD_CLI_CHROMIUM=/usr/bin/chromium
COPY --from=build --chown=bun:bun /app/dist ./
# Bun.mmap opens files read-write, so the runtime user owns them like dist;
# Core maps them privately and never writes.
COPY --from=geoip --chown=bun:bun /geoip /app/geoip
USER bun
EXPOSE 3000
CMD ["bun", "server.js"]