Files
attune/docker/Dockerfile.optimized
David Culbreth 57fa3bf7cf
Some checks failed
CI / Rustfmt (push) Failing after 56s
CI / Clippy (push) Successful in 2m4s
CI / Web Blocking Checks (push) Successful in 50s
CI / Cargo Audit & Deny (push) Successful in 2m2s
CI / Security Blocking Checks (push) Successful in 10s
CI / Security Advisory Checks (push) Successful in 41s
Publish Images And Chart / Resolve Publish Metadata (push) Successful in 3s
Publish Images And Chart / Publish init-packs (push) Failing after 13s
Publish Images And Chart / Publish init-user (push) Failing after 11s
CI / Web Advisory Checks (push) Successful in 1m38s
Publish Images And Chart / Publish migrations (push) Failing after 11s
Publish Images And Chart / Publish web (push) Failing after 10s
Publish Images And Chart / Publish worker (push) Failing after 10s
Publish Images And Chart / Publish sensor (push) Failing after 31s
Publish Images And Chart / Publish api (push) Failing after 10s
Publish Images And Chart / Publish notifier (push) Failing after 11s
Publish Images And Chart / Publish executor (push) Failing after 31s
Publish Images And Chart / Publish Helm Chart (push) Has been skipped
CI / Tests (push) Successful in 1h34m2s
added oidc adapter
2026-03-18 16:35:21 -05:00

129 lines
5.6 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=33554432
# 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 && \
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, SQLx metadata, and migrations
COPY .sqlx/ ./.sqlx/
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 && \
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 configuration and migrations
COPY config.docker.yaml ./config.yaml
COPY migrations/ ./migrations/
RUN chown -R attune:attune /opt/attune
USER attune
ENV RUST_LOG=info
ENV ATTUNE_CONFIG=/opt/attune/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"]