|
| 1 | +# syntax=docker/dockerfile:1.4 |
| 2 | +# ============================================================================= |
| 3 | +# Dockhand Docker Image - RISC-V 64-bit (Experimental) |
| 4 | +# ============================================================================= |
| 5 | +# Experimental riscv64 build. Wolfi has no riscv64 packages, and official |
| 6 | +# node:24-alpine/slim images don't include riscv64 either. Alpine edge repos |
| 7 | +# have nodejs 24 for riscv64, so we use those directly. |
| 8 | +# |
| 9 | +# docker-compose is not packaged for riscv64 in Alpine, so we build it from |
| 10 | +# source using Go (which has full riscv64 support). |
| 11 | +# |
| 12 | +# lightningcss (used by Vite) has no riscv64 prebuilt binary, so we split |
| 13 | +# the build: Vite runs on the build platform (fast, has lightningcss), then |
| 14 | +# native addons are rebuilt on riscv64 (QEMU, slower but necessary). |
| 15 | +# |
| 16 | +# Build: |
| 17 | +# docker buildx build --platform linux/riscv64 -f Dockerfile.riscv64 \ |
| 18 | +# -t registry.bor6.pl/dockhand:riscv64-test --push . |
| 19 | +# ============================================================================= |
| 20 | + |
| 21 | +# ----------------------------------------------------------------------------- |
| 22 | +# Stage 1: Docker Compose Builder (Go - cross-compile from build platform) |
| 23 | +# ----------------------------------------------------------------------------- |
| 24 | +# Alpine edge has docker-cli for riscv64 but NOT docker-compose. |
| 25 | +# Build it from source since Go has excellent riscv64 cross-compilation. |
| 26 | +FROM --platform=$BUILDPLATFORM golang:1.25.9-alpine AS compose-builder |
| 27 | +ARG TARGETARCH |
| 28 | + |
| 29 | +RUN apk add --no-cache git |
| 30 | + |
| 31 | +RUN git clone --depth 1 --branch v2.36.1 https://github.com/docker/compose.git /src/compose |
| 32 | + |
| 33 | +WORKDIR /src/compose |
| 34 | +RUN CGO_ENABLED=0 GOARCH=$TARGETARCH go build -trimpath -ldflags="-s -w" -o /usr/bin/docker-compose ./cmd |
| 35 | + |
| 36 | +# ----------------------------------------------------------------------------- |
| 37 | +# Stage 2: JS Builder (runs on build platform - has lightningcss binaries) |
| 38 | +# ----------------------------------------------------------------------------- |
| 39 | +# Vite/lightningcss have no riscv64 prebuilt binaries. Since Vite produces |
| 40 | +# plain JS bundles with no arch dependency, we build on the host platform. |
| 41 | +FROM --platform=$BUILDPLATFORM node:24-alpine AS js-builder |
| 42 | + |
| 43 | +WORKDIR /app |
| 44 | + |
| 45 | +RUN apk add --no-cache git curl python3 make g++ gcc musl-dev |
| 46 | + |
| 47 | +COPY package.json package-lock.json ./ |
| 48 | +RUN MAKEFLAGS="-j$(nproc)" npm ci --ignore-scripts \ |
| 49 | + && MAKEFLAGS="-j$(nproc)" npm rebuild |
| 50 | + |
| 51 | +COPY . . |
| 52 | +RUN npm run build |
| 53 | + |
| 54 | +# ----------------------------------------------------------------------------- |
| 55 | +# Stage 3: Native Addon Builder (runs on riscv64 via QEMU) |
| 56 | +# ----------------------------------------------------------------------------- |
| 57 | +# better-sqlite3 and argon2 have C/C++ native addons that must be compiled |
| 58 | +# for the target architecture (riscv64). |
| 59 | +FROM --platform=$TARGETPLATFORM alpine:edge AS addon-builder |
| 60 | + |
| 61 | +RUN apk add --no-cache --repository=https://dl-cdn.alpinelinux.org/alpine/edge/main \ |
| 62 | + --repository=https://dl-cdn.alpinelinux.org/alpine/edge/community \ |
| 63 | + nodejs npm python3 make g++ gcc musl-dev |
| 64 | + |
| 65 | +WORKDIR /app |
| 66 | + |
| 67 | +COPY package.json package-lock.json ./ |
| 68 | +RUN MAKEFLAGS="-j$(nproc)" npm ci --omit=dev --ignore-scripts \ |
| 69 | + && MAKEFLAGS="-j$(nproc)" npm rebuild better-sqlite3 argon2 \ |
| 70 | + && rm -rf node_modules/@types |
| 71 | + |
| 72 | +# ----------------------------------------------------------------------------- |
| 73 | +# Stage 4: Go Collector Builder (cross-compile from build platform) |
| 74 | +# ----------------------------------------------------------------------------- |
| 75 | +FROM --platform=$BUILDPLATFORM golang:1.25.9 AS go-builder |
| 76 | +ARG TARGETARCH |
| 77 | +WORKDIR /app |
| 78 | +COPY collector/ ./collector/ |
| 79 | +RUN cd collector && CGO_ENABLED=0 GOARCH=$TARGETARCH go build -o /app/bin/collection-worker . |
| 80 | + |
| 81 | +# ----------------------------------------------------------------------------- |
| 82 | +# Stage 5: Final Image (Alpine edge runtime) |
| 83 | +# ----------------------------------------------------------------------------- |
| 84 | +FROM alpine:edge |
| 85 | + |
| 86 | +# Install runtime packages from main + community repos |
| 87 | +RUN apk add --no-cache \ |
| 88 | + --repository=https://dl-cdn.alpinelinux.org/alpine/edge/main \ |
| 89 | + --repository=https://dl-cdn.alpinelinux.org/alpine/edge/community \ |
| 90 | + nodejs \ |
| 91 | + ca-certificates \ |
| 92 | + tzdata \ |
| 93 | + docker-cli \ |
| 94 | + docker-cli-buildx \ |
| 95 | + sqlite \ |
| 96 | + postgresql17-client \ |
| 97 | + git \ |
| 98 | + openssh-client \ |
| 99 | + curl \ |
| 100 | + tini \ |
| 101 | + su-exec \ |
| 102 | + libstdc++ |
| 103 | + |
| 104 | +# Copy docker-compose built from source (not available as Alpine package for riscv64) |
| 105 | +COPY --from=compose-builder /usr/bin/docker-compose /usr/bin/docker-compose |
| 106 | + |
| 107 | +# Create docker compose plugin symlink |
| 108 | +RUN mkdir -p /usr/libexec/docker/cli-plugins \ |
| 109 | + && ln -sf /usr/bin/docker-compose /usr/libexec/docker/cli-plugins/docker-compose |
| 110 | + |
| 111 | +# Create dockhand user and group |
| 112 | +RUN addgroup -g 1001 dockhand \ |
| 113 | + && adduser -u 1001 -G dockhand -h /home/dockhand -D dockhand |
| 114 | + |
| 115 | +WORKDIR /app |
| 116 | + |
| 117 | +# Set up environment variables |
| 118 | +ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt \ |
| 119 | + NODE_ENV=production \ |
| 120 | + PORT=3000 \ |
| 121 | + HOST=0.0.0.0 \ |
| 122 | + DATA_DIR=/app/data \ |
| 123 | + HOME=/home/dockhand \ |
| 124 | + PUID=1001 \ |
| 125 | + PGID=1001 |
| 126 | + |
| 127 | +# Copy node_modules with riscv64 native addons |
| 128 | +COPY --from=addon-builder --chown=dockhand:dockhand /app/node_modules ./node_modules |
| 129 | + |
| 130 | +# Copy built JS app from cross-platform builder |
| 131 | +COPY --from=js-builder --chown=dockhand:dockhand /app/package.json ./ |
| 132 | +COPY --from=js-builder --chown=dockhand:dockhand /app/build ./build |
| 133 | +COPY --from=js-builder --chown=dockhand:dockhand /app/server.js ./ |
| 134 | + |
| 135 | +# Copy Go collector binary |
| 136 | +COPY --from=go-builder --chown=dockhand:dockhand /app/bin/collection-worker ./bin/collection-worker |
| 137 | + |
| 138 | +# Copy database migrations |
| 139 | +COPY --chown=dockhand:dockhand drizzle/ ./drizzle/ |
| 140 | +COPY --chown=dockhand:dockhand drizzle-pg/ ./drizzle-pg/ |
| 141 | + |
| 142 | +# Copy legal documents |
| 143 | +COPY --chown=dockhand:dockhand LICENSE.txt PRIVACY.txt ./ |
| 144 | + |
| 145 | +# Copy entrypoint script |
| 146 | +COPY docker-entrypoint-node.sh /usr/local/bin/docker-entrypoint.sh |
| 147 | +RUN chmod +x /usr/local/bin/docker-entrypoint.sh |
| 148 | + |
| 149 | +# Copy emergency scripts |
| 150 | +COPY --chown=dockhand:dockhand scripts/emergency/ ./scripts/ |
| 151 | +RUN chmod +x ./scripts/*.sh ./scripts/**/*.sh 2>/dev/null || true |
| 152 | + |
| 153 | +# Create data directories |
| 154 | +RUN mkdir -p /home/dockhand/.dockhand/stacks /app/data \ |
| 155 | + && chown dockhand:dockhand /app/data /home/dockhand /home/dockhand/.dockhand /home/dockhand/.dockhand/stacks |
| 156 | + |
| 157 | +EXPOSE 3000 |
| 158 | + |
| 159 | +HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ |
| 160 | + CMD curl -f http://localhost:${PORT:-3000}/ || exit 1 |
| 161 | + |
| 162 | +ENTRYPOINT ["/sbin/tini", "--", "/usr/local/bin/docker-entrypoint.sh"] |
| 163 | +CMD [] |
0 commit comments