mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-09-13 18:32:12 +03:00
Validated in an isolated worktree against main: typecheck:core clean, 15/15 focused tests pass (docker-build-memory-budget, bun-support, resolve-next-build-bundler-flag). Root cause confirmed against the current workflow config (docker-publish.yml triggers on push to both main and release/v*, so this genuinely needed to target main). One out-of-scope change dropped before merging: config/alibaba-free-tier-allowlist.json's validUntil bump (2026-08-27 -> 2027-12-31) was unrelated to the Docker/Bun fix — reverted to the current value, keeping only the Docker/Bun/memory-guard changes this PR is actually about. Thanks for the thorough root-cause writeup and the worker-pool math.
176 lines
5.6 KiB
Docker
176 lines
5.6 KiB
Docker
# ── Multi-stage Dockerfile for Native Bun Runtime (web-latest-bun) ───────────
|
||
FROM oven/bun:1.4.0-slim AS base
|
||
WORKDIR /app
|
||
|
||
RUN apt-get update \
|
||
&& apt-get upgrade -y \
|
||
&& apt-get install -y --no-install-recommends \
|
||
build-essential \
|
||
python3 \
|
||
python-is-python3 \
|
||
make \
|
||
g++ \
|
||
libsecret-1-0 \
|
||
ca-certificates \
|
||
curl \
|
||
&& rm -rf /var/lib/apt/lists/*
|
||
|
||
# ── Builder stage (100% Bun Native Install & Build) ─────────────────────────
|
||
FROM base AS builder
|
||
WORKDIR /app
|
||
|
||
COPY . .
|
||
|
||
# Fast Bun native package install
|
||
RUN bun install --include=optional --quiet
|
||
|
||
# Compile native better-sqlite3 Node-API addon under Bun
|
||
RUN if [ -d "node_modules/better-sqlite3" ]; then \
|
||
(cd node_modules/better-sqlite3 && bunx node-gyp rebuild); \
|
||
fi
|
||
|
||
# Fetch tls-client-node native binary if script exists
|
||
RUN if [ -f "node_modules/tls-client-node/scripts/postinstall.js" ]; then \
|
||
bun node_modules/tls-client-node/scripts/postinstall.js || true; \
|
||
fi
|
||
|
||
# Turbopack is supported on Bun 1.4+ (Next 16.3); override via
|
||
# --build-arg OMNIROUTE_USE_TURBOPACK=0 to force the webpack fallback.
|
||
ARG OMNIROUTE_USE_TURBOPACK=1
|
||
ENV OMNIROUTE_USE_TURBOPACK=${OMNIROUTE_USE_TURBOPACK}
|
||
|
||
ARG OMNIROUTE_BASE_PATH=""
|
||
ENV OMNIROUTE_BASE_PATH=$OMNIROUTE_BASE_PATH
|
||
|
||
ARG DASHBOARD_ALLOW_EMBED=""
|
||
ENV DASHBOARD_ALLOW_EMBED=$DASHBOARD_ALLOW_EMBED
|
||
|
||
ENV NEXT_TELEMETRY_DISABLED=1
|
||
ENV NODE_ENV=production
|
||
|
||
# Cap the Next.js build heap and page-data worker pool inside the Bun image the
|
||
# same way the node Dockerfile does (#10060/#11419/#7518). Without these knobs
|
||
# Next falls back to its defaults: worker pool = os.cpus()-1 (3 on the 4-vCPU
|
||
# GitHub runner) and an 8 GB V8 heap ceiling per process. 4+ V8 processes at
|
||
# multi-GB each blow past the 16 GB runner, the cgroup OOM killer SIGKILLs a
|
||
# build worker mid-compile, and buildx fails the step with `ResourceExhausted:
|
||
# ... cannot allocate memory` — every Bun image published on main since the -bun
|
||
# targets landed (#11709, #11039).
|
||
#
|
||
# The per-process peak is a MEASURED ~4.5 GB RSS (dmesg OOM-killer report,
|
||
# #7518), independent of NODE_OPTIONS — Turbopack is native/Rust and compiles
|
||
# outside the V8 heap — and it applies to the parent process too, so 2 page-data
|
||
# workers (3 processes × 4.5 GB ≈ 13.5 GB) do not fit the 12.288 GB (75%)
|
||
# budget either. Both images therefore default to OMNIROUTE_BUILD_WORKERS=2
|
||
# (1 page-data worker): 2 processes × 4.5 GB ≈ 9 GB fits with headroom (#11663).
|
||
# The default Turbopack path keeps the compile outside the V8 heap, but the
|
||
# guards must hold for the webpack fallback (OMNIROUTE_USE_TURBOPACK=0) too, so
|
||
# they are wired exactly like the node image.
|
||
#
|
||
# NODE_OPTIONS propagates to the spawned `next build` child and its workers
|
||
# (build-next-isolated.mjs → resolveNextBuildEnv spreads process.env), so the
|
||
# ceiling is per PROCESS, not per build.
|
||
ARG OMNIROUTE_BUILD_MEMORY_MB=6144
|
||
ENV NODE_OPTIONS="--max-old-space-size=${OMNIROUTE_BUILD_MEMORY_MB}"
|
||
ARG OMNIROUTE_BUILD_WORKERS=2
|
||
ENV CIRCLE_NODE_TOTAL=${OMNIROUTE_BUILD_WORKERS}
|
||
|
||
# Bun native Next.js build execution
|
||
RUN bun run --quiet build
|
||
|
||
# ── Runner Base stage (100% Bun Native Production Runtime) ──────────────────
|
||
FROM oven/bun:1.3.14-slim AS runner-base
|
||
|
||
LABEL org.opencontainers.image.title="omniroute" \
|
||
org.opencontainers.image.description="Unified AI proxy — route any LLM through one endpoint (Bun Native)" \
|
||
org.opencontainers.image.url="https://omniroute.online" \
|
||
org.opencontainers.image.source="https://github.com/diegosouzapw/OmniRoute" \
|
||
org.opencontainers.image.licenses="MIT"
|
||
|
||
WORKDIR /app
|
||
|
||
RUN apt-get update \
|
||
&& apt-get install -y --no-install-recommends \
|
||
libsecret-1-0 \
|
||
ca-certificates \
|
||
curl \
|
||
&& rm -rf /var/lib/apt/lists/*
|
||
|
||
ENV NODE_ENV=production
|
||
ENV PORT=20128
|
||
ENV HOSTNAME=0.0.0.0
|
||
ENV OMNIROUTE_MEMORY_MB=1024
|
||
|
||
ENV DATA_DIR=/app/data
|
||
RUN mkdir -p /app/data
|
||
|
||
COPY --from=builder /app/.build/next/standalone ./
|
||
COPY --from=builder /app/node_modules/better-sqlite3 ./node_modules/better-sqlite3
|
||
ENV OMNIROUTE_MIGRATIONS_DIR=/app/migrations
|
||
|
||
COPY --from=builder /app/scripts/dev/healthcheck.mjs ./healthcheck.mjs
|
||
|
||
EXPOSE 20128
|
||
|
||
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
|
||
CMD bun healthcheck.mjs || exit 1
|
||
|
||
ENTRYPOINT ["bun", "dev/run-standalone.mjs"]
|
||
|
||
# ── Runner Web stage (Bun Native + Chromium/Playwright for Web providers) ───
|
||
FROM runner-base AS runner-web
|
||
|
||
USER root
|
||
|
||
RUN apt-get update \
|
||
&& apt-get install -y --no-install-recommends \
|
||
chromium \
|
||
chromium-driver \
|
||
fonts-liberation \
|
||
libasound2t64 \
|
||
gconf-service \
|
||
libatk-bridge2.0-0 \
|
||
libatk1.0-0 \
|
||
libc6 \
|
||
libcairo2 \
|
||
libcups2 \
|
||
libdbus-1-3 \
|
||
libexpat1 \
|
||
libfontconfig1 \
|
||
libgbm1 \
|
||
libgcc-s1 \
|
||
libglib2.0-0 \
|
||
libgtk-3-0 \
|
||
libnspr4 \
|
||
libnss3 \
|
||
libpango-1.0-0 \
|
||
pangocairo-1.0-0 \
|
||
stdc++6 \
|
||
libx11-6 \
|
||
libx11-xcb1 \
|
||
libxcb1 \
|
||
libxcomposite1 \
|
||
libxcursor1 \
|
||
libxdamage1 \
|
||
libxext6 \
|
||
libxfixes3 \
|
||
libxi6 \
|
||
libxrandr2 \
|
||
libxrender1 \
|
||
libxss1 \
|
||
libxtst6 \
|
||
ca-certificates \
|
||
fonts-gargi \
|
||
fonts-ipafont-gothic \
|
||
fonts-kacst \
|
||
fonts-thai-tlwg \
|
||
fonts-wqy-zenhei \
|
||
&& rm -rf /var/lib/apt/lists/*
|
||
|
||
ENV PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1
|
||
ENV PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/chromium
|
||
|
||
# Return to the base image non-root user after the apt install (mirrors the
|
||
# Node Dockerfile runner-web stage, which re-asserts USER node).
|
||
USER bun
|