128 lines
5.7 KiB
Docker
128 lines
5.7 KiB
Docker
# Multi-stage Dockerfile for Attune Rust services (api, executor, sensor, notifier)
|
|
#
|
|
# Simple and robust: build the entire workspace, then copy the target binary.
|
|
# No dummy sources, no selective crate copying, no fragile hacks.
|
|
#
|
|
# Usage:
|
|
# DOCKER_BUILDKIT=1 docker build --build-arg SERVICE=api -f docker/Dockerfile.optimized -t attune-api .
|
|
# DOCKER_BUILDKIT=1 docker build --build-arg SERVICE=executor -f docker/Dockerfile.optimized -t attune-executor .
|
|
# DOCKER_BUILDKIT=1 docker build --build-arg SERVICE=sensor -f docker/Dockerfile.optimized -t attune-sensor .
|
|
# DOCKER_BUILDKIT=1 docker build --build-arg SERVICE=notifier -f docker/Dockerfile.optimized -t attune-notifier .
|
|
#
|
|
# Note: Packs are NOT copied into the image — they are mounted as volumes at runtime.
|
|
|
|
ARG RUST_VERSION=1.92
|
|
ARG DEBIAN_VERSION=bookworm
|
|
|
|
# ============================================================================
|
|
# Stage 1: Builder - Compile the entire workspace
|
|
# ============================================================================
|
|
FROM rust:${RUST_VERSION}-${DEBIAN_VERSION} AS builder
|
|
|
|
RUN apt-get update && apt-get install -y \
|
|
pkg-config \
|
|
libssl-dev \
|
|
ca-certificates \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
WORKDIR /build
|
|
|
|
# Increase rustc stack size to prevent SIGSEGV during release builds
|
|
ENV RUST_MIN_STACK=67108864
|
|
|
|
# Copy dependency metadata first so `cargo fetch` layer is cached
|
|
# when only source code changes (Cargo.toml/Cargo.lock stay the same)
|
|
COPY Cargo.toml Cargo.lock ./
|
|
COPY crates/common/Cargo.toml ./crates/common/Cargo.toml
|
|
COPY crates/api/Cargo.toml ./crates/api/Cargo.toml
|
|
COPY crates/executor/Cargo.toml ./crates/executor/Cargo.toml
|
|
COPY crates/sensor/Cargo.toml ./crates/sensor/Cargo.toml
|
|
COPY crates/core-timer-sensor/Cargo.toml ./crates/core-timer-sensor/Cargo.toml
|
|
COPY crates/worker/Cargo.toml ./crates/worker/Cargo.toml
|
|
COPY crates/notifier/Cargo.toml ./crates/notifier/Cargo.toml
|
|
COPY crates/cli/Cargo.toml ./crates/cli/Cargo.toml
|
|
|
|
# Create minimal stub sources so cargo can resolve the workspace and fetch deps.
|
|
# These are ONLY used for `cargo fetch` — never compiled.
|
|
RUN mkdir -p crates/common/src && echo "" > crates/common/src/lib.rs && \
|
|
mkdir -p crates/api/src && echo "fn main(){}" > crates/api/src/main.rs && \
|
|
mkdir -p crates/executor/src && echo "fn main(){}" > crates/executor/src/main.rs && \
|
|
mkdir -p crates/executor/benches && echo "fn main(){}" > crates/executor/benches/context_clone.rs && \
|
|
mkdir -p crates/sensor/src && echo "fn main(){}" > crates/sensor/src/main.rs && \
|
|
mkdir -p crates/core-timer-sensor/src && echo "fn main(){}" > crates/core-timer-sensor/src/main.rs && \
|
|
mkdir -p crates/worker/src && echo "fn main(){}" > crates/worker/src/main.rs && \
|
|
echo "fn main(){}" > crates/worker/src/agent_main.rs && \
|
|
mkdir -p crates/notifier/src && echo "fn main(){}" > crates/notifier/src/main.rs && \
|
|
mkdir -p crates/cli/src && echo "fn main(){}" > crates/cli/src/main.rs
|
|
|
|
# Download all dependencies (cached unless Cargo.toml/Cargo.lock change)
|
|
# registry/git use sharing=shared — cargo handles concurrent reads safely
|
|
RUN --mount=type=cache,target=/usr/local/cargo/registry,sharing=shared \
|
|
--mount=type=cache,target=/usr/local/cargo/git,sharing=shared \
|
|
cargo fetch
|
|
|
|
# Now copy the real source code and migrations
|
|
COPY migrations/ ./migrations/
|
|
COPY crates/ ./crates/
|
|
|
|
# Build the entire workspace in release mode.
|
|
# All binaries are compiled together, sharing dependency compilation.
|
|
# target cache uses sharing=locked so concurrent service builds serialize
|
|
# writes to the shared compilation cache instead of corrupting it.
|
|
#
|
|
# IMPORTANT: ARG SERVICE is declared AFTER this RUN so that changing the
|
|
# SERVICE value does not invalidate the cached build layer. The first
|
|
# service to build compiles the full workspace; subsequent services get
|
|
# a cache hit here and skip straight to the cp below.
|
|
RUN --mount=type=cache,target=/usr/local/cargo/registry,sharing=shared \
|
|
--mount=type=cache,target=/usr/local/cargo/git,sharing=shared \
|
|
--mount=type=cache,target=/build/target,sharing=locked \
|
|
cargo build --release --workspace --bins -j 4
|
|
|
|
# Extract the requested service binary from the target cache.
|
|
# This is the only layer that varies per SERVICE value.
|
|
ARG SERVICE=api
|
|
RUN --mount=type=cache,target=/build/target,sharing=locked \
|
|
cp /build/target/release/attune-${SERVICE} /build/attune-service-binary
|
|
|
|
# ============================================================================
|
|
# Stage 2: Runtime - Minimal image with just the service binary
|
|
# ============================================================================
|
|
FROM debian:${DEBIAN_VERSION}-slim AS runtime
|
|
|
|
RUN apt-get update && apt-get install -y \
|
|
ca-certificates \
|
|
libssl3 \
|
|
curl \
|
|
git \
|
|
&& rm -rf /var/lib/apt/lists/*
|
|
|
|
# Create non-root user and directories
|
|
# /opt/attune/packs is mounted as a volume at runtime, not copied in
|
|
RUN useradd -m -u 1000 attune && \
|
|
mkdir -p /opt/attune/packs /opt/attune/logs /opt/attune/runtime_envs /opt/attune/config && \
|
|
chown -R attune:attune /opt/attune
|
|
|
|
WORKDIR /opt/attune
|
|
|
|
# Copy the service binary from builder using a fixed path (no variable in COPY source)
|
|
# This avoids the circular dependency Docker hits when using ARG in --from paths
|
|
COPY --from=builder /build/attune-service-binary /usr/local/bin/attune-service
|
|
|
|
# Copy migrations only. Runtime config is mounted via Docker Compose.
|
|
COPY migrations/ ./migrations/
|
|
|
|
RUN chown -R attune:attune /opt/attune
|
|
|
|
USER attune
|
|
|
|
ENV RUST_LOG=info
|
|
ENV ATTUNE_CONFIG=/opt/attune/config/config.yaml
|
|
|
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
|
|
CMD curl -f http://localhost:8080/health || exit 1
|
|
|
|
EXPOSE 8080
|
|
|
|
CMD ["/usr/local/bin/attune-service"]
|