Example Docker Compose stack for ProxySQL/orchestrator with:
- MySQL 8.0 primary + 3 replicas (GTID, official
mysql:8.0image) - 3 Orchestrator nodes in Raft HA (SQLite backend)
- HAProxy routing HTTP only to the current Raft leader
- ZooKeeper for Orchestrator KV (
submit-masters-to-kv-stores)
No external MySQL-replication image is required. Replicas are wired with a small
init script and GTID SOURCE_AUTO_POSITION.
Orchestrator lineage: Outbrain → Booking.com → GitHub → openark → Percona → ProxySQL (current maintainer).
docker compose up --buildOn first boot this will:
- Start MySQL 8 primary (
db1) and configure a replication user - Start three replicas (
db2–db4) and point them atdb1with GTID - Form a 3-node Orchestrator Raft cluster
- Auto-discover
db1via theorchestrator-bootstrapone-shot service
UI (leader only, via HAProxy):
Direct node ports: 3331 / 3332 / 3333.
docker compose exec orchestrator1 orchestrator-client -c topology --alias dummy-clusterExpected shape (versions will vary with the MySQL 8.0 patch level):
db1:3306 [0s,ok,8.0.x,rw,ROW,>>,GTID,P-GTID]
+ db2:3306 [0s,ok,8.0.x,ro,ROW,>>,GTID,P-GTID]
+ db3:3306 [0s,ok,8.0.x,ro,ROW,>>,GTID,P-GTID]
+ db4:3306 [0s,ok,8.0.x,ro,ROW,>>,GTID,P-GTID]
Or via the API / HAProxy:
curl -s http://127.0.0.1:8080/api/cluster/alias/dummy-cluster | jq .docker compose exec db2 mysql -uroot -ppassword -e "SHOW REPLICA STATUS\G" \
| egrep 'Source_Host:|Replica_IO_Running:|Replica_SQL_Running:|Seconds_Behind_Source:'docker compose up --build orchestrator1| Role | User | Password |
|---|---|---|
| MySQL root | root |
password |
| App DB | test_user |
test_password (test_db) |
| Replication | repl_user |
repl_password |
| Orchestrator topology | root |
password |
docker-compose.yml # full stack
Dockerfile # ProxySQL Orchestrator built from source (latest master)
docker/
entrypoint.sh # generates orchestrator.conf.json (Raft + SQLite + ZK)
haproxy.cfg # leader-only proxy via /api/leader-check
bootstrap-discover.sh # one-shot topology discovery
mysql/
primary.cnf # GTID + binlog for primary
replica.cnf # GTID for replicas
init-primary.sql # creates repl_user
init-replica.sh # CHANGE REPLICATION SOURCE TO … SOURCE_AUTO_POSITION=1
The image builds ProxySQL/orchestrator
from source (releases up to v4.31.1 ship a broken Bootstrap SRI hash that
breaks the web UI; latest master fixes it). Select any branch, tag, or
commit via ORCHESTRATOR_REF in .env (or the environment):
ORCHESTRATOR_REF=master # default
ORCHESTRATOR_REF=v3.2.6 # legacy openark-era releaseOld v3.x tags predate Go 1.17's module-graph pruning and need a
period-correct toolchain — set GOLANG_IMAGE alongside the ref:
ORCHESTRATOR_REF=v3.2.6
GOLANG_IMAGE=golang:1.16-busterThe built image records the exact commit in /usr/local/orchestrator/COMMIT.
Human-guided failover drills live under scenarios/ and are not part of the
default stack. Multi-tier leafs come from compose.multi-tier.yml only when a
scenario asks for them.
./scripts/scenarios list
./scripts/scenarios setup stranded-leafs # master dead, IMs must_not, leafs untagged
./scripts/scenarios status stranded-leafs
./scripts/scenarios solution stranded-leafs # facilitator spoilers
./scripts/scenarios shell # drill subshell with wrappers on PATH:
orchestrator-client -c topology --alias dummy-clusterSee scenarios/README.md for how to add new scenarios.
- MySQL 5.7 support dropped — stack targets MySQL 8.0 only.
- Replaces the old
docker-mysql-replicationimage with the official MySQL image and a few conf/init files (GTID makes setup much simpler than file/pos dumps). - Fresh data directories are required for init scripts to re-run
(
docker compose down -vif you need a clean slate). - Demo credentials only — do not use this layout in production.