# Cache-Optimized Dockerfile for homelab use # Build with: docker build --build-context native=./native -f build/docker/simple.Dockerfile . # ============================================================================ # STAGE 1: Native C++ Builder (separate cache layer) # ============================================================================ FROM alpine:3.19 AS native-builder RUN apk add --no-cache gcc g++ cmake make musl-dev linux-headers WORKDIR /build COPY native/ ./ ENV FETCHML_DOCKER_BUILD=1 RUN mkdir -p build && cd build && \ cmake .. -DCMAKE_BUILD_TYPE=Release -DBUILD_NVML_GPU=OFF && \ make -j$(nproc) # ============================================================================ # STAGE 2: Go Dependencies (cached layer - only changes when go.mod/sum changes) # ============================================================================ FROM golang:1.25-alpine AS go-deps RUN apk add --no-cache git make gcc g++ musl-dev cmake WORKDIR /app # Copy only module files first for maximum cache efficiency COPY go.mod go.sum ./ RUN --mount=type=cache,target=/go/pkg/mod \ go mod download && \ go mod verify # ============================================================================ # STAGE 3: Go Builder (source changes don't invalidate deps) # ============================================================================ FROM go-deps AS go-builder # Copy source code (changes here won't rebuild deps layer) COPY cmd/ ./cmd/ COPY internal/ ./internal/ COPY pkg/ ./pkg/ COPY tools/ ./tools/ # Build Go binaries with cache mount for build cache RUN --mount=type=cache,target=/go/pkg/mod \ --mount=type=cache,target=/root/.cache/go-build \ CGO_ENABLED=1 go build -ldflags="-w -s" -o bin/api-server ./cmd/api-server/main.go && \ CGO_ENABLED=1 go build -ldflags="-w -s" -o bin/worker ./cmd/worker # ============================================================================ # STAGE 4: Final Runtime (minimal layers) # ============================================================================ FROM alpine:3.19 # Install runtime deps in single layer with cache mount RUN --mount=type=cache,target=/var/cache/apk \ apk add --no-cache bash ca-certificates redis openssl curl podman fuse-overlayfs slirp4netns iptables libstdc++ # Create app user RUN addgroup -g 1001 -S appgroup && \ adduser -u 1001 -S appuser -G appgroup WORKDIR /app # Copy binaries (separate layer for quick updates) COPY --from=go-builder /app/bin/api-server /usr/local/bin/ COPY --from=go-builder /app/bin/worker /usr/local/bin/ # Copy configs (changes often - keep near end) COPY configs/ /app/configs/ # Setup directories and SSL in single layer RUN mkdir -p /app/data/experiments /app/data/datasets /app/data/snapshots /app/logs /app/ssl && \ openssl req -x509 -newkey rsa:2048 -keyout /app/ssl/key.pem -out /app/ssl/cert.pem -days 365 -nodes \ -subj "/C=US/ST=Homelab/L=Local/O=ML/OU=Experiments/CN=localhost" && \ chmod 644 /app/ssl/cert.pem && \ chmod 600 /app/ssl/key.pem && \ chown -R appuser:appgroup /app/data /app/logs /app/ssl /app/configs USER appuser EXPOSE 9101 HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \ CMD curl -f http://localhost:9101/health || curl -k -f https://localhost:9101/health || exit 1 CMD ["/usr/local/bin/api-server", "-config", "/app/configs/api/dev.yaml"]