# syntax=docker/dockerfile:1.6 # Multi-stage Dockerfile for RustFS - LOCAL DEVELOPMENT ONLY # # IMPORTANT: This Dockerfile builds RustFS from source for local development and testing. # CI/CD uses the production Dockerfile with prebuilt binaries instead. # # Example: # docker build -f Dockerfile.source -t rustfs:dev-local . # docker run --rm -p 9000:9000 rustfs:dev-local # # Supports cross-compilation for amd64 and arm64 via TARGETPLATFORM. ARG TARGETPLATFORM ARG BUILDPLATFORM # ----------------------------- # Build stage # ----------------------------- FROM rust:1.88-bookworm AS builder # Re-declare args after FROM ARG TARGETPLATFORM ARG BUILDPLATFORM # Debug: print platforms RUN echo "Build info -> BUILDPLATFORM=${BUILDPLATFORM}, TARGETPLATFORM=${TARGETPLATFORM}" # Install build toolchain and headers # Use distro packages for protoc/flatc to avoid host-arch mismatch RUN set -eux; \ export DEBIAN_FRONTEND=noninteractive; \ apt-get update; \ apt-get install -y --no-install-recommends \ build-essential \ ca-certificates \ curl \ git \ pkg-config \ libssl-dev \ lld \ protobuf-compiler \ flatbuffers-compiler \ gcc-aarch64-linux-gnu \ gcc-x86-64-linux-gnu; \ rm -rf /var/lib/apt/lists/* # Optional: cross toolchain for aarch64 (only when targeting linux/arm64) RUN set -eux; \ if [ "${TARGETPLATFORM:-linux/amd64}" = "linux/arm64" ]; then \ export DEBIAN_FRONTEND=noninteractive; \ apt-get update; \ apt-get install -y --no-install-recommends gcc-aarch64-linux-gnu; \ rm -rf /var/lib/apt/lists/*; \ fi # Add Rust targets for both arches (to support cross-builds on multi-arch runners) RUN set -eux; \ rustup target add x86_64-unknown-linux-gnu aarch64-unknown-linux-gnu; \ rustup component add rust-std-x86_64-unknown-linux-gnu rust-std-aarch64-unknown-linux-gnu # Cross-compilation environment (used only when targeting aarch64) ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc ENV CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc ENV CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++ ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=x86_64-linux-gnu-gcc ENV CC_x86_64_unknown_linux_gnu=x86_64-linux-gnu-gcc ENV CXX_x86_64_unknown_linux_gnu=x86_64-linux-gnu-g++ WORKDIR /usr/src/rustfs # Layered copy to maximize caching: # 1) top-level manifests COPY Cargo.toml Cargo.lock ./ # 2) workspace member manifests (adjust if workspace layout changes) COPY rustfs/Cargo.toml rustfs/Cargo.toml COPY crates/*/Cargo.toml crates/ # Pre-fetch dependencies for better caching RUN --mount=type=cache,target=/usr/local/cargo/registry \ --mount=type=cache,target=/usr/local/cargo/git \ cargo fetch --locked || true # 3) copy full sources (this is the main cache invalidation point) COPY . . # Cargo build configuration for lean release artifacts ENV CARGO_NET_GIT_FETCH_WITH_CLI=true \ CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse \ CARGO_INCREMENTAL=0 \ CARGO_PROFILE_RELEASE_DEBUG=false \ CARGO_PROFILE_RELEASE_SPLIT_DEBUGINFO=off \ CARGO_PROFILE_RELEASE_STRIP=symbols # Generate protobuf/flatbuffers code (uses protoc/flatc from distro) RUN --mount=type=cache,target=/usr/local/cargo/registry \ --mount=type=cache,target=/usr/local/cargo/git \ --mount=type=cache,target=/usr/src/rustfs/target \ cargo run --bin gproto # Build RustFS (target depends on TARGETPLATFORM) RUN --mount=type=cache,target=/usr/local/cargo/registry \ --mount=type=cache,target=/usr/local/cargo/git \ --mount=type=cache,target=/usr/src/rustfs/target \ set -eux; \ case "${TARGETPLATFORM:-linux/amd64}" in \ linux/amd64) \ echo "Building for x86_64-unknown-linux-gnu"; \ cargo build --release --locked --target x86_64-unknown-linux-gnu --bin rustfs -j "$(nproc)"; \ install -m 0755 target/x86_64-unknown-linux-gnu/release/rustfs /usr/local/bin/rustfs \ ;; \ linux/arm64) \ echo "Building for aarch64-unknown-linux-gnu"; \ cargo build --release --locked --target aarch64-unknown-linux-gnu --bin rustfs -j "$(nproc)"; \ install -m 0755 target/aarch64-unknown-linux-gnu/release/rustfs /usr/local/bin/rustfs \ ;; \ *) \ echo "Unsupported TARGETPLATFORM=${TARGETPLATFORM}" >&2; exit 1 \ ;; \ esac # ----------------------------- # Development stage (keeps toolchain) # ----------------------------- FROM builder AS dev ARG BUILD_DATE ARG VCS_REF LABEL name="RustFS (dev-source)" \ maintainer="RustFS Team" \ build-date="${BUILD_DATE}" \ vcs-ref="${VCS_REF}" \ description="RustFS - local development with Rust toolchain." # Install runtime dependencies that might be missing in partial builder # (builder already has build-essential, lld, etc.) WORKDIR /app ENV CARGO_INCREMENTAL=1 # Ensure we have the same default env vars available ENV RUSTFS_ADDRESS=":9000" \ RUSTFS_ACCESS_KEY="rustfsadmin" \ RUSTFS_SECRET_KEY="rustfsadmin" \ RUSTFS_CONSOLE_ENABLE="true" \ RUSTFS_VOLUMES="/data" \ RUST_LOG="warn" \ RUSTFS_OBS_LOG_DIRECTORY="/logs" \ RUSTFS_USERNAME="rustfs" \ RUSTFS_GROUPNAME="rustfs" \ RUSTFS_UID="10001" \ RUSTFS_GID="10001" # Note: We don't COPY source here because we expect it to be mounted at /app # We rely on cargo run to build and run EXPOSE 9000 9001 COPY entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"] CMD ["cargo", "run", "--bin", "rustfs", "--"] # ----------------------------- # Runtime stage (Ubuntu minimal) # ----------------------------- FROM ubuntu:22.04 ARG BUILD_DATE ARG VCS_REF LABEL name="RustFS (dev-local)" \ maintainer="RustFS Team" \ build-date="${BUILD_DATE}" \ vcs-ref="${VCS_REF}" \ description="RustFS - local development image built from source (NOT for production)." # Minimal runtime deps: certificates + tzdata + coreutils (for chroot --userspec) RUN set -eux; \ export DEBIAN_FRONTEND=noninteractive; \ apt-get update; \ apt-get install -y --no-install-recommends \ ca-certificates \ tzdata \ coreutils; \ rm -rf /var/lib/apt/lists/* # Create a conventional runtime user/group (final switch happens in entrypoint via chroot --userspec) RUN set -eux; \ groupadd -g 10001 rustfs; \ useradd -u 10001 -g rustfs -M -s /usr/sbin/nologin rustfs WORKDIR /app # Prepare data/log directories with sane defaults RUN set -eux; \ mkdir -p /data /logs; \ chown -R rustfs:rustfs /data /logs /app; \ chmod 0750 /data /logs # Copy the freshly built binary and the entrypoint COPY --from=builder /usr/local/bin/rustfs /usr/bin/rustfs COPY entrypoint.sh /entrypoint.sh RUN chmod +x /usr/bin/rustfs /entrypoint.sh # Default environment (override in docker run/compose as needed) ENV RUSTFS_ADDRESS=":9000" \ RUSTFS_ACCESS_KEY="rustfsadmin" \ RUSTFS_SECRET_KEY="rustfsadmin" \ RUSTFS_CONSOLE_ENABLE="true" \ RUSTFS_VOLUMES="/data" \ RUST_LOG="warn" \ RUSTFS_USERNAME="rustfs" \ RUSTFS_GROUPNAME="rustfs" \ RUSTFS_UID="10001" \ RUSTFS_GID="10001" EXPOSE 9000 VOLUME ["/data"] # Keep root here; entrypoint will drop privileges using chroot --userspec ENTRYPOINT ["/entrypoint.sh"] CMD ["/usr/bin/rustfs"]