Files
mcp-server/Dockerfile
T
ClaudeandClaude Fable 5 e518c669e4 chore(docker): enable files_mcp service in container image
- Dockerfile: COPY files_mcp package, mkdir -p /app/data/files at build
  time, set ENV FILES_MCP_ROOT=/app/data/files as the default sandbox
  root (overridable at runtime).
- docker-compose.yml: surface FILES_MCP_ROOT in the env block with the
  same default, so operators can override it via .env or -e.

FILES_MCP_ROOT must exist at process start (path_guard._init_root
checks is_dir()), so the directory is created during build rather than
deferred to entrypoint — fail-fast at image build beats a runtime
RuntimeError on every container start.

Default lives under /app/data so it rides the existing data volume
(./data:/app/data) and persists across container restarts alongside
connections.json / pending_jobs.json / logs/.

Verified locally: docker compose config --quiet passes; FILES_MCP_ROOT
resolves to /app/data/files in the rendered config. Full image build
not run (docker daemon unavailable in this environment); please run
`docker compose up -d --build` to confirm in your environment.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-30 19:34:06 +08:00

97 lines
3.4 KiB
Docker

# syntax=docker/dockerfile:1
#
# Spark Executor MCP — runtime image.
# Build deps with uv (frozen, prod-only), then drop in the source on top of
# ppython:3.12-slim-bookworm with Spark + YARN configs mounted for the spark-submit /
# yarn CLI calls inside the MCP tools.
FROM python:3.12-slim-bookworm
# --- uv (official binary) ---
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /usr/local/bin/
# --- Spark + Hadoop config (matches the original Dockerfile) ---
ARG SPARK_VERSION=3.5.8
RUN sed -i 's|deb.debian.org|mirrors.tuna.tsinghua.edu.cn|g' /etc/apt/sources.list.d/debian.sources && \
apt-get update && \
apt-get install -y --no-install-recommends \
curl \
ca-certificates \
tar \
gcc \
g++ \
make \
pkg-config \
libkrb5-dev \
openjdk-17-jre-headless && \
curl -L \
https://mirrors.tuna.tsinghua.edu.cn/apache/spark/spark-${SPARK_VERSION}/spark-${SPARK_VERSION}-bin-hadoop3.tgz \
-o /tmp/spark.tgz && \
mkdir -p /opt && \
tar -xzf /tmp/spark.tgz -C /opt && \
mv /opt/spark-${SPARK_VERSION}-bin-hadoop3 /opt/spark && \
rm -f /tmp/spark.tgz && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
ENV JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
ENV SPARK_HOME=/opt/spark
ENV PATH=${JAVA_HOME}/bin:${SPARK_HOME}/bin:${PATH}
# Hadoop/Yarn 配置目录(运行时挂载)
RUN mkdir -p /etc/hadoop/conf
# 默认值,可在 docker run 时覆盖
ENV HADOOP_CONF_DIR=/etc/hadoop/conf
ENV YARN_CONF_DIR=/etc/hadoop/conf
# --- App ---
WORKDIR /app
# Install Python deps first so this layer caches independently of source.
# --frozen pins to uv.lock exactly; --no-dev skips pytest etc. for a slim
# production image; --no-install-project defers copying the source.
COPY pyproject.toml uv.lock ./
RUN uv sync --index-url=https://pypi.tuna.tsinghua.edu.cn/simple/ --frozen --no-dev --no-install-project
# Now copy the source and let uv wire it in.
COPY main.py ./
COPY spark_executor ./spark_executor
COPY files_mcp ./files_mcp
COPY common ./common
COPY gunicorn.conf.py ./
RUN uv sync --index-url=https://pypi.tuna.tsinghua.edu.cn/simple/ --frozen --no-dev
# --- files_mcp sandbox ---
# FILES_MCP_ROOT is the only directory the files_mcp tools can touch. It
# must exist at process start (path_guard._init_root checks is_dir()) and
# persist across container restarts, so it lives under the data volume.
# Operators can override FILES_MCP_ROOT at `docker run` / compose to point
# at a separate host mount if they want strict isolation from /app/data.
RUN mkdir -p /app/data/files
ENV FILES_MCP_ROOT=/app/data/files
# Put the venv on PATH so `python` / `gunicorn` / `uvicorn` resolve to the project env.
ENV PATH=/app/.venv/bin:$PATH
ENV PYTHONUNBUFFERED=1
# Entrypoint re-derives PATH from JAVA_HOME and SPARK_HOME at container
# start, so overriding either via docker-compose / .env actually changes
# which `java` and `spark-submit` binaries the gunicorn process picks up.
COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
RUN chmod +x /usr/local/bin/docker-entrypoint.sh
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
# gunicorn is the prod entrypoint — multiple ASGI workers, graceful
# shutdown, stdout/stderr logs. Config knobs are env-var driven (see
# gunicorn.conf.py).
#
# Common overrides via -e flags at `docker run`:
# -e GUNICORN_WORKERS=4
# -e GUNICORN_TIMEOUT=180
# -e GUNICORN_BIND=0.0.0.0:9000
EXPOSE 8000
CMD ["gunicorn", "main:app"]