mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-10-23 00:45:25 +08:00
Probe the existing HTTP health endpoints exposed by each service: - langbot: GET /healthz on 5300 - langbot_plugin_runtime: GET /healthz on 5400 - langbot_box: GET /readyz on 5410 (readiness, 503 until ready) python is used instead of curl because the image removes curl at build time.
141 lines
7.4 KiB
YAML
141 lines
7.4 KiB
YAML
# Docker Compose configuration for LangBot
|
|
# For Kubernetes deployment, see kubernetes.yaml and the deployment guide at https://langbot.app/docs
|
|
version: "3"
|
|
|
|
services:
|
|
|
|
langbot_plugin_runtime:
|
|
image: rockchin/langbot:latest
|
|
container_name: langbot_plugin_runtime
|
|
volumes:
|
|
- ./data/plugins:/app/data/plugins
|
|
ports:
|
|
- 5401:5401
|
|
restart: on-failure
|
|
environment:
|
|
- TZ=Asia/Shanghai
|
|
# Optional. Leave unset on both OSS services, or set the same value on
|
|
# both to protect the control WebSocket. Generate with: openssl rand -hex 32
|
|
- LANGBOT_PLUGIN_RUNTIME_CONTROL_TOKEN=${LANGBOT_PLUGIN_RUNTIME_CONTROL_TOKEN:-}
|
|
# Process-wide admission for every asyncio.to_thread() call.
|
|
- LANGBOT_BLOCKING_EXECUTOR_MAX_WORKERS=${LANGBOT_BLOCKING_EXECUTOR_MAX_WORKERS:-8}
|
|
- LANGBOT_BLOCKING_EXECUTOR_MAX_PENDING=${LANGBOT_BLOCKING_EXECUTOR_MAX_PENDING:-128}
|
|
- LANGBOT_BLOCKING_EXECUTOR_MAX_INFLIGHT_PER_SCOPE=${LANGBOT_BLOCKING_EXECUTOR_MAX_INFLIGHT_PER_SCOPE:-4}
|
|
command: ["uv", "run", "--no-sync", "-m", "langbot_plugin.cli.__init__", "rt"]
|
|
# The control WebSocket port also serves an unauthenticated GET /healthz
|
|
# (see langbot_plugin runtime/io/controllers/ws/server.py). curl is removed
|
|
# from the image, so probe with the always-present python.
|
|
healthcheck:
|
|
test: ["CMD", "python", "-c", "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1:5400/healthz', timeout=3).getcode()==200 else 1)"]
|
|
interval: 30s
|
|
timeout: 5s
|
|
retries: 3
|
|
start_period: 30s
|
|
networks:
|
|
- langbot_network
|
|
|
|
# The Box sandbox runtime is optional. It is only started when you run
|
|
# ``docker compose --profile box up`` (or ``docker compose --profile all
|
|
# up``). With Box off, LangBot keeps skill management, activation, and
|
|
# read-only resources available but disables execution tools and stdio MCP —
|
|
# set ``box.enabled: false`` in ``data/config.yaml`` (or
|
|
# ``BOX__ENABLED=false`` in the langbot service env below) to match.
|
|
langbot_box:
|
|
image: rockchin/langbot:latest
|
|
container_name: langbot_box
|
|
profiles: ["box", "all"]
|
|
volumes:
|
|
# Keep the source and target path identical because langbot_box uses the
|
|
# host Docker socket to create sandbox containers. Override
|
|
# LANGBOT_BOX_ROOT with an absolute path if you do not want the default.
|
|
- ${LANGBOT_BOX_ROOT:-${PWD}/data/box}:${LANGBOT_BOX_ROOT:-${PWD}/data/box}
|
|
# Mount container runtime socket for Box sandbox backend.
|
|
# Uncomment the one that matches your container runtime:
|
|
# - /var/run/podman/podman.sock:/var/run/podman/podman.sock # Podman
|
|
- /var/run/docker.sock:/var/run/docker.sock # Docker
|
|
restart: on-failure
|
|
environment:
|
|
- TZ=Asia/Shanghai
|
|
# Optional shared control-plane secret used to authenticate both the RPC
|
|
# socket and managed-process relay. Leave unset on both OSS services, or
|
|
# generate one with ``openssl rand -hex 32`` and set the same value on
|
|
# both ends. Strongly recommended when the deployment is Internet-accessible.
|
|
- LANGBOT_BOX_CONTROL_TOKEN=${LANGBOT_BOX_CONTROL_TOKEN:-}
|
|
# Box has its own process-wide blocking-work budget.
|
|
- LANGBOT_BLOCKING_EXECUTOR_MAX_WORKERS=${LANGBOT_BLOCKING_EXECUTOR_MAX_WORKERS:-8}
|
|
- LANGBOT_BLOCKING_EXECUTOR_MAX_PENDING=${LANGBOT_BLOCKING_EXECUTOR_MAX_PENDING:-128}
|
|
- LANGBOT_BLOCKING_EXECUTOR_MAX_INFLIGHT_PER_SCOPE=${LANGBOT_BLOCKING_EXECUTOR_MAX_INFLIGHT_PER_SCOPE:-4}
|
|
# The Box runtime does NOT read box.local.* from config.yaml or env; it
|
|
# receives its functional configuration from LangBot via the INIT RPC
|
|
# action. Do not add BOX__* here because those would be ignored.
|
|
# Launched through the same CLI entry point as the plugin runtime
|
|
# (`langbot_plugin.cli.__init__ <subcommand>`). WebSocket is the default
|
|
# control transport — mirrors `rt`, which also runs with no flag. Pass
|
|
# `-s` / `--stdio-control` only for the stdio mode LangBot uses outside
|
|
# containers.
|
|
command: ["uv", "run", "--no-sync", "-m", "langbot_plugin.cli.__init__", "box"]
|
|
# Box serves GET /healthz (liveness) and GET /readyz (readiness, 503 until
|
|
# the configured backend and isolation guarantees are ready) on the control
|
|
# port (default 5410). Use /readyz so the container is only reported healthy
|
|
# once it can actually accept sandbox work.
|
|
healthcheck:
|
|
test: ["CMD", "python", "-c", "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1:5410/readyz', timeout=3).getcode()==200 else 1)"]
|
|
interval: 30s
|
|
timeout: 5s
|
|
retries: 3
|
|
start_period: 20s
|
|
networks:
|
|
- langbot_network
|
|
|
|
langbot:
|
|
image: rockchin/langbot:latest
|
|
container_name: langbot
|
|
volumes:
|
|
- ./data:/app/data
|
|
# Core owns the SkillRepository even when the Box profile is disabled.
|
|
# Keep this path identical to langbot_box so optional execution can
|
|
# consume the same Workspace-scoped package revisions.
|
|
- ${LANGBOT_BOX_ROOT:-${PWD}/data/box}:${LANGBOT_BOX_ROOT:-${PWD}/data/box}
|
|
restart: on-failure
|
|
environment:
|
|
- TZ=Asia/Shanghai
|
|
# Optional. Leave unset on both OSS services, or match plugin Runtime.
|
|
- LANGBOT_PLUGIN_RUNTIME_CONTROL_TOKEN=${LANGBOT_PLUGIN_RUNTIME_CONTROL_TOKEN:-}
|
|
# When set, this must match langbot_box. If both ends leave it unset,
|
|
# OSS permits the connection without token authentication. The token is
|
|
# sent only in WebSocket handshake headers, never in URLs or payloads.
|
|
- LANGBOT_BOX_CONTROL_TOKEN=${LANGBOT_BOX_CONTROL_TOKEN:-}
|
|
# Core process-wide blocking-work admission. These are native config
|
|
# overrides and are persisted with the effective data/config.yaml.
|
|
- SYSTEM__BLOCKING_EXECUTOR__MAX_WORKERS=${LANGBOT_BLOCKING_EXECUTOR_MAX_WORKERS:-8}
|
|
- SYSTEM__BLOCKING_EXECUTOR__MAX_PENDING=${LANGBOT_BLOCKING_EXECUTOR_MAX_PENDING:-128}
|
|
- SYSTEM__BLOCKING_EXECUTOR__MAX_INFLIGHT_PER_SCOPE=${LANGBOT_BLOCKING_EXECUTOR_MAX_INFLIGHT_PER_SCOPE:-4}
|
|
# Unified env-override convention: SECTION__SUBSECTION__KEY overrides the
|
|
# matching config.yaml field (see LoadConfigStage). These map onto
|
|
# box.* and are forwarded to the Box runtime via INIT RPC.
|
|
- BOX__LOCAL__HOST_ROOT=${LANGBOT_BOX_ROOT:-${PWD}/data/box}
|
|
- BOX__LOCAL__DEFAULT_WORKSPACE=default
|
|
# TODO(next-major): default LANGBOT_SKILLS_ROOT to ${PWD}/data/skills
|
|
# after the historical Box storage path no longer needs zero-copy upgrades.
|
|
- SKILLS__ROOT=${LANGBOT_SKILLS_ROOT:-${LANGBOT_BOX_ROOT:-${PWD}/data/box}/skills}
|
|
- BOX__LOCAL__ALLOWED_MOUNT_ROOTS=${LANGBOT_BOX_ROOT:-${PWD}/data/box}
|
|
- BOX__DOCKER__CPU_LIMIT_ENABLED=${LANGBOT_BOX_DOCKER_CPU_LIMIT_ENABLED:-true}
|
|
ports:
|
|
- 5300:5300 # For web ui and webhook callback
|
|
- 2280-2285:2280-2285 # For platform reverse connection
|
|
# The core Quart app exposes an unauthenticated GET /healthz on api.port
|
|
# (see langbot/pkg/api/http/controller/main.py). curl is removed from the
|
|
# image, so probe with the always-present python.
|
|
healthcheck:
|
|
test: ["CMD", "python", "-c", "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1:5300/healthz', timeout=3).getcode()==200 else 1)"]
|
|
interval: 30s
|
|
timeout: 5s
|
|
retries: 3
|
|
start_period: 60s
|
|
networks:
|
|
- langbot_network
|
|
|
|
networks:
|
|
langbot_network:
|
|
driver: bridge
|