# Before/after switch is via Docker Compose PROFILES — no file editing: # before world: docker compose --profile before up -d # the switch: docker compose stop transformer && docker compose --profile after up -d # kafka / cli / console / postgres run in BOTH worlds; `transformer` is the "before" world, # `gateway` is the "after" world. The kafka volume is preserved across the switch, so the # transformer's committed offsets survive to seed the consumer migration. services: kafka: image: apache/kafka:4.2.0 hostname: kafka ports: ["9092:9092"] environment: KAFKA_NODE_ID: 1 KAFKA_PROCESS_ROLES: broker,controller KAFKA_LISTENERS: PLAINTEXT://:9092,CONTROLLER://:9093 KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092 KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER KAFKA_CONTROLLER_QUORUM_VOTERS: 1@kafka:9093 KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,CONTROLLER:PLAINTEXT KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1 KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1 healthcheck: # broker is ready once it answers an admin request; everything else waits on this test: ["CMD-SHELL", "/opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 --list || exit 1"] interval: 5s timeout: 5s retries: 30 start_period: 15s cli: image: apache/kafka:4.2.0 entrypoint: ["/bin/sh", "-c", "sleep infinity"] depends_on: [kafka] volumes: - ./scripts:/scripts - ./topic-view:/topic-view # Create the input + output topics once, then exit. Runs in both worlds; needs no Console or license. # Waits for the kafka healthcheck, so no polling here. create-topics: image: apache/kafka:4.2.0 depends_on: kafka: condition: service_healthy entrypoint: ["/bin/sh", "-c"] command: - | /opt/kafka/bin/kafka-topics.sh --bootstrap-server kafka:9092 --create --if-not-exists --topic orders --partitions 3 --replication-factor 1 /opt/kafka/bin/kafka-topics.sh --bootstrap-server kafka:9092 --create --if-not-exists --topic orders_fr_kstreams --partitions 3 --replication-factor 1 # "before" world only — the Kafka Streams transformer, built locally from ./transformer. transformer: build: ./transformer profiles: ["before"] depends_on: kafka: condition: service_healthy create-topics: condition: service_completed_successfully environment: BOOTSTRAP_SERVERS: kafka:9092 APPLICATION_ID: orders-transformer # "after" world only — the Conduktor Gateway. Started by `--profile after`; needs CONDUKTOR_LICENSE_KEY. gateway: image: conduktor/conduktor-gateway:3.20.0 profiles: ["after"] depends_on: kafka: condition: service_healthy ports: ["6969:6969", "8888:8888"] environment: GATEWAY_LICENSE_KEY: ${CONDUKTOR_LICENSE_KEY:-} # required for the 'after' profile — see README KAFKA_BOOTSTRAP_SERVERS: kafka:9092 GATEWAY_ADVERTISED_HOST: gateway # all CLI runs inside the cli container + Console is on the network GATEWAY_ACL_ENABLED: "false" # tutorial: no client auth; plain clients behave like normal Kafka healthcheck: test: ["CMD", "curl", "-f", "localhost:8888/health"] interval: 5s timeout: 3s retries: 30 postgres: image: postgres:16 environment: POSTGRES_USER: conduktor POSTGRES_PASSWORD: conduktor POSTGRES_DB: conduktor volumes: ["pgdata:/var/lib/postgresql/data"] console: image: conduktor/conduktor-console:1.46.1 depends_on: [postgres, kafka] ports: ["8080:8080"] volumes: - ./console/platform-config.yaml:/etc/conduktor/platform-config.yaml environment: CDK_IN_CONF_FILE: /etc/conduktor/platform-config.yaml # tell Console to load the mounted config (clusters) CDK_DATABASE_URL: "postgresql://conduktor:conduktor@postgres:5432/conduktor" volumes: pgdata: {}