Merge pull request 'refactor: deduplicate Rust Dockerfiles into shared template (#203)' (#216) from refactor/issue-203-dockerfile-dedup into main

This commit was merged in pull request #216.
This commit is contained in:
2026-03-11 11:37:52 +01:00
8 changed files with 115 additions and 229 deletions

View File

@@ -72,7 +72,11 @@ services:
audit: audit:
build: build:
context: .. context: ..
dockerfile: docker/rust/audit.Dockerfile dockerfile: docker/rust/service.Dockerfile
args:
SERVICE_DIR: audit
SERVICE_PACKAGE: audit-service
SERVICE_PORT: "50052"
container_name: llm-audit container_name: llm-audit
volumes: volumes:
- audit-data:/data - audit-data:/data
@@ -94,7 +98,11 @@ services:
secrets: secrets:
build: build:
context: .. context: ..
dockerfile: docker/rust/secrets.Dockerfile dockerfile: docker/rust/service.Dockerfile
args:
SERVICE_DIR: secrets
SERVICE_PACKAGE: secrets-service
SERVICE_PORT: "50053"
container_name: llm-secrets container_name: llm-secrets
volumes: volumes:
# D-Bus socket for host secret service (GNOME Keyring, KeePassXC). # D-Bus socket for host secret service (GNOME Keyring, KeePassXC).
@@ -120,7 +128,13 @@ services:
model-gateway: model-gateway:
build: build:
context: .. context: ..
dockerfile: docker/rust/model-gateway.Dockerfile dockerfile: docker/rust/service.Dockerfile
args:
SERVICE_DIR: model-gateway
SERVICE_PACKAGE: model-gateway
SERVICE_PORT: "50055"
EXTRA_BUILD_DEPS: "libssl-dev pkg-config"
EXTRA_RUNTIME_DEPS: "libssl3 ca-certificates"
container_name: llm-model-gateway container_name: llm-model-gateway
environment: environment:
- MODEL_GATEWAY_CONFIG=/etc/llm-multiverse/model-gateway.toml - MODEL_GATEWAY_CONFIG=/etc/llm-multiverse/model-gateway.toml
@@ -139,7 +153,12 @@ services:
memory: memory:
build: build:
context: .. context: ..
dockerfile: docker/rust/memory.Dockerfile dockerfile: docker/rust/service.Dockerfile
args:
SERVICE_DIR: memory
SERVICE_PACKAGE: memory-service
SERVICE_PORT: "50054"
EXTRA_BUILD_DEPS: "build-essential cmake"
container_name: llm-memory container_name: llm-memory
volumes: volumes:
- memory-data:/data - memory-data:/data
@@ -160,7 +179,11 @@ services:
tool-broker: tool-broker:
build: build:
context: .. context: ..
dockerfile: docker/rust/tool-broker.Dockerfile dockerfile: docker/rust/service.Dockerfile
args:
SERVICE_DIR: tool-broker
SERVICE_PACKAGE: tool-broker
SERVICE_PORT: "50057"
container_name: llm-tool-broker container_name: llm-tool-broker
volumes: volumes:
- ./manifests:/etc/llm-multiverse/manifests:ro - ./manifests:/etc/llm-multiverse/manifests:ro

View File

@@ -1,51 +0,0 @@
# Audit Service — multi-stage Dockerfile
# Build from repo root: docker build -f docker/rust/audit.Dockerfile -t llm-multiverse/audit-service .
# ---------- Builder ----------
FROM rust:1.85-bookworm AS builder
RUN apt-get update \
&& apt-get install -y --no-install-recommends protobuf-compiler \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Copy workspace manifests for dependency caching
COPY Cargo.toml Cargo.lock ./
COPY gen/rust/Cargo.toml gen/rust/
COPY services/audit/Cargo.toml services/audit/
COPY services/secrets/Cargo.toml services/secrets/
COPY services/memory/Cargo.toml services/memory/
COPY services/model-gateway/Cargo.toml services/model-gateway/
COPY services/tool-broker/Cargo.toml services/tool-broker/
# Create dummy sources for all workspace members
RUN mkdir -p gen/rust/src && echo "" > gen/rust/src/lib.rs \
&& mkdir -p services/audit/src && echo "fn main() {}" > services/audit/src/main.rs \
&& mkdir -p services/secrets/src && echo "fn main() {}" > services/secrets/src/main.rs \
&& mkdir -p services/memory/src && echo "fn main() {}" > services/memory/src/main.rs \
&& mkdir -p services/model-gateway/src && echo "fn main() {}" > services/model-gateway/src/main.rs \
&& mkdir -p services/tool-broker/src && echo "fn main() {}" > services/tool-broker/src/main.rs
# Build dependencies only (cached layer)
RUN cargo build --release -p audit-service 2>/dev/null ; true
# Copy real source
COPY proto/ proto/
COPY gen/rust/ gen/rust/
COPY services/audit/ services/audit/
# Touch source to force rebuild of the actual code
RUN touch services/audit/src/main.rs \
&& cargo build --release -p audit-service
# ---------- Runtime ----------
FROM debian:bookworm-slim
RUN groupadd -r app && useradd -r -g app -d /nonexistent -s /usr/sbin/nologin app
COPY --from=builder /app/target/release/audit-service /usr/local/bin/
USER app
EXPOSE 50052
ENTRYPOINT ["audit-service"]

View File

@@ -1,55 +0,0 @@
# Memory Service — multi-stage Dockerfile
# Build from repo root: docker build -f docker/rust/memory.Dockerfile -t llm-multiverse/memory-service .
# Note: DuckDB with bundled feature compiles from C++ source — first build may take 10+ minutes.
# ---------- Builder ----------
FROM rust:1.85-bookworm AS builder
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
protobuf-compiler \
build-essential \
cmake \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Copy workspace manifests for dependency caching
COPY Cargo.toml Cargo.lock ./
COPY gen/rust/Cargo.toml gen/rust/
COPY services/audit/Cargo.toml services/audit/
COPY services/secrets/Cargo.toml services/secrets/
COPY services/memory/Cargo.toml services/memory/
COPY services/model-gateway/Cargo.toml services/model-gateway/
COPY services/tool-broker/Cargo.toml services/tool-broker/
# Create dummy sources for all workspace members
RUN mkdir -p gen/rust/src && echo "" > gen/rust/src/lib.rs \
&& mkdir -p services/audit/src && echo "fn main() {}" > services/audit/src/main.rs \
&& mkdir -p services/secrets/src && echo "fn main() {}" > services/secrets/src/main.rs \
&& mkdir -p services/memory/src && echo "fn main() {}" > services/memory/src/main.rs \
&& mkdir -p services/model-gateway/src && echo "fn main() {}" > services/model-gateway/src/main.rs \
&& mkdir -p services/tool-broker/src && echo "fn main() {}" > services/tool-broker/src/main.rs
# Build dependencies only (cached layer — DuckDB bundled build is slow)
RUN cargo build --release -p memory-service 2>/dev/null ; true
# Copy real source
COPY proto/ proto/
COPY gen/rust/ gen/rust/
COPY services/memory/ services/memory/
# Touch source to force rebuild of the actual code
RUN touch services/memory/src/main.rs \
&& cargo build --release -p memory-service
# ---------- Runtime ----------
FROM debian:bookworm-slim
RUN groupadd -r app && useradd -r -g app -d /nonexistent -s /usr/sbin/nologin app
COPY --from=builder /app/target/release/memory-service /usr/local/bin/
USER app
EXPOSE 50054
ENTRYPOINT ["memory-service"]

View File

@@ -1,51 +0,0 @@
# Secrets Service — multi-stage Dockerfile
# Build from repo root: docker build -f docker/rust/secrets.Dockerfile -t llm-multiverse/secrets-service .
# ---------- Builder ----------
FROM rust:1.85-bookworm AS builder
RUN apt-get update \
&& apt-get install -y --no-install-recommends protobuf-compiler \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Copy workspace manifests for dependency caching
COPY Cargo.toml Cargo.lock ./
COPY gen/rust/Cargo.toml gen/rust/
COPY services/audit/Cargo.toml services/audit/
COPY services/secrets/Cargo.toml services/secrets/
COPY services/memory/Cargo.toml services/memory/
COPY services/model-gateway/Cargo.toml services/model-gateway/
COPY services/tool-broker/Cargo.toml services/tool-broker/
# Create dummy sources for all workspace members
RUN mkdir -p gen/rust/src && echo "" > gen/rust/src/lib.rs \
&& mkdir -p services/audit/src && echo "fn main() {}" > services/audit/src/main.rs \
&& mkdir -p services/secrets/src && echo "fn main() {}" > services/secrets/src/main.rs \
&& mkdir -p services/memory/src && echo "fn main() {}" > services/memory/src/main.rs \
&& mkdir -p services/model-gateway/src && echo "fn main() {}" > services/model-gateway/src/main.rs \
&& mkdir -p services/tool-broker/src && echo "fn main() {}" > services/tool-broker/src/main.rs
# Build dependencies only (cached layer)
RUN cargo build --release -p secrets-service 2>/dev/null ; true
# Copy real source
COPY proto/ proto/
COPY gen/rust/ gen/rust/
COPY services/secrets/ services/secrets/
# Touch source to force rebuild of the actual code
RUN touch services/secrets/src/main.rs \
&& cargo build --release -p secrets-service
# ---------- Runtime ----------
FROM debian:bookworm-slim
RUN groupadd -r app && useradd -r -g app -d /nonexistent -s /usr/sbin/nologin app
COPY --from=builder /app/target/release/secrets-service /usr/local/bin/
USER app
EXPOSE 50053
ENTRYPOINT ["secrets-service"]

View File

@@ -1,14 +1,29 @@
# Model Gateway — multi-stage Dockerfile # Shared Rust service Dockerfile template
# Build from repo root: docker build -f docker/rust/model-gateway.Dockerfile -t llm-multiverse/model-gateway . # Build from repo root with SERVICE_* build args:
# docker build -f docker/rust/service.Dockerfile \
# --build-arg SERVICE_DIR=audit --build-arg SERVICE_PACKAGE=audit-service --build-arg SERVICE_PORT=50052 \
# -t llm-multiverse/audit-service .
#
# Optional: EXTRA_BUILD_DEPS for services needing additional build-time APT packages
# EXTRA_RUNTIME_DEPS for services needing additional runtime APT packages
ARG SERVICE_DIR
ARG SERVICE_PACKAGE
ARG SERVICE_PORT=50058
ARG EXTRA_BUILD_DEPS=""
ARG EXTRA_RUNTIME_DEPS=""
# ---------- Builder ---------- # ---------- Builder ----------
FROM rust:1.85-bookworm AS builder FROM rust:1.85-bookworm AS builder
ARG SERVICE_DIR
ARG SERVICE_PACKAGE
ARG EXTRA_BUILD_DEPS
RUN apt-get update \ RUN apt-get update \
&& apt-get install -y --no-install-recommends \ && apt-get install -y --no-install-recommends \
protobuf-compiler \ protobuf-compiler \
libssl-dev \ ${EXTRA_BUILD_DEPS} \
pkg-config \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
WORKDIR /app WORKDIR /app
@@ -31,30 +46,34 @@ RUN mkdir -p gen/rust/src && echo "" > gen/rust/src/lib.rs \
&& mkdir -p services/tool-broker/src && echo "fn main() {}" > services/tool-broker/src/main.rs && mkdir -p services/tool-broker/src && echo "fn main() {}" > services/tool-broker/src/main.rs
# Build dependencies only (cached layer) # Build dependencies only (cached layer)
RUN cargo build --release -p model-gateway 2>/dev/null ; true RUN cargo build --release -p ${SERVICE_PACKAGE} 2>/dev/null ; true
# Copy real source # Copy real source
COPY proto/ proto/ COPY proto/ proto/
COPY gen/rust/ gen/rust/ COPY gen/rust/ gen/rust/
COPY services/model-gateway/ services/model-gateway/ COPY services/${SERVICE_DIR}/ services/${SERVICE_DIR}/
# Touch source to force rebuild of the actual code # Touch source to force rebuild of the actual code
RUN touch services/model-gateway/src/main.rs \ RUN touch services/${SERVICE_DIR}/src/main.rs \
&& cargo build --release -p model-gateway && cargo build --release -p ${SERVICE_PACKAGE}
# ---------- Runtime ---------- # ---------- Runtime ----------
FROM debian:bookworm-slim FROM debian:bookworm-slim
RUN apt-get update \ ARG SERVICE_PACKAGE
&& apt-get install -y --no-install-recommends \ ARG SERVICE_PORT
libssl3 \ ARG EXTRA_RUNTIME_DEPS
ca-certificates \
&& rm -rf /var/lib/apt/lists/* RUN if [ -n "${EXTRA_RUNTIME_DEPS}" ]; then \
apt-get update \
&& apt-get install -y --no-install-recommends ${EXTRA_RUNTIME_DEPS} \
&& rm -rf /var/lib/apt/lists/*; \
fi
RUN groupadd -r app && useradd -r -g app -d /nonexistent -s /usr/sbin/nologin app RUN groupadd -r app && useradd -r -g app -d /nonexistent -s /usr/sbin/nologin app
COPY --from=builder /app/target/release/model-gateway /usr/local/bin/ COPY --from=builder /app/target/release/${SERVICE_PACKAGE} /usr/local/bin/service
USER app USER app
EXPOSE 50055 EXPOSE ${SERVICE_PORT}
ENTRYPOINT ["model-gateway"] ENTRYPOINT ["service"]

View File

@@ -1,51 +0,0 @@
# Tool Broker — multi-stage Dockerfile
# Build from repo root: docker build -f docker/rust/tool-broker.Dockerfile -t llm-multiverse/tool-broker .
# ---------- Builder ----------
FROM rust:1.85-bookworm AS builder
RUN apt-get update \
&& apt-get install -y --no-install-recommends protobuf-compiler \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
# Copy workspace manifests for dependency caching
COPY Cargo.toml Cargo.lock ./
COPY gen/rust/Cargo.toml gen/rust/
COPY services/audit/Cargo.toml services/audit/
COPY services/secrets/Cargo.toml services/secrets/
COPY services/memory/Cargo.toml services/memory/
COPY services/model-gateway/Cargo.toml services/model-gateway/
COPY services/tool-broker/Cargo.toml services/tool-broker/
# Create dummy sources for all workspace members
RUN mkdir -p gen/rust/src && echo "" > gen/rust/src/lib.rs \
&& mkdir -p services/audit/src && echo "fn main() {}" > services/audit/src/main.rs \
&& mkdir -p services/secrets/src && echo "fn main() {}" > services/secrets/src/main.rs \
&& mkdir -p services/memory/src && echo "fn main() {}" > services/memory/src/main.rs \
&& mkdir -p services/model-gateway/src && echo "fn main() {}" > services/model-gateway/src/main.rs \
&& mkdir -p services/tool-broker/src && echo "fn main() {}" > services/tool-broker/src/main.rs
# Build dependencies only (cached layer)
RUN cargo build --release -p tool-broker 2>/dev/null ; true
# Copy real source
COPY proto/ proto/
COPY gen/rust/ gen/rust/
COPY services/tool-broker/ services/tool-broker/
# Touch source to force rebuild of the actual code
RUN touch services/tool-broker/src/main.rs \
&& cargo build --release -p tool-broker
# ---------- Runtime ----------
FROM debian:bookworm-slim
RUN groupadd -r app && useradd -r -g app -d /nonexistent -s /usr/sbin/nologin app
COPY --from=builder /app/target/release/tool-broker /usr/local/bin/
USER app
EXPOSE 50057
ENTRYPOINT ["tool-broker"]

View File

@@ -109,6 +109,7 @@
| #200 | Refactor: consolidate duplicated _AGENT_TYPE_NAMES mappings | — | `COMPLETED` | Python | [issue-200.md](issue-200.md) | | #200 | Refactor: consolidate duplicated _AGENT_TYPE_NAMES mappings | — | `COMPLETED` | Python | [issue-200.md](issue-200.md) |
| #201 | Refactor: extract duplicated _CONFIDENCE_MAP and _JSON_BLOCK_RE | — | `COMPLETED` | Python | [issue-201.md](issue-201.md) | | #201 | Refactor: extract duplicated _CONFIDENCE_MAP and _JSON_BLOCK_RE | — | `COMPLETED` | Python | [issue-201.md](issue-201.md) |
| #202 | Bug: Docker network missing internal:true and edge separation | — | `COMPLETED` | Docker / YAML | [issue-202.md](issue-202.md) | | #202 | Bug: Docker network missing internal:true and edge separation | — | `COMPLETED` | Docker / YAML | [issue-202.md](issue-202.md) |
| #203 | Refactor: deduplicate Rust Dockerfile builder stage boilerplate | — | `COMPLETED` | Docker | [issue-203.md](issue-203.md) |
## Status Legend ## Status Legend

View File

@@ -0,0 +1,51 @@
# Implementation Plan — Issue #203: Deduplicate Rust Dockerfile builder stage boilerplate
## Metadata
| Field | Value |
|---|---|
| Issue | [#203](https://git.shahondin1624.de/llm-multiverse/llm-multiverse/issues/203) |
| Title | Refactor: deduplicate Rust Dockerfile builder stage boilerplate |
| Milestone | — (tech debt) |
| Labels | `type:refactor`, `priority:medium`, `cat:docker` |
| Status | `COMPLETED` |
| Language | Docker |
| Related Plans | [issue-089.md](issue-089.md) |
| Blocked by | — |
## Acceptance Criteria
- [x] Single shared `docker/rust/service.Dockerfile` parameterized with ARGs
- [x] All 5 Rust services use the shared template via docker-compose build args
- [x] Old per-service Dockerfiles deleted
- [x] `EXTRA_BUILD_DEPS` / `EXTRA_RUNTIME_DEPS` ARGs for services needing additional packages
- [x] ENTRYPOINT uses fixed binary name to avoid ARG expansion issues in JSON form
## Implementation Steps
### 1. Create shared ARG-parameterized Dockerfile
Created `docker/rust/service.Dockerfile` with ARGs: `SERVICE_DIR`, `SERVICE_PACKAGE`, `SERVICE_PORT`, `EXTRA_BUILD_DEPS`, `EXTRA_RUNTIME_DEPS`. Binary renamed to fixed `service` to work around Docker ENTRYPOINT JSON form not expanding ARGs.
### 2. Update docker-compose.yml
Updated all 5 Rust service build sections to use `dockerfile: docker/rust/service.Dockerfile` with appropriate build args.
### 3. Delete old Dockerfiles
Removed `audit.Dockerfile`, `secrets.Dockerfile`, `memory.Dockerfile`, `model-gateway.Dockerfile`, `tool-broker.Dockerfile`.
## Files Created/Modified
| File | Action | Purpose |
|---|---|---|
| `docker/rust/service.Dockerfile` | Create | Shared ARG-parameterized template |
| `docker/docker-compose.yml` | Modify | Use shared Dockerfile with build args |
| `docker/rust/audit.Dockerfile` | Delete | Replaced by shared template |
| `docker/rust/secrets.Dockerfile` | Delete | Replaced by shared template |
| `docker/rust/memory.Dockerfile` | Delete | Replaced by shared template |
| `docker/rust/model-gateway.Dockerfile` | Delete | Replaced by shared template |
| `docker/rust/tool-broker.Dockerfile` | Delete | Replaced by shared template |
## Deviation Log
| Deviation | Reason |
|---|---|
| Binary renamed to fixed `service` instead of using `${SERVICE_PACKAGE}` in ENTRYPOINT | Docker ENTRYPOINT JSON form does not expand ARG/ENV variables |