This directory contains the Docker build configuration for the dcipher project, implementing a multi-stage caching strategy optimized for CI/CD pipelines.
The Docker setup is designed around two key principles:
- Split Dockerfiles for CI/CD: Separate build stages that can be cached independently
- Full Dockerfile for Standalone Builds: A complete Dockerfile that can build from scratch while benefiting from existing cached layers
- Purpose: Builds and caches Rust dependencies using
cargo-chef - Key Feature: Creates a cached layer containing all compiled dependencies
- Usage: Run first in CI to establish the dependency cache layer
- Output: Intermediate image with compiled Rust dependencies
# Builds dependencies - this is the caching Docker layer!
RUN cargo chef cook --release --recipe-path recipe.json- Purpose: Builds Solidity contracts using Foundry
- Key Feature: Compiles smart contracts and caches the build artifacts
- Parameters:
SOLIDITY_PROJECT_DIR: Which Solidity project to build (e.g., "blocklock-solidity")
- Output: Intermediate image with compiled Solidity contracts
- Purpose: Complete standalone Dockerfile for building any Rust application
- Key Feature: Can build independently OR reuse cached layers from previous stages
- Parameters:
APPLICATION: Name of the Rust application to buildSOLIDITY_PROJECT_DIR: Which Solidity contracts to include
- Strategy: Duplicates the dependency building steps so it can work standalone, but benefits from cached layers when available
- Dependency Caching: Rust dependencies are built once and reused across all applications
- Solidity Caching: Smart contracts are compiled once per project and reused
- Parallel Builds: Multiple applications can build concurrently using shared cached layers
- Incremental Updates: Only rebuild what actually changed
- Standalone Capability: Each application can be built independently
- Layer Reuse: Automatically benefits from any existing cached layers
- Fast Rebuilds: Dependency changes only require rebuilding the dependency layer
The docker-bake.hcl file orchestrates the build process:
_base-config: Common configuration (context, etc.)_solidity-builder: Base for Solidity buildsrust-deps-builder: Rust dependency cache builderrust-app: Generic Rust application builder
blocklock-weft: Blocklock application with blocklock-solidity contractsrandomness-weft: Randomness application with randomness-solidity contracts- Additional applications can be added following the same pattern
base-configs: Core infrastructure imagesbuilders: Solidity contract buildersdcipher-apps: All application imagesblocklock: Complete blocklock stack
# Step 1: Build shared dependency cache
docker buildx bake rust-deps-builder
# Step 2: Build Solidity contracts in parallel
docker buildx bake builders
# Step 3: Build all applications (reusing cached layers)
docker buildx bake dcipher-apps# Build a single application (will reuse any existing cached layers)
docker buildx bake blocklock-weft
# Build everything from scratch
docker buildx bake# Build with custom parameters
docker buildx bake rust-app --set rust-app.args.APPLICATION=my-app --set rust-app.args.SOLIDITY_PROJECT_DIR=my-contracts- Base OS + Tools: Node.js, Rust, Foundry (rarely changes)
- Package Dependencies: npm packages, Cargo dependencies (changes occasionally)
- Contract Compilation: Solidity builds (changes with contract updates)
- Application Code: Rust application builds (changes frequently)
- Rust Dependencies: Invalidated when
Cargo.tomlorCargo.lockchanges - Solidity Contracts: Invalidated when contract source files change
- Application Code: Invalidated when application source changes
To add a new application:
- Create application Dockerfile in the crate directory (following existing patterns)
- Add target to docker-bake.hcl:
target "my-new-app" { inherits = ["rust-app"] tags = [ "${DOCKER_REGISTRY}/my-new-app:${IMAGE_TAG}" ] args = { APPLICATION = "my-new-app" SOLIDITY_PROJECT_DIR = "relevant-solidity-project" } }
- Update build groups as needed
- Cold Build: ~10-15 minutes (compiling all dependencies)
- Warm Build: ~2-3 minutes (reusing cached layers)
- Code-only Changes: ~30-60 seconds (only rebuilding application layer)
- Parallel Builds: Multiple applications build concurrently after shared stages complete
- Use
docker buildx pruneto clear build cache if needed - Check layer reuse with
docker buildx bake --progress=plain
- Ensure you're building from the repository root
- Verify all required build arguments are provided
- Check that Solidity contracts compile successfully
- Matrix Builds: The bakefile is being enhanced to use matrix builds for automatic target generation
- Multi-arch Support: Planned support for ARM64 and AMD64 architectures
- Registry Optimization: Enhanced layer sharing across different applications