Confluent Platform 7.9 · Apache Kafka · Kafka Connect · Schema Registry · ksqlDB · Control Center

Confluent Platform, screen by screen: a streaming pipeline you can open in a browser

Kafka is easy to describe and hard to picture: topics, partitions, offsets and consumer groups are mostly invisible. This post runs the whole Confluent Platform on one machine, with live sample data flowing through it, and walks through Control Center one screen at a time: where the data comes from, where it lands, how its shape is governed, and how a SQL statement turns a stream of events into a continuously updated table.

The environment is live at confluent.maximo.me.uk. It is a sandbox: one broker, generated data, no sign-in.

What you will learn

Reading time: about 12 minutes.

1 · The ideaThe pipeline in one picture

Two Datagen source connectors generate fake website traffic: page views and user profiles. Kafka Connect writes them to two topics, Schema Registry stores the Avro schema of each record, and ksqlDB reads the page views and keeps a running count per page in a new topic. Control Center watches all of it.

Datagenpageviews, users Kafka Connect2 source connectors Kafka brokertopics pageviews, users ksqlDBCOUNT(*) GROUP BY page PAGEVIEWS_PER_PAGEtable, compacted topic Schema RegistryAvro schemas Control Centermonitors brokers, topics, connectors, queries, consumers
Key idea

Every arrow is a Kafka topic. Connect, ksqlDB and Control Center do not call each other directly; they read and write topics. Even Connect's own configuration, offsets and status are stored in topics (_connect-configs, _connect-offsets, _connect-status).

2 · ArchitectureThe six containers

