dp-zp-agent/deployment/docker-compose.yml

159 lines
4.6 KiB
YAML

name: zp-agent
services:
zp-agent-api:
build:
context: ..
dockerfile: deployment/Dockerfile
args:
EMBEDDING_MODEL: ${EMBEDDING_MODEL:-intfloat/multilingual-e5-small}
EMBEDDING_REVISION: ${EMBEDDING_REVISION:-}
CHUNK_TOKEN_ENCODING: ${CHUNK_TOKEN_ENCODING:-cl100k_base}
RAG_LLM_TOKEN_ENCODING: ${RAG_LLM_TOKEN_ENCODING:-cl100k_base}
container_name: zp-agent-api
ports:
- "8000:8000"
env_file:
- ../.env
environment:
ZPWIKI_ROOT: /zpwiki
WIKI_SYNC_INTERVAL_SECONDS: ${WIKI_SYNC_INTERVAL_SECONDS:-86400}
SYNC_UPSTREAM_FORK: ${SYNC_UPSTREAM_FORK:-1}
ZPWIKI_SYNC_KEY_FILE: /run/secrets/zpwiki_ssh_key
CHUNK_MAX_TOKENS: "450"
CHUNK_OVERLAP_TOKENS: "70"
CHUNK_MIN_TOKENS: "80"
CHUNK_TOKEN_ENCODING: ${CHUNK_TOKEN_ENCODING:-cl100k_base}
RAG_LLM_MAX_TOKENS: ${RAG_LLM_MAX_TOKENS:-12000}
RAG_LLM_TOKEN_ENCODING: ${RAG_LLM_TOKEN_ENCODING:-cl100k_base}
HF_HOME: /cache/huggingface
HF_HUB_OFFLINE: "1"
TRANSFORMERS_OFFLINE: "1"
ZP_RUNTIME_ASSETS: /opt/zp-assets
ZP_ASSETS_REQUIRED: "1"
GIT_SSH_COMMAND: >-
ssh -F /dev/null -i /run/secrets/zpwiki_ssh_key
-o IdentitiesOnly=yes -o BatchMode=yes -o StrictHostKeyChecking=yes
-o UserKnownHostsFile=/run/secrets/zpwiki_known_hosts -o ConnectTimeout=15
NEO4J_URI: bolt://neo4j:7687
NEO4J_USER: ${NEO4J_USER:-neo4j}
NEO4J_PASSWORD: ${NEO4J_PASSWORD}
NEO4J_DATABASE: ${NEO4J_DATABASE:-neo4j}
volumes:
- ../data:/app/data
- ../../zpwiki:/zpwiki
- hf-cache:/cache/huggingface
- type: bind
source: ${ZPWIKI_SSH_KEY:-${HOME}/.ssh/id_ed25519}
target: /run/secrets/zpwiki_ssh_key
read_only: true
bind:
create_host_path: false
- type: bind
source: ${ZPWIKI_KNOWN_HOSTS:-${HOME}/.ssh/known_hosts}
target: /run/secrets/zpwiki_known_hosts
read_only: true
bind:
create_host_path: false
restart: unless-stopped
stop_grace_period: 5m
depends_on:
neo4j:
condition: service_healthy
healthcheck:
test: ["CMD", "python", "-m", "tools.runtime.runtime_health"]
interval: 15s
timeout: 10s
retries: 12
start_period: 90s
claude-mcp:
profiles: [claude]
build:
context: ..
dockerfile: deployment/claude.Dockerfile
ports:
- "127.0.0.1:8001:8001"
environment:
ZP_AGENT_URL: http://zp-agent-api:8000
ZP_AGENT_API_KEY: ${SEARCH_API_KEY}
ZP_AGENT_ALLOW_HTTP: "1"
ZP_MCP_ACCESS_TOKEN: ${ZP_MCP_ACCESS_TOKEN:-}
ZP_MCP_PUBLIC_URL: ${ZP_MCP_PUBLIC_URL:-}
ZP_MCP_BIND: "0.0.0.0"
ZP_MCP_AUTH_MODE: ${ZP_MCP_AUTH_MODE:-oauth}
ZP_MCP_LOGIN_PASSWORD: ${ZP_MCP_LOGIN_PASSWORD:-}
volumes:
- claude-oauth:/var/lib/zp-oauth
depends_on:
zp-agent-api:
condition: service_healthy
healthcheck:
test:
- CMD
- python
- -c
- >-
import os,urllib.request;
r=urllib.request.Request('http://127.0.0.1:8001/health',headers={'Authorization':'Bearer '+os.environ['ZP_MCP_ACCESS_TOKEN']});
assert urllib.request.urlopen(r,timeout=5).status==200
interval: 15s
timeout: 6s
retries: 5
restart: unless-stopped
read_only: true
cap_drop: [ALL]
security_opt: [no-new-privileges:true]
# The tunnel connects through Docker DNS, not a possibly different WSL
# localhost service. OAuth on claude-mcp still protects every tool call.
claude-tunnel:
profiles: [claude-tunnel]
image: cloudflare/cloudflared@sha256:4955524aeaa379e154023d5a027c250f7b35041a2e7e950cf13f144bc9b9c5ba
command: [tunnel, --no-autoupdate, --protocol, http2, --url, "http://claude-mcp:8001"]
depends_on:
claude-mcp:
condition: service_healthy
restart: unless-stopped
read_only: true
cap_drop: [ALL]
security_opt: [no-new-privileges:true]
neo4j:
image: neo4j:2026.09.0
container_name: zp-agent-neo4j
ports:
- "127.0.0.1:7474:7474"
- "127.0.0.1:7687:7687"
environment:
NEO4J_AUTH: ${NEO4J_USER:-neo4j}/${NEO4J_PASSWORD}
volumes:
- neo4j-data:/data
- neo4j-logs:/logs
healthcheck:
test:
[
"CMD-SHELL",
"u=$${NEO4J_AUTH%%/*}; p=$${NEO4J_AUTH#*/}; cypher-shell -u \"$$u\" -p \"$$p\" 'RETURN 1' >/dev/null 2>&1"
]
interval: 10s
timeout: 5s
retries: 10
start_period: 20s
restart: unless-stopped
volumes:
claude-oauth:
hf-cache:
neo4j-data:
neo4j-logs: