-
Notifications
You must be signed in to change notification settings - Fork 44
Expand file tree
/
Copy pathDockerfile
More file actions
199 lines (176 loc) · 9.06 KB
/
Copy pathDockerfile
File metadata and controls
199 lines (176 loc) · 9.06 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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# syntax=docker/dockerfile:1
# ─────────────────────────────────────────────────────────────────────────────
# DonSeTch MCP server — production image
#
# Builds from the local source tree (this repo).
#
# Build: docker build -t donsetch-mcp .
# Run: docker compose run --rm donsetch (recommended — see docker-compose.yml)
# or: docker run -i --rm --init donsetch-mcp donsetch mcp --supervised
#
# Optional Chrome for tier 2 browser escalation:
# docker build --build-arg INSTALL_CHROME=true -t donsetch-mcp .
#
# The container runs the MCP server on stdio. Connect from your MCP
# client:
# Claude Code: mcp server config using "docker run -i --rm donsetch-mcp donsetch mcp --supervised"
# Cursor/OpenCode: stdio MCP configuration
#
# Note: build.rs downloads and sha256-verifies the PDFium static archive
# and the ONNX Runtime archive at build time, exactly as the upstream CI
# does (curl + tar are needed).
# ─────────────────────────────────────────────────────────────────────────────
# Optional: install Chrome for tier 2 browser escalation (bot-wall bypass).
# Adds ~350MB. Enable with: docker build --build-arg INSTALL_CHROME=true .
ARG INSTALL_CHROME=false
# ── Builder stage ─────────────────────────────────────────────────────────────
# Use Rust slim image (Debian-based, edition2024 support in Rust 1.82+)
#
# Both stages must share one modern Debian generation. The ort-sys
# prebuilt ONNX Runtime archives reference glibc 2.38+ symbols
# (__isoc23_strtoll/strtoull), so they will not link against an older
# glibc — and a binary built against a newer glibc will not run on one.
# rust:slim and debian:trixie-slim track Debian trixie together.
FROM rust:slim AS builder
# Install build dependencies for boring-sys (BoringSSL) and PDFium.
# Go is required by BoringSSL's build system; NASM builds the x86_64
# crypto assembly; libclang drives bindgen.
RUN apt-get update && apt-get install -y --no-install-recommends \
cmake \
g++ \
gcc \
gnupg \
libclang-dev \
libssl-dev \
make \
nasm \
curl \
tar \
git \
pkg-config \
&& rm -rf /var/lib/apt/lists/*
# Install Go (required for BoringSSL's build system). TARGETARCH
# (amd64/arm64, injected by BuildKit; falls back to the host arch for
# classic builds) selects the tarball so arm64 builds work too.
ARG TARGETARCH
RUN arch="${TARGETARCH:-$(dpkg --print-architecture)}" \
&& curl -fsSL "https://go.dev/dl/go1.23.4.linux-${arch}.tar.gz" -o /tmp/go.tar.gz \
&& tar -C /usr/local -xzf /tmp/go.tar.gz \
&& rm /tmp/go.tar.gz
ENV PATH="/usr/local/go/bin:${PATH}"
WORKDIR /build
# Copy source code (build.rs must ship: it acquires + links PDFium
# and emits the linux_like cfg)
COPY Cargo.toml Cargo.lock README.md LICENSE ./
COPY build.rs ./
COPY src/ ./src/
COPY tests/ ./tests/
# Pre-fetch PDFium before cargo build. build.rs vendors the library
# under vendor/pdfium and skips its own download once lib/libpdfium.a
# exists — but its curl path gives up on a single mid-transfer reset
# (curl 35 is not retried without --retry-all-errors). Filtered or
# flaky networks that stall then reset long transfers die there, so
# fetch here first with aggressive retries and stall detection, and
# verify the same sha256 pins build.rs enforces (KNOWN_HASHES) to
# keep the download fail-closed.
ARG TARGETARCH
RUN set -eu; \
arch="${TARGETARCH:-$(dpkg --print-architecture)}"; \
pair="linux-x64"; \
hash="13908bb2d40a6e017c4c5a6a7baecc6efd7b1c30392c8a79e80072d2b48b18eb"; \
if [ "$arch" = "arm64" ] || [ "$arch" = "aarch64" ]; then \
pair="linux-arm64"; \
hash="abe1c3d5b168ec2baaafc7a8fcddfda1a09417f39199c7993fd28d34d3a7f70e"; \
fi; \
url="https://github.com/kognitos/pdfium-static/releases/download/chromium/7809/pdfium-${pair}-static.tgz"; \
mkdir -p vendor/pdfium; \
curl -fSL --proto '=https' --proto-redir '=https' \
--retry 8 --retry-all-errors --retry-delay 3 \
--connect-timeout 20 --speed-time 30 --speed-limit 1024 \
-o /tmp/pdfium.tgz "$url"; \
echo "${hash} /tmp/pdfium.tgz" | sha256sum -c -; \
tar -xzf /tmp/pdfium.tgz -C vendor/pdfium; \
rm /tmp/pdfium.tgz
# Build all features (OCR + semantic reranking), locked to Cargo.lock
ENV CARGO_TERM_COLOR=always
# All three features: ocr + rerank (ONNX) and http (axum/tower-http
# streamable-HTTP transport, same set as the linux-x64/macOS-arm64/
# Windows-x64 release binaries).
RUN cargo build --release --features ocr,rerank,http --locked
# Stage the ONNX Runtime shared library for the runtime image. Since
# 3.2.5, ort loads ONNX Runtime dynamically: when ocr/rerank are
# enabled, build.rs builds vendor/onnx/libonnxruntime.so from the pyke
# CDN archive and the binary dlopens it at runtime (searched next to
# the executable first, then the cache dir). Stage only the .so — the
# vendor/onnx dir also holds the large static archive, which the
# runtime image does not need. arm64 has no ONNX prebuilt: stage an
# empty dir there so the runtime COPY is a no-op and ocr/rerank
# self-disable at runtime with a notice instead of failing the build.
RUN mkdir -p /stage-onnx \
&& if [ -f vendor/onnx/libonnxruntime.so ]; then \
cp vendor/onnx/libonnxruntime.so /stage-onnx/; \
fi
# ── Runtime stage ─────────────────────────────────────────────────────────────
# Minimal Debian image for runtime — trixie, matching the builder stage's
# glibc generation (see the glibc note on the builder stage above)
FROM debian:trixie-slim
# Install runtime dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
libgcc-s1 \
&& rm -rf /var/lib/apt/lists/*
# Optional: install Chrome for tier 2 browser escalation
ARG INSTALL_CHROME=false
RUN if [ "$INSTALL_CHROME" = "true" ]; then \
apt-get update && \
apt-get install -y --no-install-recommends chromium xvfb && \
rm -rf /var/lib/apt/lists/*; \
fi
# Copy binary from builder
COPY --from=builder /build/target/release/donsetch /usr/local/bin/donsetch
# ONNX Runtime shared library (ocr + rerank features, dynamic since
# 3.2.5). The binary looks for it next to the executable first, then
# $cache_dir/onnx/ — /usr/local/bin satisfies the first even when an
# older cache volume shadows the second. Empty dir on arm64: nothing
# is copied and the features degrade at runtime.
COPY --from=builder /stage-onnx/ /usr/local/bin/
# Verify binary works
RUN donsetch --version
# ── Non-root runtime user ────────────────────────────────────────────────────
# The cache dir must exist and be donsetch-owned before the VOLUME
# declaration below: when it is absent from the image, the daemon
# creates a root-owned mountpoint and fresh volumes stay root-owned,
# so the non-root user can neither write the fetch cache nor download
# the rerank model on first use.
RUN useradd -m -u 1000 donsetch \
&& mkdir -p /home/donsetch/.cache/donsetch \
&& chown -R donsetch:donsetch /home/donsetch/.cache
USER donsetch
WORKDIR /home/donsetch
# Cache directory for fetch/search results and ghost browser profile.
# The server resolves it as $HOME/.cache/donsetch (XDG_CACHE_HOME is
# honoured too); no env var is needed. VOLUME makes plain `docker run`
# persist it in an anonymous volume.
# Chromium's sandbox cannot initialize inside a default Docker container
# (no unprivileged user namespaces): the browser dies at launch before the
# DevTools handshake. Upstream's documented container escape hatch
# (`DONGHOST_NO_SANDBOX=1`, see ghost docs) is therefore the correct
# default for this image. The container boundary + non-root user provide
# the isolation the sandbox would on a host.
ENV DONGHOST_NO_SANDBOX=1
VOLUME /home/donsetch/.cache/donsetch
# Set Chrome path if Chrome was installed
RUN if [ "$INSTALL_CHROME" = "true" ]; then \
echo "chromium found at $(which chromium)" && \
echo "Set DONGHOST_CHROME=/usr/bin/chromium for browser escalation"; \
fi
# Healthcheck: verify binary responds to version check
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
CMD donsetch --version || exit 1
# Port for the HTTP transport (compose activates it via
# DONSETCH_TRANSPORT=http in the http profile).
EXPOSE 8765
# Run the MCP server on stdio with crash-only supervisor.
# HTTP mode: docker run -d -p 127.0.0.1:8765:8765 \
# -e DONSETCH_TRANSPORT=http -e DONSETCH_HTTP_HOST=0.0.0.0 donsetch-mcp
CMD ["donsetch", "mcp", "--supervised"]