docker-compose.e2e.dbs.yml
Rama main · réplica de lectura del repositorio original.
name: rsync-ai-e2e
services:
# ============================================================================
# E2E: MySQL (seeded) + Postgres (logical replication) + MinIO + Mock GitHub
# Runs as a separate Docker Desktop group: rsync-ai-e2e
# ============================================================================
mysql-e2e:
image: mysql:8.4
container_name: rsync-ai-mysql-e2e
# Enable MySQL binlog (required for Debezium CDC)
command:
- "--server-id=184054"
- "--log-bin=mysql-bin"
- "--binlog-format=ROW"
- "--binlog-row-image=FULL"
- "--gtid-mode=ON"
- "--enforce-gtid-consistency=ON"
# Re-enable mysql_native_password (DISABLED by default on 8.4, NOT removed
# until 9.x). Without this, e2e_user defaults to caching_sha2_password,
# whose cold-cache first-auth requires TLS/RSA — the Go batch executor
# (go-sql-driver) can't complete it over the plaintext socket and fails
# with "2061 Authentication requires secure connection" until some other
# client warms the cache. That made the golden batch gate test flaky
# (green only when the container happened to be warm). init/001 switches
# e2e_user to this plugin so auth is deterministic for every client.
- "--mysql-native-password=ON"
environment:
- MYSQL_ROOT_PASSWORD=rootpassword
- MYSQL_DATABASE=e2e_db
- MYSQL_USER=e2e_user
- MYSQL_PASSWORD=e2e_password
ports:
- "127.0.0.1:${RSYNC_HP_MYSQL_E2E:-3307}:3306"
volumes:
- ./e2e/mysql/init:/docker-entrypoint-initdb.d:ro
healthcheck:
test: ["CMD-SHELL", "mysqladmin ping -h 127.0.0.1 -uroot -prootpassword --silent"]
interval: 5s
timeout: 5s
retries: 20
networks:
rsync-ai_default:
aliases:
- mysql-e2e
- e2e-mysql # connection configs may use either name
postgres-e2e:
image: postgres:16-alpine
container_name: rsync-ai-postgres-e2e
# Enable logical replication so Postgres can be used as a Debezium CDC source in E2E.
command:
- postgres
- -c
- wal_level=logical
- -c
- max_wal_senders=10
- -c
- max_replication_slots=10
environment:
- POSTGRES_USER=e2e_user
- POSTGRES_PASSWORD=e2e_password
- POSTGRES_DB=e2e_db
ports:
- "127.0.0.1:${RSYNC_HP_POSTGRES_E2E:-5433}:5432"
volumes:
- ./e2e/postgres/init:/docker-entrypoint-initdb.d:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U e2e_user -d e2e_db"]
interval: 5s
timeout: 5s
retries: 20
networks:
rsync-ai_default:
aliases:
- postgres-e2e
# STANDALONE-ONLY minio. The e2e GATE (e2e/run_gate.sh) does NOT start this —
# it brings up the MAIN stack's minio (docker-compose.yml, container
# rsync-ai-minio) and runs `minio-init` below with `--no-deps`. This service
# exists only for `make e2e-start` (e2e DBs without the main stack), where it
# provides minio + host ports 9000/9001.
# NO hard container_name pin: the main stack already owns `rsync-ai-minio`, and
# a pinned name here crash-collides ("container name already in use") if both
# run. Without the pin Docker auto-names this one. Do NOT run this standalone
# minio while the main stack is up — both alias `minio` on the shared network,
# which makes that hostname ambiguous.
minio:
# Gated behind the `standalone-minio` profile so a plain `up` (the old
# `make e2e-start`) does NOT start it. It shares the `minio` network alias
# with the main stack's `rsync-ai-minio`; running both makes `minio:9000`
# DNS-round-robin across two stores, so claim-check writes and reads can hit
# different MinIO instances → NoSuchKey → DLQ → silent data drop. Only start
# it when the main stack is absent — `make e2e-start` guards on exactly that.
profiles: ["standalone-minio"]
# Chainguard's build: MinIO withdrew anonymous pulls from docker.io/minio/* and
# then quay.io/minio/*. Floating on purpose (a torn-down fixture; see the
# ALLOWLIST in llm-service/tests/test_shipped_images_are_pinned.py).
image: cgr.dev/chainguard/minio:latest
# Root, like the image this replaces: `minio_data` persists across runs, and a
# volume the old image wrote is root-owned, which this image's default user
# (65532) cannot write.
user: "0:0"
command: ["server", "/data", "--console-address", ":9001"]
environment:
- MINIO_ROOT_USER=minioadmin
- MINIO_ROOT_PASSWORD=minioadmin
ports:
- "127.0.0.1:${RSYNC_HP_MINIO:-9000}:9000"
- "127.0.0.1:${RSYNC_HP_MINIO_CONSOLE:-9001}:9001"
volumes:
- minio_data:/data
healthcheck:
# The image has no curl; mc ships in it with a default `local` alias.
test: ["CMD", "mc", "ready", "local"]
interval: 5s
timeout: 5s
retries: 20
networks:
rsync-ai_default:
aliases:
- minio
minio-init:
# Same profile as `minio`. The e2e GATE starts it explicitly with
# `up -d --no-deps minio-init` (an explicitly-named service starts even when
# its profile is inactive) and points it at the MAIN stack's minio; a plain
# profile-less `up` must NOT pull it in.
profiles: ["standalone-minio"]
# The server image: it ships `mc` and the shell the entrypoint below needs.
image: cgr.dev/chainguard/minio:latest
container_name: rsync-ai-minio-init
depends_on:
minio:
condition: service_healthy
entrypoint: ["/bin/sh", "-lc"]
command:
- |
mc alias set rsync http://minio:9000 minioadmin minioadmin;
mc mb -p rsync/pipeline-data || true;
mc mb -p rsync/intermediate-storage || true;
mc mb -p rsync/agent-artifacts || true;
mc mb -p rsync/audit-logs || true;
mc mb -p rsync/backups || true;
echo "minio-init done";
restart: "no"
networks:
rsync-ai_default: {}
# E2E: Mock GitHub OAuth + API server (offline auth-expiry tests)
mock-github:
image: python:3.11-alpine
container_name: rsync-ai-mock-github
environment:
- PORT=8080
command: ["python", "/app/mock_github_server.py"]
volumes:
- ./e2e/mock_github_server.py:/app/mock_github_server.py:ro
ports:
- "127.0.0.1:${RSYNC_HP_MOCK_GITHUB:-8099}:8080"
healthcheck:
# Use IPv4 explicitly: Alpine wget may prefer IPv6 ::1 for localhost
# while the server binds only on 0.0.0.0, causing false "Connection refused".
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:8080/health"]
interval: 5s
timeout: 3s
retries: 20
networks:
rsync-ai_default:
aliases:
- mock-github
# E2E: Mock GraphQL server (deterministic Relay `widgets` API — offline,
# mock-backed generated-GraphQL-connector pipeline test). Only relevant when
# E2E_INCLUDE_GRAPHQL=1; harmless otherwise (unused idle container).
mock-graphql:
image: python:3.11-alpine
container_name: rsync-ai-mock-graphql
environment:
- PORT=8080
command: ["python", "/app/mock_graphql_server.py"]
volumes:
- ./e2e/mock_graphql_server.py:/app/mock_graphql_server.py:ro
ports:
- "127.0.0.1:${RSYNC_HP_MOCK_GRAPHQL:-8098}:8080"
healthcheck:
# IPv4 explicit: Alpine wget may prefer IPv6 ::1 while the server binds 0.0.0.0.
test: ["CMD", "wget", "-qO-", "http://127.0.0.1:8080/health"]
interval: 5s
timeout: 3s
retries: 20
networks:
rsync-ai_default:
aliases:
- mock-graphql
# Extra MySQL instance for CDC testing (separate from existing mysql-e2e)
mysql-e2e2:
image: mysql:8.4
# Enable MySQL binlog (required for Debezium CDC)
command:
- "--server-id=284054"
- "--log-bin=mysql-bin"
- "--binlog-format=ROW"
- "--binlog-row-image=FULL"
- "--gtid-mode=ON"
- "--enforce-gtid-consistency=ON"
environment:
- MYSQL_ROOT_PASSWORD=rootpassword
- MYSQL_DATABASE=e2e_db
- MYSQL_USER=e2e_user
- MYSQL_PASSWORD=e2e_password
volumes:
- ./e2e/mysql/init:/docker-entrypoint-initdb.d:ro
# Seed richer demo datasets (fintech_db, logistics_db) so table selection has real tables.
- ./e2e/mysql/fixtures/fintech_logistics.sql:/docker-entrypoint-initdb.d/004_fintech_logistics.sql:ro
healthcheck:
test: ["CMD-SHELL", "mysqladmin ping -h 127.0.0.1 -uroot -prootpassword --silent"]
interval: 5s
timeout: 5s
retries: 20
networks:
rsync-ai_default:
aliases:
- mysql-e2e2
# Extra Postgres instance for CDC testing (separate from existing postgres-e2e)
postgres-e2e2:
image: postgres:16-alpine
# Required for Debezium Postgres CDC:
# - wal_level=logical
# - enough slots/senders for replication
command: ["postgres", "-c", "wal_level=logical", "-c", "max_replication_slots=10", "-c", "max_wal_senders=10"]
environment:
- POSTGRES_USER=e2e_user
- POSTGRES_PASSWORD=e2e_password
- POSTGRES_DB=e2e_db
volumes:
- ./e2e/postgres/init:/docker-entrypoint-initdb.d:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U e2e_user -d e2e_db"]
interval: 5s
timeout: 5s
retries: 20
networks:
rsync-ai_default:
aliases:
- postgres-e2e2
# MongoDB (replica set) for Debezium CDC testing
mongo-e2e:
image: mongo:6
container_name: rsync-ai-mongo-e2e
command: ["mongod", "--replSet", "rs0", "--bind_ip_all"]
healthcheck:
test: ["CMD-SHELL", "mongosh --quiet --eval 'db.runCommand({ ping: 1 }).ok' | grep 1 >/dev/null"]
interval: 5s
timeout: 5s
retries: 30
networks:
rsync-ai_default:
aliases:
- mongo-e2e
mongo-e2e-init:
image: mongo:6
depends_on:
mongo-e2e:
condition: service_healthy
entrypoint: ["/bin/sh", "-lc"]
command:
- |
mongosh --host mongo-e2e --quiet --eval '
try {
rs.status();
print("replica set already initialized");
} catch (e) {
rs.initiate({_id:"rs0", members:[{_id:0, host:"mongo-e2e:27017"}]});
print("replica set initiated");
}'
restart: "no"
networks:
rsync-ai_default: {}
networks:
# Attach e2e DBs to the main app network so Kafka Connect and MCP connectors can resolve them by hostname.
rsync-ai_default:
external: true
name: rsync-ai_default
volumes:
minio_data: