-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDockerfile
More file actions
111 lines (86 loc) · 4.08 KB
/
Copy pathDockerfile
File metadata and controls
111 lines (86 loc) · 4.08 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
# Stage 1: Builder — compiles deps, NIF, and application
FROM elixir:1.19.5-otp-27-slim AS builder
WORKDIR /app
# Install build dependencies
RUN apt-get update && apt-get install -y \
build-essential \
git \
curl \
&& rm -rf /var/lib/apt/lists/*
# Install Rust (for tree-sitter NIF compilation)
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
ENV PATH="/root/.cargo/bin:${PATH}"
# Build in prod mode so the compiled artefacts land in _build/prod/
# matching what docker-compose.yml sets at runtime (MIX_ENV=prod).
ENV MIX_ENV=prod
# Copy mix files first for better layer caching.
# Use a dummy VERSION so version bumps don't bust the deps layer.
COPY mix.exs mix.lock ./
RUN echo "0.0.0" > VERSION
# Install Elixir dependencies (limit parallelism to avoid OOM)
RUN mix local.hex --force && \
mix local.rebar --force && \
mix deps.get
# Compile deps separately to limit memory usage
ENV ERL_FLAGS="+JMsingle true"
RUN mix deps.compile --no-optional 2>/dev/null; mix deps.compile || true
# Patch ex_mcp tool call timeout (default 10s -> 120s) for long-running tools like reindex.
# ExMCP 0.9.0 has no config option for this; patch is applied at build time.
# TODO: remove once https://github.com/cloudwalk/ex_mcp supports configurable timeouts.
RUN sed -i 's/{:execute_tool, tool_name, arguments}, 10_*000\b/{:execute_tool, tool_name, arguments}, 120_000/' \
deps/ex_mcp/lib/ex_mcp/message_processor.ex
# Patch ex_mcp Cowboy max_header_value_length (default 4096 -> 32768).
# Claude Code's MCP HTTP client sends large headers that exceed the Cowboy default,
# causing HTTP 431 responses and MCP disconnects. Targets only the production
# cowboy_opts block (no trailing comma = not the test-isolation ranch_ref path).
RUN sed -z -i 's/ip: parse_host(host)\n ]/ip: parse_host(host),\n protocol_options: [max_header_value_length: 32_768]\n ]/' \
deps/ex_mcp/lib/ex_mcp/server/transport.ex && \
mix deps.compile ex_mcp --force
# Copy native code (Rust NIFs)
COPY native native
# Copy real VERSION now (after deps) so version bumps don't bust the deps cache
COPY VERSION .
# Copy source code and config
COPY lib lib
COPY config config
COPY priv priv
# Bundled skills are read at compile time by Resources.skill_index/0 and embedded
# in the module binary. Without this copy, the published image ships zero skills.
COPY .agents .agents
# Remove macOS NIF binary (will be rebuilt for Linux below)
RUN rm -f priv/native/tree_sitter_nif.so
# Compile application + rebuild tree-sitter NIF for Linux
# Temporarily enable NIF compilation by patching skip_compilation
RUN sed -i 's/skip_compilation?: true/skip_compilation?: false/' lib/elixir_nexus/tree_sitter_parser.ex && \
mix compile --force && \
sed -i 's/skip_compilation?: false/skip_compilation?: true/' lib/elixir_nexus/tree_sitter_parser.ex
# Generate static asset digest manifest required by Phoenix in prod mode.
RUN mix phx.digest
# Stage 2: Runtime — slim image without Rust toolchain or build tools
FROM elixir:1.19.5-otp-27-slim AS runtime
WORKDIR /app
# Only runtime dependencies — inotify-tools for file watching
RUN apt-get update && apt-get install -y \
inotify-tools \
&& rm -rf /var/lib/apt/lists/*
# Copy hex/rebar from builder so mix commands work at runtime
COPY --from=builder /root/.mix /root/.mix
COPY --from=builder /root/.hex /root/.hex
# Copy compiled application from builder
COPY --from=builder /app/mix.exs /app/mix.lock /app/VERSION ./
COPY --from=builder /app/deps deps
COPY --from=builder /app/_build _build
COPY --from=builder /app/lib lib
COPY --from=builder /app/config config
COPY --from=builder /app/priv priv
# Copy bundled skills into runtime — Phoenix's dev-mode code reloader can
# recompile Resources at startup and re-reads @skills_dir then. Without this,
# any recompile produces an empty skill list.
COPY --from=builder /app/.agents .agents
# Copy entrypoint script
COPY docker-entrypoint.sh ./
RUN chmod +x docker-entrypoint.sh
# Expose ports (Phoenix + MCP HTTP)
EXPOSE 4100 3001
# Start both Phoenix and MCP HTTP servers
CMD ["./docker-entrypoint.sh"]