Files
mcp-server/docker-compose.yml
T
Claude 13e39b39f3 refactor: env-configurable loguru file paths
common/logging.py used hardcoded 'data/logs/{debug,info}/' paths,
which forced logs into the same dir as connections.json. Operators
couldn't put logs on a dedicated volume or a different disk for
retention policy reasons.

Now the base log dir comes from settings.log_dir (env var
SPARK_EXECUTOR_LOG_DIR, default <data_dir>/logs). Subdirs debug/ and
info/ are auto-created. Same behavior in dev (./data/logs/), but in
prod you can do:

  SPARK_EXECUTOR_LOG_DIR=/var/log/spark-executor   # dedicated volume
  SPARK_EXECUTOR_LOG_DIR=/mnt/slow-storage/logs   # cold storage for old logs

Other changes:
  - .env.example: new SPARK_EXECUTOR_LOG_DIR entry, split into its own
    'Loguru file sinks' section
  - docker-compose.yml: forwards SPARK_EXECUTOR_LOG_DIR with the
    container-side default /app/data/logs (the existing ./data:/app/data
    volume mount already covers this)
  - common/config.py: Settings gets a new log_dir field, defaults
    derived from data_dir; reload() also resets it

116/116 still pass. Live smoke verified: with
SPARK_EXECUTOR_LOG_DIR=/tmp/spark-logs, both
  /tmp/spark-logs/info/2026-06-25.log
  /tmp/spark-logs/debug/2026-06-25.log
are created on the first request.
2026-06-25 10:57:50 +08:00

83 lines
3.1 KiB
YAML

# spark-executor-mcp — production runtime
#
# Bring up with:
# docker compose up -d --build
#
# Prerequisites (one-time):
# 1. Put your YARN/Hadoop client configs in ./hadoop-conf/ (must contain
# core-site.xml + yarn-site.xml + hdfs-site.xml matching the target
# cluster). The Dockerfile's RUN mkdir -p already creates the dir, but
# it will be empty until you populate it.
# 2. Set YARN_RESOURCE_MANAGER_URL in .env (or export it in your shell).
# This is the fallback when a Connection was saved without yarn_rm_url.
#
# After it starts, the MCP endpoint is at:
# http://localhost:8000/spark-executor-mcp (initialize -> tools/list -> tools/call)
services:
mcp-server:
build:
context: .
dockerfile: Dockerfile
image: mcp-server:latest
container_name: mcp-tools
restart: unless-stopped
ports:
- "8000:8000"
environment:
# Stream Python output to stdout/stderr line-by-line (live loguru output).
PYTHONUNBUFFERED: "1"
# --- common/config.py knobs (see .env.example for full docs) ---
# Base dir for connections.json, pending_jobs.json, loguru logs/, jobs/.
# Defaults to ./data inside the container (mounted from host via volumes below).
SPARK_EXECUTOR_DATA_DIR: ${SPARK_EXECUTOR_DATA_DIR:-/app/data}
# Where generate_job_file writes LLM-generated PySpark code.
# Defaults to <SPARK_EXECUTOR_DATA_DIR>/jobs.
SPARK_EXECUTOR_JOBS_DIR: ${SPARK_EXECUTOR_JOBS_DIR:-/app/data/jobs}
# Base dir for loguru file output (debug/ + info/ subdirs are
# auto-created). Defaults to <SPARK_EXECUTOR_DATA_DIR>/logs.
SPARK_EXECUTOR_LOG_DIR: ${SPARK_EXECUTOR_LOG_DIR:-/app/data/logs}
# Fallback YARN RM URL used by the REST client when a Connection's
# yarn_rm_url is not set or a Job lacks a snapshot. Leave empty if
# you always set yarn_rm_url per Connection via save_connection.
YARN_RESOURCE_MANAGER_URL: ${YARN_RESOURCE_MANAGER_URL:-}
# Loguru verbosity for stderr + info file. DEBUG | INFO.
SPARK_EXECUTOR_LOG_LEVEL: ${SPARK_EXECUTOR_LOG_LEVEL:-DEBUG}
# --- gunicorn.conf.py knobs (NOT read by common/config.py) ---
# 2 workers is a good default for a small MCP service; raise for
# high-concurrency deploys.
GUNICORN_WORKERS: ${GUNICORN_WORKERS:-2}
GUNICORN_TIMEOUT: ${GUNICORN_TIMEOUT:-120}
GUNICORN_BIND: ${GUNICORN_BIND:-0.0.0.0:8000}
# Optional: pass JVM options to spark-submit (e.g. for proxies, memory).
# SPARK_SUBMIT_OPTS: "-Dhttps.proxyHost=..."
volumes:
# Persist Connections, PendingSubmissions, and loguru logs across
# container restarts. Gitignored.
- ./data:/app/data
# Real Hadoop/YARN client configs read by spark-submit at submit time.
# Read-only so the running container cannot mutate cluster config.
- ./hadoop-conf:/etc/hadoop/conf:ro
# No resource limits — spark-submit talks to YARN, which does the actual
# heavy lifting. The MCP server itself is lightweight (FastAPI + httpx).
# Uncomment to cap if needed:
# deploy:
# resources:
# limits:
# cpus: "1.0"
# memory: 1G