Ctrl K
ComunidadGuías…

docker-compose.oss.yml

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# OSS / community edition overlay — build the moat-free images from source.
#
# ── THIS FILE IS NOT STANDALONE ──────────────────────────────────────────────
# It is an overlay. Rendering it alone fails, by design:
#
#     $ docker compose -f docker-compose.oss.yml config --services
#     service "connector-seed" refers to undefined volume mcp_connectors: invalid compose project
#
# Two objects are missing, not one, and Compose reports whichever it reaches
# first — the same command also prints
# `service "connector-deployer" refers to undefined network rsync-ai-mcp`
# depending on service iteration order, so do not treat either message as the
# whole diagnosis. Do NOT "fix" either by declaring them here. Both must be the SAME objects the
# base file creates — declaring a second `mcp_connectors` in this file would give
# the overlay its own empty volume, and `connector-seed` would seed a volume the
# orchestrator never reads. They are inherited from the base layered underneath.
#
# ── THE REQUIRED BASE IS docker-compose.quickstart.yml ───────────────────────
# Not `docker-compose.yml`. The cloud base has no `mcp_connectors` volume (its
# top-level `volumes:` block carries postgres/kafka/redis/minio/connect_secrets/
# tool_generator_oauth_tokens and nothing else), so
# `-f docker-compose.yml -f docker-compose.oss.yml` fails with
# `service "connector-deployer" refers to undefined volume mcp_connectors`.
# Cloud uses a bind mount for connectors; only the quickstart stack uses the
# named volume this overlay seeds.
#
#     docker compose -f docker-compose.quickstart.yml -f docker-compose.oss.yml up -d
#
# Validate the merge before starting anything (rc=0 and 17 services today):
#
#     docker compose -f docker-compose.quickstart.yml -f docker-compose.oss.yml \
#         config --services
#
# ── WHAT THIS OVERLAY ACTUALLY CHANGES ───────────────────────────────────────
# The quickstart ALREADY runs the moat-free lifecycle service: it pulls
# `ghcr.io/rsync-ai/connector-lifecycle` for `tool-generator` and runs
# `src.lifecycle.main`. This overlay does NOT introduce that — it switches three
# services from PULLING the published images to BUILDING them from this working
# tree. Diff of the rendered project, quickstart alone -> quickstart + this file:
#
#     tool-generator      ghcr.io/rsync-ai/connector-lifecycle:latest
#                      -> rsync-ai/connector-lifecycle:local   (llm-service/Dockerfile.oss)
#     connector-seed      ghcr.io/rsync-ai/connector-seed:latest
#                      -> rsync-ai/connector-seed:local        (shared/mcp-connectors/Dockerfile.seed)
#     connector-deployer  ghcr.io/rsync-ai/connector-deployer:latest  (tag kept)
#                      +  build: ./connector-deployer
#     tool-generator container_name  rsync-ai-tool-generator -> rsync-ai-connector-lifecycle
#
# Nothing else differs. `depends_on`, networks, volumes and every env var are
# identical to the quickstart's — so use this file when you want to run YOUR
# source, and plain `docker compose -f docker-compose.quickstart.yml up -d` when
# you want the published release.
#
# Two consequences of the local tags: `docker compose pull` cannot resolve
# `rsync-ai/*:local`, so pull with `--ignore-buildable` (or just `up -d`, which
# builds what is missing); and `up -d` reuses an already-built local image, so
# pass `--build` after editing source.
#
# ── DO NOT scale context7-mcp ────────────────────────────────────────────────
# An earlier version of this header advised scaling llm-service, planner AND
# context7-mcp to zero. The third one is wrong and the retired flag is
# deliberately not spelled out here, because
# llm-service/tests/test_oss_overlay_documents_its_invocation.py scans this whole
# header for `--scale <name>=` and would match the cautionary quote as if it
# were live advice.
# `context7-mcp` carries `profiles: ["generate"]` (docker-compose.quickstart.yml)
# and is therefore ABSENT from the default project — `config --services` lists it
# only under `--profile generate`. Naming it in `--scale` scales a service the
# rendered project does not contain.
#
# `llm-service` and `planner` ARE in the default project and are pullable: both
# run the stripped `ghcr.io/rsync-ai/llm-service-oss` image, not the moat build,
# so their presence is deliberate rather than a leak. Scaling them to 0 is a
# resource choice (the Go data plane's REST create+run path is Python-free and
# every LLM feature degrades gracefully when absent), not a requirement:
#
#     docker compose -f docker-compose.quickstart.yml -f docker-compose.oss.yml \
#         up -d --scale llm-service=0 --scale planner=0
#
# ── OSS/cloud split ──────────────────────────────────────────────────────────
# No runtime edition gate anywhere in this file. `RSYNC_EDITION: community`
# below is cosmetic — its only reads are the `edition` field of the
# lifecycle service's /health and /version bodies (llm-service/src/lifecycle/
# main.py:52,60), and nothing branches on it. `RSYNC_BILLING_ENFORCED` is
# deliberately NOT set here: it defaults to enforced (the cloud behavior) and
# only docker-compose.quickstart.yml, the base underneath, sets it false.
# See docs/internal/oss-cloud-runtime-split.md.
# ─────────────────────────────────────────────────────────────────────────────

