rustberg 0.0.5

A production-grade, cross-platform, single-binary Apache Iceberg REST Catalog
Documentation
# =============================================================================
# Rustberg Docker Image
# Multi-stage, multi-arch build for minimal, secure production image
# =============================================================================
# Build commands:
#   Single arch:  docker build -t rustberg .
#   Multi-arch:   docker buildx build --platform linux/amd64,linux/arm64 -t rustberg .
#   Debug:        docker build --target debug -t rustberg:debug .
# =============================================================================

# -----------------------------------------------------------------------------
# Stage 1: Build (supports both amd64 and arm64)
# -----------------------------------------------------------------------------
FROM --platform=$BUILDPLATFORM rust:1.89-bookworm AS builder

# Build arguments for cross-compilation
ARG TARGETPLATFORM
ARG TARGETARCH
ARG BUILDPLATFORM

# Install minimal dependencies and cargo-zigbuild for cross-compilation
# cargo-zigbuild uses Zig as a linker, which provides hermetic musl support
# without needing external toolchain downloads
RUN apt-get update && apt-get install -y --no-install-recommends \
    ca-certificates \
    musl-tools \
    musl-dev \
    xz-utils \
    && rm -rf /var/lib/apt/lists/*

# Install Zig (architecture-aware) and cargo-zigbuild for reliable cross-compilation
RUN case "$BUILDPLATFORM" in \
        linux/amd64) ZIG_ARCH="x86_64" ;; \
        linux/arm64) ZIG_ARCH="aarch64" ;; \
        *) echo "Unsupported build platform: $BUILDPLATFORM" && exit 1 ;; \
    esac && \
    curl -L "https://ziglang.org/download/0.13.0/zig-linux-${ZIG_ARCH}-0.13.0.tar.xz" | tar -xJ -C /opt && \
    ln -s /opt/zig-linux-${ZIG_ARCH}-0.13.0/zig /usr/local/bin/zig && \
    cargo install cargo-zigbuild

# Set up Rust target based on architecture
RUN case "$TARGETARCH" in \
        amd64) RUST_TARGET="x86_64-unknown-linux-musl" ;; \
        arm64) RUST_TARGET="aarch64-unknown-linux-musl" ;; \
        *) echo "Unsupported architecture: $TARGETARCH" && exit 1 ;; \
    esac && \
    rustup target add $RUST_TARGET && \
    echo "$RUST_TARGET" > /tmp/rust-target

WORKDIR /build

# Copy Cargo files first for dependency caching
COPY Cargo.toml Cargo.lock ./

# Create dummy source for dependency caching
RUN mkdir -p src && \
    echo 'fn main() { println!("dummy"); }' > src/main.rs && \
    echo 'pub fn dummy() {}' > src/lib.rs

# Build dependencies only (this layer is cached)
RUN RUST_TARGET=$(cat /tmp/rust-target) && \
    cargo zigbuild --release --target $RUST_TARGET --features slatedb-storage,cli,tls 2>/dev/null || true

# Remove dummy source
RUN rm -rf src/

# Copy actual source
COPY src/ src/

# Touch to force rebuild
RUN touch src/main.rs src/lib.rs

# Build the actual binary
RUN RUST_TARGET=$(cat /tmp/rust-target) && \
    cargo zigbuild --release --target $RUST_TARGET --features slatedb-storage,cli,tls && \
    cp /build/target/$RUST_TARGET/release/rustberg /build/rustberg && \
    strip /build/rustberg 2>/dev/null || true

# Verify binary
RUN ls -lh /build/rustberg && file /build/rustberg

# -----------------------------------------------------------------------------
# Stage 2: Minimal Runtime (distroless for maximum security)
# -----------------------------------------------------------------------------
# Google's distroless: minimal attack surface
# - No shell, no package manager, no unnecessary binaries
# - Only libc and ca-certificates
# - Significantly fewer CVEs than debian-slim or alpine
FROM gcr.io/distroless/cc-debian12:nonroot AS runtime

# OCI Labels
LABEL org.opencontainers.image.title="Rustberg"
LABEL org.opencontainers.image.description="Production-grade Apache Iceberg REST Catalog - 100% Rust"
LABEL org.opencontainers.image.vendor="hupe1980"
LABEL org.opencontainers.image.licenses="Apache-2.0"
LABEL org.opencontainers.image.source="https://github.com/hupe1980/rustberg"
LABEL org.opencontainers.image.documentation="https://hupe1980.github.io/rustberg/"

# Copy binary from builder
COPY --from=builder /build/rustberg /usr/local/bin/rustberg

# Environment defaults
ENV RUSTBERG_HOST=0.0.0.0
ENV RUSTBERG_PORT=8000
ENV RUSTBERG_INSECURE_HTTP=false
ENV RUST_LOG=info

# Expose default port
EXPOSE 8000

# Run as non-root (distroless:nonroot uses UID 65532)
USER nonroot:nonroot

# Entrypoint
ENTRYPOINT ["/usr/local/bin/rustberg"]

# -----------------------------------------------------------------------------
# Stage 3: Debug variant (with shell for troubleshooting)
# Build with: docker build --target debug -t rustberg:debug .
# -----------------------------------------------------------------------------
FROM gcr.io/distroless/cc-debian12:debug-nonroot AS debug

LABEL org.opencontainers.image.title="Rustberg (Debug)"
LABEL org.opencontainers.image.description="Debug variant with busybox shell for troubleshooting"

COPY --from=builder /build/rustberg /usr/local/bin/rustberg

ENV RUSTBERG_HOST=0.0.0.0
ENV RUSTBERG_PORT=8000
ENV RUSTBERG_INSECURE_HTTP=false
ENV RUST_LOG=debug

EXPOSE 8000

USER nonroot:nonroot

ENTRYPOINT ["/usr/local/bin/rustberg"]

# -----------------------------------------------------------------------------
# Default target is the minimal runtime
# -----------------------------------------------------------------------------
FROM runtime