# syntax=docker/dockerfile:1.7 # DataCenterIndex — worker image (also runs the scheduler, the migrate one-shot and the `dci` CLI: # the first CMD word selects the role — see deploy/docker/entrypoint.sh). # Build context = repo root: docker build -f deploy/docker/Dockerfile.worker . ARG NODE_IMAGE=node:22-bookworm-slim ARG PNPM_VERSION=11.1.2 ARG TSX_VERSION=4.23.13 # ---------------------------------------------------------------- base: node + pnpm (build stages only) FROM ${NODE_IMAGE} AS base ARG PNPM_VERSION # pnpm 11 refuses ignored build scripts without a TTY → installs pass --config.dangerously-allow-all-builds=true # (same setting the laptop uses globally) and --config.confirm-modules-purge=false (prod re-install over `pnpm fetch`). ENV PNPM_HOME=/pnpm \ PATH=/pnpm:$PATH \ npm_config_store_dir=/pnpm/store RUN (corepack enable && corepack prepare "pnpm@${PNPM_VERSION}" --activate) \ || npm install -g "pnpm@${PNPM_VERSION}" --no-fund --no-audit # ---------------------------------------------------------------- fetch: lockfile-only layer (cached until the lockfile changes) FROM base AS fetch WORKDIR /app COPY pnpm-lock.yaml pnpm-workspace.yaml ./ # pnpm fetch warms the store but also imports EVERY lockfile package into node_modules/.pnpm — drop that so the # filtered install below only materialises the worker's own dependency graph. RUN --mount=type=cache,id=dci-pnpm-store,target=/pnpm/store pnpm fetch --prod && rm -rf node_modules # ---------------------------------------------------------------- deps: prod install limited to the worker + its workspace deps FROM fetch AS deps COPY . . RUN --mount=type=cache,id=dci-pnpm-store,target=/pnpm/store \ pnpm install --offline --frozen-lockfile --config.dangerously-allow-all-builds=true --config.confirm-modules-purge=false --prod --filter "@dci/worker..." \ && rm -rf apps/web apps/api scripts # ---------------------------------------------------------------- runtime FROM ${NODE_IMAGE} AS runtime ARG TSX_VERSION ENV NODE_ENV=production \ NODE_OPTIONS=--enable-source-maps \ DCI_CONFIG_DIR=/app/config/connectors \ WORKER_PORT=8320 RUN apt-get update \ && apt-get install -y --no-install-recommends tini ca-certificates \ && rm -rf /var/lib/apt/lists/* \ && npm install -g "tsx@${TSX_VERSION}" --no-fund --no-audit \ && npm cache clean --force WORKDIR /app COPY --from=deps --chown=node:node /app/package.json /app/pnpm-workspace.yaml /app/tsconfig.base.json ./ COPY --from=deps --chown=node:node /app/node_modules ./node_modules COPY --from=deps --chown=node:node /app/packages ./packages COPY --from=deps --chown=node:node /app/apps/worker ./apps/worker COPY --from=deps --chown=node:node /app/config ./config COPY --chown=node:node deploy/docker/ensure-clickhouse.ts ./deploy/docker/ensure-clickhouse.ts COPY --chmod=755 deploy/docker/entrypoint.sh /usr/local/bin/dci-entrypoint # `node ../../node_modules/tsx/dist/cli.mjs` (package.json scripts) and the entrypoint both resolve tsx here. RUN ln -s /usr/local/lib/node_modules/tsx /app/node_modules/tsx \ && mkdir -p /app/data && chown node:node /app/data USER node EXPOSE 8320 HEALTHCHECK --interval=30s --timeout=5s --start-period=40s --retries=3 \ CMD ["node", "-e", "fetch('http://127.0.0.1:'+(process.env.WORKER_PORT||8320)+'/healthz').then(r=>process.exit(r.ok?0:1),()=>process.exit(1))"] ENTRYPOINT ["/usr/bin/tini", "--", "/usr/local/bin/dci-entrypoint"] CMD ["worker"]