-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathDockerfile
More file actions
123 lines (99 loc) · 5.26 KB
/
Copy pathDockerfile
File metadata and controls
123 lines (99 loc) · 5.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# ============================================================================
# GarraIA — Multi-stage Dockerfile
# Target: < 50MB final image with Node.js 22 for MCP servers
# ============================================================================
# ---------------------------------------------------------------------------
# Stage 1: Chef — prepare recipe for dependency caching
# ---------------------------------------------------------------------------
FROM rust:1.92-slim AS chef
RUN apt-get update && apt-get install -y --no-install-recommends \
pkg-config libssl-dev \
&& rm -rf /var/lib/apt/lists/*
RUN cargo install cargo-chef --locked
WORKDIR /build
# ---------------------------------------------------------------------------
# Stage 2: Planner — generate build recipe from source
# ---------------------------------------------------------------------------
FROM chef AS planner
COPY Cargo.toml Cargo.lock ./
COPY crates/ crates/
RUN cargo chef prepare --recipe-path recipe.json
# ---------------------------------------------------------------------------
# Stage 3: Builder — compile release binary with cached deps
# ---------------------------------------------------------------------------
FROM chef AS builder
COPY --from=planner /build/recipe.json recipe.json
# Build dependencies only (cached layer) — scoped to the `garra` binary so
# we don't warm up Tauri/glib for `garraia-desktop`, which is workspace-only
# and not part of this image.
RUN cargo chef cook --release --recipe-path recipe.json --bin garra
# Copy full source and build
COPY Cargo.toml Cargo.lock ./
COPY crates/ crates/
RUN cargo build --release --package garraia \
&& strip target/release/garra
# ---------------------------------------------------------------------------
# Stage 4: Node — install Node.js 22 minimal for MCP servers
# ---------------------------------------------------------------------------
FROM debian:bookworm-slim AS node-installer
RUN apt-get update && apt-get install -y --no-install-recommends \
curl ca-certificates \
&& rm -rf /var/lib/apt/lists/*
RUN curl -fsSL https://deb.nodesource.com/setup_22.x | bash - \
&& apt-get install -y --no-install-recommends nodejs \
&& rm -rf /var/lib/apt/lists/* \
&& npm cache clean --force
# ---------------------------------------------------------------------------
# Stage 5: Runtime — minimal production image
# ---------------------------------------------------------------------------
# Must match the builder's glibc. `rust:1.92-slim` (chef base, line 9) is
# debian:trixie with glibc 2.39, so the `garra` binary is linked against
# 2.39. Using bookworm here (glibc 2.36) made the binary fail at startup
# with `GLIBC_2.39 not found` — discovered during the GAR-603 Runpod local
# smoke test on 2026-05-13 (first runtime exercise of the image after the
# rust:1.86 → 1.92 bump in PR #314, commit c1483e6). Same root cause as
# the Runpod LB "timed out waiting for worker" symptom on endpoint
# k3d2h9xumk2r4o: the worker container exited(1) before binding the port.
#
# Trixie's newer glibc is backward-compatible, so the Node 22 binary copied
# from the bookworm-based node-installer stage continues to work here.
FROM debian:trixie-slim AS runtime
LABEL org.opencontainers.image.title="GarraIA Gateway" \
org.opencontainers.image.description="Multi-channel, multi-provider LLM orchestration gateway" \
org.opencontainers.image.vendor="michelbr84" \
org.opencontainers.image.source="https://github.com/michelbr84/GarraRUST" \
org.opencontainers.image.licenses="MIT" \
org.opencontainers.image.version="0.3.0"
# Install only essential runtime deps
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates curl tini \
&& rm -rf /var/lib/apt/lists/*
# Copy Node.js from installer stage
COPY --from=node-installer /usr/bin/node /usr/bin/node
COPY --from=node-installer /usr/bin/npx /usr/bin/npx
COPY --from=node-installer /usr/bin/npm /usr/bin/npm
COPY --from=node-installer /usr/lib/node_modules /usr/lib/node_modules
# Copy compiled binary
COPY --from=builder /build/target/release/garra /usr/local/bin/garra
# Create non-root user
RUN groupadd --gid 1000 garraia \
&& useradd --uid 1000 --gid 1000 --create-home --shell /bin/bash garraia \
&& mkdir -p /home/garraia/.config/garraia/data \
/home/garraia/.config/garraia/credentials \
/home/garraia/.config/garraia/skills \
&& chown -R garraia:garraia /home/garraia
USER garraia
WORKDIR /home/garraia
EXPOSE 3888
# GAR-603 — Use `/ping` for the container-level healthcheck so it matches
# what Runpod Load Balancer Serverless probes on `PORT_HEALTH`. `/ping` is
# stateless and DB-free; `/health` is heavier and aggregates provider
# status (still available as a richer probe for orchestrators that want it).
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD curl -sf http://localhost:3888/ping || exit 1
ENTRYPOINT ["tini", "--", "garra"]
# `garra start` honors `PORT` and `HOST` env vars (GAR-603) — Runpod /
# container runtimes that set them get the right binding without
# overriding CMD. Explicit `--host 0.0.0.0` here ensures the default
# `docker run` (no env) still binds to all interfaces.
CMD ["start", "--host", "0.0.0.0"]