harb/docker/Dockerfile.service-ci
johba e5e1308e72 refactor: consolidate CI and local dev orchestration (#108)
## Summary
- Extract shared bootstrap functions into `scripts/bootstrap-common.sh` (eliminates ~120 lines of duplicated forge/cast commands from e2e.yml)
- Create reusable `scripts/wait-for-service.sh` for health checks (replaces 60-line inline wait-for-stack)
- Merge dev and CI entrypoints into unified scripts branching on `CI` env var (delete `docker/ci-entrypoints/`)
- Replace 4 per-service CI Dockerfiles with parameterized `docker/Dockerfile.service-ci`
- Add `sync-tax-rates.mjs` to CI image builder stage
- Fix: CI now grants txnBot recenter access (was missing)
- Fix: txnBot funding parameterized (CI=10eth, local=1eth)
- Delete 5 obsolete migration docs and 4 DinD integration files

Net: -1540 lines removed

Closes #107

## Test plan
- [ ] E2E pipeline passes (bootstrap sources shared script, services use old images with commands override)
- [ ] build-ci-images pipeline builds all 4 services with unified Dockerfile
- [ ] Local dev stack boots via `./scripts/dev.sh start`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: openhands <openhands@all-hands.dev>
Reviewed-on: https://codeberg.org/johba/harb/pulls/108
2026-02-03 12:07:28 +01:00

113 lines
3.9 KiB
Text

# Unified CI image for Harb services (ponder, webapp, landing, txnBot).
# Parameterized via build args — eliminates per-service Dockerfile duplication.
#
# Usage:
# docker build -f docker/Dockerfile.service-ci \
# --build-arg SERVICE_DIR=services/ponder \
# --build-arg SERVICE_PORT=42069 \
# --build-arg ENTRYPOINT_SCRIPT=containers/ponder-entrypoint.sh \
# -t ponder-ci .
# ── Build args (declared early for builder stage) ──────────────────
ARG SERVICE_DIR
ARG NPM_INSTALL_CMD=ci
# ── Builder stage ──────────────────────────────────────────────────
FROM node:20-alpine AS builder
RUN apk add --no-cache git bash
WORKDIR /app
# Copy root package files
COPY package.json package-lock.json ./
# Copy kraiken-lib package files
COPY kraiken-lib/package.json kraiken-lib/package-lock.json ./kraiken-lib/
# Copy ABI files needed by kraiken-lib
COPY onchain/out/Kraiken.sol/Kraiken.json ./onchain/out/Kraiken.sol/
COPY onchain/out/Stake.sol/Stake.json ./onchain/out/Stake.sol/
# Copy Stake.sol for sync-tax-rates + the script itself
COPY onchain/src/Stake.sol ./onchain/src/
COPY scripts/sync-tax-rates.mjs ./scripts/
# Install kraiken-lib dependencies, run sync-tax-rates, and build
WORKDIR /app/kraiken-lib
RUN npm ci --ignore-scripts
COPY kraiken-lib/ ./
RUN node ../scripts/sync-tax-rates.mjs && ./node_modules/.bin/tsc
# Install service dependencies
ARG SERVICE_DIR
ARG NPM_INSTALL_CMD
WORKDIR /app/${SERVICE_DIR}
COPY ${SERVICE_DIR}/package.json ./
# Use glob pattern to optionally copy package-lock.json (txnBot has none)
COPY ${SERVICE_DIR}/package-lock.jso[n] ./
RUN if [ "$NPM_INSTALL_CMD" = "install" ]; then npm install; else npm ci; fi
# Copy service source
COPY ${SERVICE_DIR}/ ./
# Copy onchain deployment artifacts (glob handles missing files)
WORKDIR /app
COPY onchain/deployments*.jso[n] ./onchain/
# ── Runtime stage ──────────────────────────────────────────────────
FROM node:20-alpine
RUN apk add --no-cache dumb-init wget bash
WORKDIR /app
# Copy kraiken-lib (src for Vite alias, dist for runtime, package.json for resolution)
COPY --from=builder /app/kraiken-lib/src ./kraiken-lib/src
COPY --from=builder /app/kraiken-lib/dist ./kraiken-lib/dist
COPY --from=builder /app/kraiken-lib/package.json ./kraiken-lib/
# Copy service with all node_modules
ARG SERVICE_DIR
COPY --from=builder /app/${SERVICE_DIR} ./${SERVICE_DIR}
# Copy onchain artifacts
COPY --from=builder /app/onchain ./onchain
# Create placeholder deployments-local.json if not present
RUN test -f /app/onchain/deployments-local.json || \
(mkdir -p /app/onchain && echo '{"contracts":{}}' > /app/onchain/deployments-local.json)
# Conditionally create symlinks for Vite path resolution (webapp only)
ARG NEEDS_SYMLINKS=false
RUN if [ "$NEEDS_SYMLINKS" = "true" ]; then \
ln -sf /app/web-app /web-app && \
ln -sf /app/kraiken-lib /kraiken-lib && \
ln -sf /app/onchain /onchain; \
fi
# Copy entrypoint script
# For services with entrypoints (ponder, webapp, txnbot): pass the actual entrypoint
# For landing (no entrypoint): defaults to entrypoint-common.sh which is just helpers
ARG ENTRYPOINT_SCRIPT=containers/entrypoint-common.sh
COPY ${ENTRYPOINT_SCRIPT} /entrypoint.sh
RUN chmod +x /entrypoint.sh
# Set working directory to service
WORKDIR /app/${SERVICE_DIR}
ARG NODE_ENV=production
ENV NODE_ENV=${NODE_ENV}
ENV HOST=0.0.0.0
ARG SERVICE_PORT=8080
ENV PORT=${SERVICE_PORT}
EXPOSE ${SERVICE_PORT}
ARG HEALTHCHECK_PATH=/
ARG HEALTHCHECK_RETRIES=12
ARG HEALTHCHECK_START=20s
HEALTHCHECK --interval=5s --timeout=3s --retries=${HEALTHCHECK_RETRIES} --start-period=${HEALTHCHECK_START} \
CMD wget --spider -q http://127.0.0.1:${PORT}${HEALTHCHECK_PATH} || exit 1
ENTRYPOINT ["dumb-init", "--", "/entrypoint.sh"]