Wire up control-plane ↔ data-plane communication in the Docker stack#63
Conversation
Signed-off-by: Lang-Akshay <akshay.shinde26@ibm.com>
Signed-off-by: Lang-Akshay <akshay.shinde26@ibm.com>
Signed-off-by: Lang-Akshay <akshay.shinde26@ibm.com>
…running entire tech stack Signed-off-by: Lang-Akshay <akshay.shinde26@ibm.com>
|
Nice work on this. The docs (topology diagram, resource table, troubleshooting matrix) make it easy to follow, and the dependency gating / RS256 wiring all check out. Two medium items worth a look before merge: 🟡 MediumM1 · M2 · PgBouncer transaction pooling + psycopg3 prepared statements — if the control-plane image doesn't disable server-side prepared statements, transaction mode can throw intermittent "prepared statement already exists" errors under concurrency. The register flow is too low-volume to trip it, so no action needed for the local loop, but worth confirming |
There was a problem hiding this comment.
Requesting changes based on clean, isolated Docker/Make validation:
-
P1 — Build the checked-out source.
make docker-prodpasses the workspace as build context, but the Dockerfile clones remotemainand only copies.cargo/config.toml. The PR build therefore compiled the base branch instead of the PR SHA, and publication is not pinned to the workflow checkout. Please copy and build the local workspace. -
P2 — Fix the nginx health route.
/healthis forwarded unchanged and returns 404; the dataplane health endpoint is/contextforge-rs/health. Please rewrite or proxy to that path.
All Make targets otherwise work: the full stack became healthy, Fast Time registered 7 tools, MCP initialize/tools/list passed, and testing-down stopped the stack. The latest image publication also succeeded. Confirmed the runtime path is dataplane → Fast Time.
…dings Signed-off-by: Lang-Akshay <akshay.shinde26@ibm.com>
|
Thanks allot for request @gandhipratik203 and @lucarlig
|
Signed-off-by: Lang-Akshay <akshay.shinde26@ibm.com>
gandhipratik203
left a comment
There was a problem hiding this comment.
Nice work, this looks good to me.
Summary
This PR extends the local Docker Compose stack so the Rust data-plane (
contextforge-gateway-rs) runs alongside the Python control-plane (mcp-context-forge), backed by Postgres/PgBouncer, and fronted by a single nginx entrypoint that routes between them.Closes IBM/mcp-context-forge#5803
PRD
Problem
Iterating on the data-plane locally required manual image builds and piecemeal
docker composeinvocations, with no easy way to bring up the dependent control-plane stack (Postgres, PgBouncer, Redis, control-plane, nginx) end-to-end.Goal
One command builds the data-plane image, one command brings up the whole stack, one command tears it down — so the dev/test loop for the data-plane is fast and repeatable.
Requirements (from the issue)
make docker-prodbuilds the data-plane production image (dataplane:latest) fromdocker/Dockerfile.make testing-upbrings up the full local stack viadocker/docker-compose.yml, and fails fast with a clear message ifdataplane:latestisn't built yet.make testing-downstops the stack.docker-compose.yml/nginx.confupdated so the stack is actually testable end-to-end:mcp-gateway-net→contextforge-gateway-net).data-planeservice builds from the local image instead of aghcr.iotag.control-plane+ one-shotmigration+postgres+pgbounceradded so the data-plane has a real control-plane to talk to.service_healthydependency gating so services don't race each other on startup.data-planeandcontrol-planecontainer names.Services
make testing-upbrings upnginx/contextforge-rs/*→ data-plane, everything else → control-planedata-planedataplane:latestcontrol-planemcp-context-forgecontrol-plane — config, policy, identity ownermigrationcontrol-plane(implicit dependency, not listed explicitly on the Make target)postgrespgbouncerpostgresredisfast_time_serverregister_fast_timefast_time_serverwithcontrol-planeover its admin APIResource limits (
make testing-up)nginxcontrol-planeredispostgrespgbouncerdata-planefast_time_serverNot part of this target:
contextforge-gateway-one/twoandmcp-counter-tool-one/tworemain separate, pre-existing demo services untouched bytesting-up.Stack topology (
make testing-up)flowchart LR client(["client"]) --> nginx["nginx"] nginx --> dataplane["data-plane"] nginx --> controlplane["control-plane"] dataplane --> redis["redis"] controlplane --> redis controlplane --> postgres["postgres\n(via pgbouncer)"] dataplane --> fastts["fast_time_server"]Out of scope
Testing (from the issue)
make docker-prodbuilds image successfully.make testing-upbrings up all services healthy.make testing-downstops stack cleanly.Changes
docker/docker-compose.yml
mcp-gateway-net→contextforge-gateway-netand applied it consistently across all services.contextforge-gateway-rs→data-plane, now built from the localdataplane:latestimage (${IMAGE_LOCAL:-dataplane:latest}) instead of a pre-builtghcr.ioimage.CONTEXTFORGE_GATEWAY_RS_REDIS_CONNECTION_MODE,CONTEXTFORGE_GATEWAY_RS_UPSTREAM_CONNECTION_MODE, and renamed the token-verification key env vars to theCONTEXTFORGE_GATEWAY_RS_*prefix.data-planenow waits onredisandcontrol-planeviaservice_healthy(previously justservice_startedon redis).container_nameto every service for easierdocker ps/ log inspection.postgres— Postgres 18 with tuned connection/memory settings, healthcheck, and a namedpgdatavolume.pgbouncer— connection pooler in front of Postgres (transaction pooling, sized pool limits).migration— one-shot init container that runs Alembic migrations + bootstrap directly against Postgres (bypasses PgBouncer since advisory locks are session-scoped) before control-plane starts.control-plane— the Pythonmcp-context-forgecontrol-plane image, wired to Postgres (via PgBouncer), Redis, and JWT keys; gated onmigrationcompleting successfully andpgbouncer/redisbeing healthy.fast_time_server— test MCP server used for exercising the SSO/monitoring/testing profiles.register_fast_time— one-shot job that mints an admin JWT and registersfast_time_serverwith the control-plane over its admin API.redisand switched its network tocontextforge-gateway-net.docker/nginx.conf
upstream contextforge-gateway-rsblock.mapfor$contextforge_control_backend_urlpointing atcontrol-plane:4444, alongside the existing data-plane backend map (now pointing atdata-plane:4445instead ofcontextforge-gateway-rs:4445).location /block that proxies everything not matched by/contextforge-rs,/health, or/nginx_statusto the control-plane, with the same rate-limiting/timeout/proxy-header conventions used elsewhere in the file.docker/Dockerfile
--features contextforge-gateway-rs-lib/with_toolsso the local image includes the tools feature set used by the compose stack.Makefile (new)
make docker-prod— builds thedataplane:latestimage fromdocker/Dockerfile.make testing-up— brings up the full testing stack (nginx, control-plane, redis, postgres, pgbouncer, data-plane, fast_time_server), refusing to start ifdataplane:latesthasn't been built yet.make testing-down— stops the stack.make help— self-documenting target list.Test plan
make docker-prodbuildsdataplane:latestsuccessfully.make testing-upbrings up the full stack and all healthchecks pass (postgres,pgbouncer,redis,control-plane,data-plane).migrationcontainer runs to completion beforecontrol-planestarts./contextforge-rs/*todata-planeand everything else tocontrol-plane.register_fast_timesuccessfully registersfast_time_serveragainst the control-plane admin API.