services:
  # One-shot init: seed the mcp_connectors volume so a COLD self-host boots WITH connectors
  # (fixes the empty-volume "dead on arrival"). Runs the image's seed-connectors.sh: a no-op on
  # the same release, a refresh of the shipped connectors after an upgrade, generated
  # connectors kept. No `command:` override -- see docker-compose.quickstart.yml.
  # NOTE: orchestrator + temporal-adapter also mount mcp_connectors (:ro); they read connectors
  # lazily at pipeline-run time, after this init has completed on boot.
  connector-seed:
    build:
      context: ./shared/mcp-connectors
      dockerfile: Dockerfile.seed
    image: rsync-ai/connector-seed:local
    container_name: rsync-ai-connector-seed
    restart: "no"
    volumes:
      - mcp_connectors:/target

  # Connector Deployer (SEC-H-02): THE trusted socket-holder for the OSS stack.
  # tool-generator (the connector-lifecycle image below) drops root + the docker
  # socket and delegates JIT build/run to this small no-LLM Go service over an
  # authenticated internal RPC. Same Go image the cloud stack uses — the OSS/cloud
  # split stays at the compose layer, no runtime edition gate. Identical in shape
  # to the connector-deployer in docker-compose.quickstart.yml (the layer this file
  # sits on), so layering merges cleanly. See
  # docs/internal/jit-connector-sandboxing.md + connector-deployer/CONTRACT.md.
  connector-deployer:
    build:
      context: ./connector-deployer
    container_name: rsync-ai-connector-deployer
    restart: unless-stopped
    environment:
      # ENVIRONMENT production => app-level S2S fail-closed (503 if secret unset),
      # same posture the tool-generator carried. Compose-level :? guard is prod.yml only.
      ENVIRONMENT: production
      LOG_FORMAT: json
      LOG_LEVEL: info
      # Rotation for the connector containers THIS service creates -- compose's
      # `logging:` blocks only reach the services compose itself starts.
      RSYNC_LOG_MAX_SIZE: ${RSYNC_LOG_MAX_SIZE:-10m}
      RSYNC_LOG_MAX_FILE: ${RSYNC_LOG_MAX_FILE:-3}
      INTERNAL_SERVICE_SECRET: ${INTERNAL_SERVICE_SECRET:-}
      DEPLOYER_DOCKER_NETWORK: rsync-ai-mcp
      MCP_SHARED_NETWORK: rsync-ai-mcp
      OAUTH_TOKENS_VOLUME_NAME: rsync-ai-oauth-tokens
    # Root + RW docker.sock live HERE now, not on tool-generator.
    user: "0:0"
    networks:
      - default
      - rsync-ai-mcp
    volumes:
      - mcp_connectors:/app/shared/mcp-connectors:ro
      - /var/run/docker.sock:/var/run/docker.sock

  tool-generator:
    # Build the moat-free lifecycle image instead of pulling the mono generation image.
    build:
      context: ./llm-service
      dockerfile: Dockerfile.oss
    image: rsync-ai/connector-lifecycle:local
    container_name: rsync-ai-connector-lifecycle
    restart: unless-stopped
    # Replace the base's llm-service dependency entirely: the OSS stack has no llm-service,
    # and the lifecycle service waits for the connector volume to be seeded so /v1/deploy can
    # resolve connectors on disk. Also gate on the connector-deployer (SEC-H-02): the
    # lifecycle service delegates JIT build/run to it and never touches the socket itself.
    depends_on: !override
      connector-seed:
        condition: service_completed_successfully
      connector-deployer:
        condition: service_started
    environment:
      PORT: 5010
      TOOLS_DIR: /app/shared/mcp-connectors
      # Managed mode: the deployer builds user MCP images + starts containers when the
      # orchestrator's preflight calls /v1/deploy. Set false to manage MCP containers via
      # a separate stack.
      RSYNC_MANAGED_CONNECTORS: ${RSYNC_MANAGED_CONNECTORS:-true}
      DOCKER_NETWORK: rsync-ai-mcp
      # SEC-H-02: delegate JIT build/run to the connector-deployer over its internal RPC.
      DEPLOYER_URL: http://connector-deployer:5011
      INTERNAL_SERVICE_SECRET: ${INTERNAL_SERVICE_SECRET:-}
      RSYNC_EDITION: community
      LOG_FORMAT: json
      LOG_LEVEL: info
      ENVIRONMENT: production
    command: ["python", "-m", "src.lifecycle.main"]
    # SEC-H-02: runs the image's default unprivileged appuser — no root, no
    # docker.sock. The connector-deployer is the sole trusted socket holder.
    networks:
      - default
      - rsync-ai-mcp
    volumes:
      - mcp_connectors:/app/shared/mcp-connectors