The platform runs as one Podman pod, so the six containers share localhost and find each other without service discovery. All images are the public confluentinc/*:7.9.10 images.

ContainerImagePortWhat it does
Brokercp-server9092Kafka itself, in KRaft mode: the same process is broker and controller, so there is no ZooKeeper.
Schema Registrycp-schema-registry8081Stores Avro, JSON Schema and Protobuf schemas per subject and checks compatibility when a schema changes.
Kafka Connectcp-server-connect8083Runs connectors that copy data in (sources) or out (sinks). The Datagen plugin is installed from Confluent Hub at start.
ksqlDBcp-ksqldb-server8088Stream processing in SQL: streams, tables, joins and aggregations that run continuously.
REST Proxycp-kafka-rest8082Produce, consume and administer Kafka over HTTP, for clients that cannot speak the Kafka protocol.
Control Centercp-enterprise-control-center9021The web console in this post.

Kafka, Schema Registry, Connect, ksqlDB and REST Proxy are free to run. Control Center and cp-server are enterprise components; on a single broker they run under the developer licence without a key.

3 · Control CenterThe cluster: home, overview, brokers

The home page lists the Kafka clusters Control Center manages. Here there is one, controlcenter.cluster, with one ksqlDB cluster and one Connect cluster attached.

Control Center home with one healthy cluster
Home: one healthy cluster, its throughput and the services connected to it.

The cluster overview puts the counts in one place: brokers, topics, partitions, connectors, ksqlDB queries. The two numbers to watch on a real cluster are under-replicated partitions and out-of-sync replicas. Both should be zero; anything else means a broker is falling behind or is down.

Cluster overview
Cluster overview: 1 broker, 66 topics, 214 partitions, 2 running connectors, 1 persistent query.

66 topics may look like a lot for two data sources. Most are internal: Control Center keeps its own aggregates in Kafka Streams state topics, Connect stores its state in topics, and ksqlDB writes a command topic and a changelog for each query. Only pageviews, users and PAGEVIEWS_PER_PAGE hold business data.

Brokers overview
Brokers: throughput in and out, partition and replica counts, the KRaft controller and disk use.
KRaft

“KRaft leader kraft.id 1” and “Metadata quorum Yes” mean the cluster keeps its metadata in Kafka's own Raft log. Kafka 4.0 removed ZooKeeper entirely; Confluent Platform 7.9 still supports both, and this environment uses KRaft only.

4 · DataTopics, messages and schemas

The topic list hides internal topics by default. Each row shows partitions and the produce and consume rates over the last five minutes. pageviews is both produced and consumed (ksqlDB reads it); users is only produced, because nothing reads it yet.

Topics list
Topics: health, partitions, production and consumption per topic.
pageviews topic overview
One topic: throughput, availability, storage and, further down, each partition with its leader, offset and size.

Reading messages

The Messages tab is a live tail. Every record has a partition, an offset (its position in that partition, which never changes), a key and a value. Datagen sends one page view per second: a timestamp, a user and a page.

Messages in the pageviews topic
Messages: offsets climb by one per record. The values are decoded from Avro with the schema in Schema Registry.
Offsets are the heart of Kafka

A topic is an append-only log. Consumers do not delete what they read; each consumer group stores its own offset per partition. That is why the same data can feed ksqlDB, a database sink and an analytics job at the same time, and why a new consumer can replay history.

The schema

The records on the wire are Avro: compact binary with no field names. The schema lives in Schema Registry under the subject pageviews-value, and each record carries only the schema id. Compatibility mode Backward means a new version must still be able to read data written with the previous one, for example by adding a field with a default.

Avro schema of pageviews
Schema: three fields (viewtime, userid, pageid), version 1, backward compatible. “Evolve schema” adds a version and checks compatibility first.

5 · IntegrationKafka Connect: data in without code

Connect is where most real integrations live: a JDBC source reading a database table, a sink writing to Elasticsearch, S3 or another database, a CDC connector streaming every change from a database's log. Each connector is a piece of JSON configuration; Connect runs it, scales it into tasks and restarts it after a failure.

Connectors list
Connectors: two Datagen sources, both running, one task each.

The whole configuration of datagen-pageviews:

{
  "connector.class": "io.confluent.kafka.connect.datagen.DatagenConnector",
  "kafka.topic": "pageviews",
  "quickstart": "pageviews",
  "key.converter": "org.apache.kafka.connect.storage.StringConverter",
  "max.interval": "1000",
  "iterations": "100000000",
  "tasks.max": "1"
}

There is no value converter here: the worker's default, AvroConverter, registers the schema in Schema Registry and serialises each record. Swap the connector class and its settings and the same pattern reads from a real system.

datagen-pageviews connector
One connector: its tasks and the worker running them, with Pause, Restart and Delete.

6 · ProcessingksqlDB: SQL over a stream

ksqlDB has two kinds of objects. A stream is the topic seen as an unbounded series of events: every page view is a new row. A table is the latest value per key: one row per page, updated as events arrive. Two statements build the pipeline:

CREATE STREAM PAGEVIEWS_S WITH (KAFKA_TOPIC='pageviews', VALUE_FORMAT='AVRO');

CREATE TABLE PAGEVIEWS_PER_PAGE AS
  SELECT PAGEID, COUNT(*) AS VIEWS
  FROM PAGEVIEWS_S
  GROUP BY PAGEID
  EMIT CHANGES;

The stream needs no column list: ksqlDB reads the fields from Schema Registry. The table is a persistent query. It keeps running after the statement returns, writes each new count to a compacted topic called PAGEVIEWS_PER_PAGE, and survives restarts.

ksqlDB streams
Streams: PAGEVIEWS_S over the pageviews topic (Avro), plus ksqlDB's own processing log.
ksqlDB flow
Flow: the lineage from stream to table through the CREATE-TABLE query.
ksqlDB persistent queries
Persistent queries: the generated SQL, source and sink, messages per second and an error counter. “Explain query” shows the Kafka Streams topology underneath.

Querying the table

A push query (EMIT CHANGES) stays open and sends every change as it happens. A pull query (no EMIT CHANGES) returns the current value and ends, like a lookup in a database:

-- push: every new count, as it changes
SELECT PAGEID, VIEWS FROM PAGEVIEWS_PER_PAGE EMIT CHANGES;

-- pull: the current count for one page, then done
SELECT VIEWS FROM PAGEVIEWS_PER_PAGE WHERE PAGEID = 'Page_18';
ksqlDB editor running a push query
Editor: the push query running. Each card is a new count for a page; the list keeps growing until Stop. Run through the public address, which needs the proxy route described in section 9.
Why this matters

The table is a materialised view that is never stale and never recomputed from scratch. The same pattern counts alarms per asset, totals meter readings per hour or flags a sensor that has gone quiet, all as the events arrive.

7 · OperationsConsumer groups and lag

Every application that reads a topic does so as a consumer group. Lag is how far behind the group is: the latest offset in the partition minus the offset the group has committed. Steady lag is normal; lag that only grows means the consumer cannot keep up or has stopped.

Consumer groups
Consumer groups: Control Center's own groups, the ksqlDB query's group and a telemetry sampler, with state, lag, members and topics.

8 · Hands-onTry it from the command line

The REST APIs are what Control Center calls. On the host running the pod (the ports are not published to the internet):

# connectors and their state
curl -s localhost:8083/connectors?expand=status

# schema subjects
curl -s localhost:8081/subjects

# produce one JSON record through the REST Proxy
curl -s -X POST localhost:8082/v3/clusters/MkU3OEVBNTcwNTJENDM2Qk/topics/demo/records \
  -H 'Content-Type: application/json' \
  -d '{"value":{"type":"JSON","data":{"asset":"PUMP-01","temp":71.5}}}'

# run ksqlDB statements
curl -s -X POST localhost:8088/ksql -H 'Content-Type: application/vnd.ksql.v1+json' \
  -d '{"ksql":"SHOW STREAMS; SHOW TABLES; SHOW QUERIES;"}'

Kafka clients on the same machine connect to localhost:29092.

Try it

Create a second table that joins the two streams: page views per user region. Make a stream over users, re-key it into a table by userid, join PAGEVIEWS_S to it and GROUP BY REGIONID. Then open the Flow tab and see the lineage grow.

9 · Behind the scenesDesign notes and one trap

Trap: SELECT in the editor and the advertised URL

SELECT statements are the exception, push and pull alike. For those the browser opens a WebSocket straight to the ksqlDB advertised URL (CONTROL_CENTER_KSQL_<NAME>_ADVERTISED_URL), not through Control Center. If that URL is http://localhost:8088, queries work on the host and fail everywhere else with “An unknown error has occurred”, while every other ksqlDB page keeps working, which makes it look like a ksqlDB problem.

The fix: advertise the public address (https://your-host) and route its /ws/ path to ksqlDB in the reverse proxy, so the browser's wss://your-host/ws/query reaches port 8088.

10 · ReferenceGlossary

Topic
A named, append-only log of records, split into partitions.
Partition
The unit of order and parallelism. Records are ordered within a partition, not across partitions.
Offset
A record's fixed position in its partition.
Consumer group
A set of consumers sharing the work of reading a topic; each partition goes to one member.
Lag
Latest offset minus the group's committed offset.
KRaft
Kafka's built-in Raft metadata quorum, which replaced ZooKeeper.
Subject
The name schemas are versioned under in Schema Registry, usually <topic>-value.
Source / sink connector
Connect plugins that bring data into Kafka or deliver it out.
Stream / table
ksqlDB views of a topic: every event, or the latest value per key.
Persistent query
A ksqlDB statement that keeps running and writes its results to a topic.
Push / pull query
A query that streams changes until stopped, or one that returns the current state and ends.

Built and tested on Confluent Platform 7.9.10 (cp-server KRaft broker, Schema Registry, Kafka Connect with kafka-connect-datagen, ksqlDB, REST Proxy, Control Center), October 2026. Screens captured from the live environment.