Files
dockhand/Dockerfile
2026-01-01 16:00:34 +01:00

87 lines
3.1 KiB
Docker

# Build stage - using Debian to avoid Alpine musl thread creation issues
# Alpine's musl libc causes rayon/tokio thread pool panics during svelte-adapter-bun build
FROM oven/bun:1.3.5-debian AS builder
WORKDIR /app
# Install build dependencies
RUN apt-get update && apt-get install -y --no-install-recommends jq git && rm -rf /var/lib/apt/lists/*
# Copy package files and install ALL dependencies (needed for build)
COPY package.json bun.lock* bunfig.toml ./
RUN bun install --frozen-lockfile
# Copy source code and build
COPY . .
# Build with parallelism - dedicated build VM has 16 CPUs and 32GB RAM
# Increased memory limits for parallel compilation with larger semi-space for GC
RUN NODE_OPTIONS="--max-old-space-size=8192 --max-semi-space-size=128" bun run build
# Production stage - minimal Alpine with Bun runtime
FROM oven/bun:1.3.5-alpine
WORKDIR /app
# Install runtime dependencies, create user
# Add sqlite for emergency scripts, git for stack git operations, curl for healthchecks
# Add docker-cli and docker-cli-compose for stack management (uses host's docker socket)
# Add openssh-client for SSH key authentication with git repositories
# Upgrade all packages to latest versions for security patches
RUN apk upgrade --no-cache \
&& apk add --no-cache curl git tini su-exec sqlite docker-cli docker-cli-compose openssh-client iproute2 \
&& addgroup -g 1001 dockhand \
&& adduser -u 1001 -G dockhand -h /home/dockhand -D dockhand
# Copy package files and install production dependencies
# This is needed because svelte-adapter-bun externalizes some packages (croner, etc.)
# that need to be available at runtime. Installing at build time is more reliable
# than Bun's auto-install which requires network access and writable cache.
COPY package.json bun.lock* ./
RUN bun install --production --frozen-lockfile
# Copy built application (Bun adapter output)
COPY --from=builder /app/build ./build
# Copy bundled subprocess scripts (built by scripts/build-subprocesses.ts)
COPY --from=builder /app/build/subprocesses/ ./subprocesses/
# Copy database migrations
COPY drizzle/ ./drizzle/
COPY drizzle-pg/ ./drizzle-pg/
# Copy legal documents
COPY LICENSE.txt PRIVACY.txt ./
# Copy entrypoint script
COPY docker-entrypoint.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
# Copy emergency scripts (only the emergency subfolder, not license generation scripts)
COPY scripts/emergency/ ./scripts/
RUN chmod +x ./scripts/*.sh ./scripts/**/*.sh 2>/dev/null || true
# Create directories with proper ownership
RUN mkdir -p /home/dockhand/.dockhand/stacks /app/data \
&& chown -R dockhand:dockhand /app /home/dockhand
EXPOSE 3000
# Runtime configuration
ENV NODE_ENV=production
ENV PORT=3000
ENV HOST=0.0.0.0
ENV DATA_DIR=/app/data
ENV HOME=/home/dockhand
# User/group IDs - customize with -e PUID=1000 -e PGID=1000
# The entrypoint will recreate the dockhand user with these IDs
ENV PUID=1001
ENV PGID=1001
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/ || exit 1
ENTRYPOINT ["/sbin/tini", "--", "/usr/local/bin/docker-entrypoint.sh"]
CMD ["bun", "run", "./build/index.js"]