User-defined Playground

PostgreSQL Debezium Playground

Watch a three-member Patroni PostgreSQL 16 cluster fail over while Debezium keeps streaming outbox events to Kafka.

PostgreSQL Debezium playground: Watch a three-member Patroni PostgreSQL 16 cluster fail over while Debezium keeps streaming outbox events to Kafka.
Machines & network
1 VM · 4 vCPU · 8GiB RAM
Playground host Internet NAT MASQUERADE local (bridge) 172.16.0.0/24 gw 172.16.0.1/24eth0
VM
vCPU ·
eth0
/
docker
About
Important

This playground requires a paid iximiuz Labs plan. It does not work on the free tier.

On the free tier, startup fails while building the Patroni image, because free-tier sessions cannot reach the PostgreSQL package repository (apt.postgresql.org). Free-tier VMs are also capped at 2 vCPUs and 4 GiB of RAM, half of what the stack needs.

What is running

One VM runs the full Compose stack from the project repository: three etcd voters, three Patroni/PostgreSQL 16 members, an HAProxy write endpoint, a KRaft Kafka broker, and a Debezium Connect worker streaming the app.outbox_events table to Kafka. The init tasks clone the repository into ~/postgres-debezium-playground, build the Patroni image, and run make up, so the stack is healthy when the terminal opens.

This is an educational single-host lab, not a production blueprint. Every role uses the password test.

Explore it

cd ~/postgres-debezium-playground
make status     # etcd, Patroni roles, HAProxy, Kafka topics, connector, slot
make failover   # stop the primary, watch a replica take over, rejoin the old one
make verify     # full replication, CDC, promotion, rejoin, and persistence check
make logs       # follow every service

Insert an outbox event through HAProxy, which always routes to the current primary:

./scripts/compose.sh exec -e PGPASSWORD=test postgres1 \
  psql -h haproxy -U postgres -d playground -c "
    INSERT INTO app.outbox_events (id, correlation_id, aggregate_type, aggregate_id, event_type, payload)
    VALUES (gen_random_uuid(), gen_random_uuid(), 'orders', 'order-42', 'ORDER_CREATED', '{\"order_id\":\"order-42\"}');"

Read it back from the routed Kafka topic, keyed by aggregate ID, and press Ctrl+C to stop:

./scripts/compose.sh exec kafka /opt/kafka/bin/kafka-console-consumer.sh \
  --bootstrap-server kafka:29092 --topic playground.events.orders \
  --from-beginning --formatter-property print.key=true

Run make failover and insert again: the event still arrives, possibly with duplicates around the promotion, because delivery is at-least-once.

Connect from your own machine

The stack binds its ports to the VM's loopback interface only. Forward them over SSH with labctl, using the session ID from labctl playground list:

labctl port-forward <session-id> -L 5432:5432 -L 9092:9092 -L 8083:8083

Then use 127.0.0.1:5432 (database playground, user postgres, password test), Kafka at 127.0.0.1:9092, and the Connect REST API at http://127.0.0.1:8083. Patroni member APIs are on ports 8008 to 8010.

Every playground includes
Learn more about playgrounds
Start
Settings