# Dockerfile Template Generator with cargo-chef Multi-Stage Build # Generates optimized 4-stage Dockerfile with dependency caching # # Usage: # Pass build config as parameter: # let template = import "this-file.ncl" in # let defaults = import "../../defaults/orchestrator-defaults.ncl" in # template defaults.orchestrator.build # # Stages: # 1. PLANNER - Generate cargo-chef recipe.json (dependency graph) # 2. CACHER - Build dependencies only (cached layer) # 3. BUILDER - Build source code (uses CACHER artifacts) # 4. RUNTIME - Minimal runtime image with binary only # Template function that takes build_config record fun build_config => let package = build_config.package in let binary = build_config.binary in let base_image = build_config.base_image in let runtime_image = build_config.runtime_image in let port = build_config.port in let health_path = build_config.health_path in let features = build_config.features in let extra_runtime_pkgs = build_config.extra_runtime_pkgs in let user_id = build_config.user_id in let config_file = build_config.config_file in let chef_enabled = build_config.chef_enabled in let sccache_enabled = build_config.sccache.enabled in let buildkit_jobs = build_config.buildkit.parallel_jobs in # Conditional string generation helpers let features_arg = if std.array.length features > 0 then "--features " ++ (std.string.join "," features) else "" in let sccache_install = if sccache_enabled then "RUN cargo install sccache --version 0.8.0\nENV RUSTC_WRAPPER=sccache" else "" in let extra_pkgs_str = if std.array.length extra_runtime_pkgs > 0 then " \\\n " ++ (std.string.join " \\\n " extra_runtime_pkgs) else "" in let config_copy = if config_file != "" then "COPY crates/" ++ package ++ "/" ++ config_file ++ " /etc/provisioning/config.defaults.toml" else "# No config file to copy" in # Generate Dockerfile content std.string.join "\n" [ "# Multi-stage build for " ++ package, "# Generated from Nickel template - DO NOT EDIT DIRECTLY", "# Source: provisioning/schemas/platform/templates/docker/Dockerfile.chef.ncl", "", "# ============================================================================", "# Stage 1: PLANNER - Generate dependency recipe", "# ============================================================================", "FROM " ++ base_image ++ " AS planner", "", "WORKDIR /workspace", "", "# Install cargo-chef", "RUN cargo install cargo-chef --version 0.1.67", "", "# Copy workspace manifests", "COPY Cargo.toml Cargo.lock ./", "COPY crates ./crates", "COPY daemon-cli ./daemon-cli", "COPY secretumvault ./secretumvault", "COPY prov-ecosystem ./prov-ecosystem", "COPY stratumiops ./stratumiops", "", "# Generate recipe.json (dependency graph)", "RUN cargo chef prepare --recipe-path recipe.json --bin " ++ binary, "", "# ============================================================================", "# Stage 2: CACHER - Build dependencies only", "# ============================================================================", "FROM " ++ base_image ++ " AS cacher", "", "WORKDIR /workspace", "", "# Install build dependencies", "RUN apt-get update && apt-get install -y \\", " pkg-config \\", " libssl-dev \\", " && rm -rf /var/lib/apt/lists/*", "", "# Install cargo-chef", "RUN cargo install cargo-chef --version 0.1.67", "", (if sccache_enabled then sccache_install else "# sccache disabled"), "", "# Copy recipe from planner", "COPY --from=planner /workspace/recipe.json recipe.json", "", "# Build dependencies - This layer will be cached", "RUN cargo chef cook --release --recipe-path recipe.json " ++ features_arg, "", "# ============================================================================", "# Stage 3: BUILDER - Build source code", "# ============================================================================", "FROM " ++ base_image ++ " AS builder", "", "WORKDIR /workspace", "", "# Install build dependencies", "RUN apt-get update && apt-get install -y \\", " pkg-config \\", " libssl-dev \\", " && rm -rf /var/lib/apt/lists/*", "", (if sccache_enabled then sccache_install else "# sccache disabled"), "", "# Copy cached dependencies from cacher stage", "COPY --from=cacher /workspace/target target", "COPY --from=cacher /usr/local/cargo /usr/local/cargo", "", "# Copy source code", "COPY Cargo.toml Cargo.lock ./", "COPY crates ./crates", "COPY daemon-cli ./daemon-cli", "COPY secretumvault ./secretumvault", "COPY prov-ecosystem ./prov-ecosystem", "COPY stratumiops ./stratumiops", "", "# Build release binary with parallelism", "ENV CARGO_BUILD_JOBS=" ++ std.string.from_number buildkit_jobs, "RUN cargo build --release --package " ++ package ++ " " ++ features_arg, "", "# ============================================================================", "# Stage 4: RUNTIME - Minimal runtime image", "# ============================================================================", "FROM " ++ runtime_image, "", "# Install runtime dependencies", "RUN apt-get update && apt-get install -y \\", " ca-certificates \\", " curl" ++ extra_pkgs_str ++ " \\", " && rm -rf /var/lib/apt/lists/*", "", "# Create non-root user", "RUN useradd -m -u " ++ std.string.from_number user_id ++ " provisioning && \\", " mkdir -p /data /var/log/" ++ package ++ " && \\", " chown -R provisioning:provisioning /data /var/log/" ++ package, "", "# Copy binary from builder", "COPY --from=builder /workspace/target/release/" ++ binary ++ " /usr/local/bin/" ++ binary, "RUN chmod +x /usr/local/bin/" ++ binary, "", config_copy, "", "# Switch to non-root user", "USER provisioning", "WORKDIR /app", "", "# Expose service port", "EXPOSE " ++ std.string.from_number port, "", "# Environment variables", "ENV RUST_LOG=info", "ENV DATA_DIR=/data", "", "# Health check", "HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \\", " CMD curl -f http://localhost:" ++ std.string.from_number port ++ health_path ++ " || exit 1", "", "# Run the binary", "CMD [\"" ++ binary ++ "\"]", "", ]