feat(docker): add all-in-one multi-arch Dockerfile and Gitea deploy config
- Dockerfile.all-in-one: self-contained multi-stage build (frontend, Rust native cross-compile with Debian cross-GCC, server bundle, prod deps, runtime) for linux/amd64 + linux/arm64 - Fix aws-lc-sys asm build on arm64: use gcc-aarch64-linux-gnu instead of napi-rs cross-toolchain (bundled GCC 4.8.5 lacks __ARM_ARCH) - Reduce memory via CARGO_PROFILE_RELEASE_LTO=thin + codegen-units=8 - Runtime mirrors upstream layout incl. schema.prisma/migrations so the selfhost predeploy job works; installs openssl + libjemalloc2 - scripts/deploy-gitea.sh + .gitea-deploy: build/push to Gitea registry - .dockerignore: exclude dist/node_modules/tsbuildinfo from context
This commit is contained in:
173
Dockerfile.all-in-one
Normal file
173
Dockerfile.all-in-one
Normal file
@@ -0,0 +1,173 @@
|
||||
# syntax=docker/dockerfile:1.7
|
||||
# =============================================================================
|
||||
# AFFiNE all-in-one Docker build (self-contained, no prebuilt artifacts needed)
|
||||
#
|
||||
# Stages:
|
||||
# 1. frontend - builds @affine/web + @affine/admin + @affine/mobile dists
|
||||
# 2. native - cross-compiles @affine/server-native (Rust) per TARGETARCH
|
||||
# 3. server-dist - bundles @affine/server (rspack) -> dist/main.js
|
||||
# 4. deps - installs production node_modules (multi-arch aware)
|
||||
# 5. runtime - assembles final image, mirrors .github/deployment/node/Dockerfile
|
||||
#
|
||||
# Build: docker buildx build --platform linux/amd64,linux/arm64 -f Dockerfile.all-in-one .
|
||||
# =============================================================================
|
||||
|
||||
# --- Shared base args ---------------------------------------------------------
|
||||
FROM node:22-bookworm-slim AS base
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends jq python3 make g++ && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
WORKDIR /app
|
||||
|
||||
# Copy everything the yarn install / builds need (respects .dockerignore).
|
||||
COPY . /app/
|
||||
|
||||
# Yarn 4 via corepack; keep scripts off like CI (.yarnrc.yml enableScripts=false)
|
||||
RUN corepack enable && corepack prepare yarn@4.18.0 --activate
|
||||
|
||||
# Full dependency install for build stages.
|
||||
# Prisma postinstall generates client for the BUILD platform only; the runtime
|
||||
# stage re-generates it for the target platform (see `deps` stage).
|
||||
RUN yarn install --immutable
|
||||
|
||||
# =============================================================================
|
||||
# Stage 1: frontend dists (web + admin + mobile)
|
||||
# =============================================================================
|
||||
FROM base AS frontend
|
||||
|
||||
# Self-hosted bundle: force publicPath '/' so assets are served from this
|
||||
# container instead of affineassets CDN (html-plugin getPublicPath()).
|
||||
ENV BUILD_TYPE=stable \
|
||||
PUBLIC_PATH=/ \
|
||||
NODE_ENV=production \
|
||||
GITHUB_SHA=dockerselfhost
|
||||
|
||||
RUN yarn affine @affine/web build && \
|
||||
yarn affine @affine/admin build && \
|
||||
yarn affine @affine/mobile build
|
||||
|
||||
# =============================================================================
|
||||
# Stage 2: Rust native module (@affine/server-native), per target arch
|
||||
# =============================================================================
|
||||
FROM base AS native
|
||||
ARG TARGETARCH
|
||||
|
||||
# Rust toolchain (minimal profile; extra targets added per-arch below).
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends curl ca-certificates && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ENV RUSTUP_HOME=/usr/local/rustup \
|
||||
CARGO_HOME=/usr/local/cargo \
|
||||
PATH=/usr/local/cargo/bin:${PATH}
|
||||
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain 1.97.1 --profile minimal && \
|
||||
cargo --version && rustc --version
|
||||
ENV CARGO_PROFILE_RELEASE_LTO=thin \
|
||||
CARGO_PROFILE_RELEASE_CODEGEN_UNITS=8 \
|
||||
CARGO_PROFILE_RELEASE_OPT_LEVEL=3 \
|
||||
CARGO_PROFILE_RELEASE_STRIP=symbols
|
||||
|
||||
|
||||
WORKDIR /app/packages/backend/native
|
||||
|
||||
# Cross-compile with Debian's cross-GCC instead of napi-rs' bundled GCC 4.8.5:
|
||||
# gcc 4.8.5 does not define __ARM_ARCH for aarch64, breaking aws-lc-sys asm.
|
||||
RUN if [ "$TARGETARCH" = "arm64" ]; then \
|
||||
apt-get update && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
gcc-aarch64-linux-gnu g++-aarch64-linux-gnu libc6-dev-arm64-cross && \
|
||||
rm -rf /var/lib/apt/lists/* && \
|
||||
rustup target add aarch64-unknown-linux-gnu && \
|
||||
CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc \
|
||||
CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++ \
|
||||
AR_aarch64_unknown_linux_gnu=aarch64-linux-gnu-ar \
|
||||
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \
|
||||
yarn build --target aarch64-unknown-linux-gnu && \
|
||||
# index.js resolves arch-specific names; rspack bundles all of them.
|
||||
cp server-native.node server-native.arm64.node && \
|
||||
cp server-native.node server-native.x64.node && \
|
||||
cp server-native.node server-native.armv7.node; \
|
||||
else \
|
||||
yarn build --target x86_64-unknown-linux-gnu && \
|
||||
# Only server-native.node is present from napi; provide arch aliases so
|
||||
# rspack can resolve index.js's arch-specific requires (docker-clean
|
||||
# prunes the wrong-arch binary at runtime anyway).
|
||||
cp server-native.node server-native.x64.node && \
|
||||
cp server-native.node server-native.arm64.node && \
|
||||
cp server-native.node server-native.armv7.node; \
|
||||
fi && \
|
||||
ls -la server-native*.node
|
||||
|
||||
# =============================================================================
|
||||
# Stage 3: server bundle (dist/main.js)
|
||||
# =============================================================================
|
||||
FROM base AS server-dist
|
||||
COPY --from=native /app/packages/backend/native/*.node /app/packages/backend/native/
|
||||
|
||||
RUN yarn workspace @affine/server build
|
||||
|
||||
# =============================================================================
|
||||
# Stage 4: production node_modules (per target arch)
|
||||
# Reuse base (full install already done & cached), then prune to server prod
|
||||
# deps. supportedArchitectures covers both cpus so optional native deps for
|
||||
# either arch get fetched.
|
||||
# =============================================================================
|
||||
FROM base AS deps
|
||||
ARG TARGETARCH
|
||||
|
||||
RUN yarn config set --json supportedArchitectures.cpu "[\"x64\", \"arm64\"]" && \
|
||||
yarn config set --json supportedArchitectures.libc "[\"glibc\"]"
|
||||
|
||||
# Re-install with both cpu targets so the image works on amd64+arm64 builds.
|
||||
RUN yarn install --immutable && \
|
||||
yarn workspaces focus @affine/server @types/affine__env --production
|
||||
|
||||
# Regenerate prisma client engines for this build platform's node_modules
|
||||
RUN cd packages/backend/server && yarn prisma generate
|
||||
|
||||
# Move to server dir layout expected by docker-clean.mjs & runtime stage
|
||||
RUN mv /app/node_modules /app/packages/backend/server/node_modules
|
||||
|
||||
# =============================================================================
|
||||
# Stage 5: runtime — mirror .github/deployment/node/Dockerfile layout
|
||||
# =============================================================================
|
||||
FROM node:22-bookworm-slim AS runtime
|
||||
ARG TARGETARCH
|
||||
WORKDIR /app
|
||||
|
||||
COPY --from=deps /app/packages/backend/server/node_modules /app/node_modules
|
||||
COPY --from=server-dist /app/packages/backend/server/dist /app/dist
|
||||
COPY --from=server-dist /app/packages/backend/server/scripts /app/scripts
|
||||
COPY --from=frontend /app/packages/frontend/apps/web/dist /app/static
|
||||
COPY --from=frontend /app/packages/frontend/admin/dist /app/static/admin
|
||||
COPY --from=frontend /app/packages/frontend/apps/mobile/dist /app/static/mobile
|
||||
# Mirror upstream layout: /app IS the server package dir — the selfhost
|
||||
# predeploy job runs `yarn prisma migrate deploy` + `yarn cli` from here.
|
||||
COPY --from=base /app/packages/backend/server/package.json /app/package.json
|
||||
COPY --from=base /app/packages/backend/server/schema.prisma /app/schema.prisma
|
||||
COPY --from=base /app/packages/backend/server/migrations /app/migrations
|
||||
|
||||
# Upstream installs these in the final image (jemalloc for ENV below,
|
||||
# openssl for prisma engines).
|
||||
RUN apt-get update && \
|
||||
apt-get install -y --no-install-recommends openssl libjemalloc2 && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
# Native binding for this target arch. node-loader emitted
|
||||
# `require('./server-native.node')` inside dist/main.js — the binary must sit
|
||||
# next to it.
|
||||
COPY --from=native /app/packages/backend/native/server-native.node /app/dist/server-native.node
|
||||
|
||||
ENV LD_PRELOAD=libjemalloc.so.2
|
||||
|
||||
|
||||
# Same pruning as upstream: sourcemaps, wrong-arch natives/prisma engines,
|
||||
# dedupe static files.
|
||||
RUN AFFINE_DOCKER_CLEAN=1 \
|
||||
TARGETARCH="$( [ "$TARGETARCH" = "amd64" ] && echo amd64 || echo arm64 )" \
|
||||
node ./scripts/docker-clean.mjs
|
||||
|
||||
EXPOSE 3010
|
||||
|
||||
CMD ["node", "./dist/main.js"]
|
||||
Reference in New Issue
Block a user