From 862d2d676fafda543d4401be8a2c6d246bd3ee2f Mon Sep 17 00:00:00 2001 From: KrishVora01 Date: Mon, 17 Jun 2024 17:19:30 +0530 Subject: [PATCH 1/7] adding kafka doi docs --- kafka/README-short.txt | 1 + kafka/content.md | 269 +++++++++++++++++++++++++++++++++++++++++ kafka/get-help.md | 1 + kafka/github-repo | 1 + kafka/issues.md | 1 + kafka/license.md | 5 + kafka/logo.png | Bin 0 -> 5357 bytes kafka/maintainer.md | 1 + kafka/metadata.json | 9 ++ 9 files changed, 288 insertions(+) create mode 100644 kafka/README-short.txt create mode 100644 kafka/content.md create mode 100644 kafka/get-help.md create mode 100644 kafka/github-repo create mode 100644 kafka/issues.md create mode 100644 kafka/license.md create mode 100644 kafka/logo.png create mode 100644 kafka/maintainer.md create mode 100644 kafka/metadata.json diff --git a/kafka/README-short.txt b/kafka/README-short.txt new file mode 100644 index 000000000000..1cb62110de64 --- /dev/null +++ b/kafka/README-short.txt @@ -0,0 +1 @@ +Apache Kafka - An open-source distributed event streaming platform. diff --git a/kafka/content.md b/kafka/content.md new file mode 100644 index 000000000000..e0dd40167fdd --- /dev/null +++ b/kafka/content.md @@ -0,0 +1,269 @@ +# What is Apache Kafka®? + +Apache Kafka is an open-source event streaming platform used to collect, process, store, and integrate data at scale in real time. It powers numerous use cases including stream processing, data integration, and pub/sub messaging. + +Kafka was originally developed at LinkedIn, was open sourced in 2011, and became an Apache Software Foundation project in 2012. It is used by thousands of organizations globally to power mission-critical real-time applications, from stock exchanges, to e-commerce applications, to IoT monitoring & analytics, to name a few. + +%%LOGO%% + +## Quick start + +Start a Kafka broker: + +```noformat +docker run -d --name broker kafka:latest +``` + +Open a shell in the broker container: + +```noformat +docker exec --workdir /opt/kafka/bin/ -it broker sh +``` + +A *topic* is a logical grouping of events in Kafka. From inside the container, create a topic called `test-topic`: + +```noformat +./kafka-topics.sh --bootstrap-server localhost:9092 --create --topic test-topic +``` + +Write two string events into the `test-topic` topic using the console producer that ships with Kafka: + + ./kafka-console-producer.sh --bootstrap-server localhost:9092 --topic test-topic + +This command will wait for input at a `>` prompt. Enter `hello`, press `Enter`, then `world`, and press `Enter again`. Enter `Ctrl+C` to exit the console producer. + +Now read the events in the `test-topic` topic from the beginning of the log: + + ./kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test-topic --from-beginning + +You will see the two strings that you previously produced: + + hello + world + +The consumer will continue to run until you exit out of it by entering `Ctrl+C`. + +When you are finished, stop and remove the container by running the following command on your host machine: + + docker rm -f broker + +## Overriding the default broker configuration + +Apache Kafka supports a broad set of broker configurations that you may override via environment variables. The environment variables must begin with `KAFKA_`, and any dots in broker configurations should be specified as underscores in the corresponding environment variable. For example, to set the default number of partitions in topics, [`num.partitions`](https://kafka.apache.org/documentation/#brokerconfigs_num.partitions), set the environment variable `KAFKA_NUM_PARTITIONS`. See [here](https://github.com/apache/kafka/blob/trunk/docker/examples/README.md) for more information on overriding broker configuration in Docker. + +It's important to note that, if you are overriding *any* configuration, then *none* of the default configurations will be used. For example, to run Kafka in KRaft [combined mode](https://kafka.apache.org/documentation/#kraft_role) (meaning that the broker handling client requests and the controller handling cluster coordination both run in the same container) and set the default number of topic partitions to 3 instead of the default 1, we would specify `KAFKA_NUM_PARTITIONS` in addition to other required configurations: + + docker run -d \ + --name broker \ + -e KAFKA_NODE_ID=1 \ + -e KAFKA_PROCESS_ROLES=broker,controller \ + -e KAFKA_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093 \ + -e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://localhost:9092 \ + -e KAFKA_CONTROLLER_LISTENER_NAMES=CONTROLLER \ + -e KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT \ + -e KAFKA_CONTROLLER_QUORUM_VOTERS=1@localhost:9093 \ + -e KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 \ + -e KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR=1 \ + -e KAFKA_TRANSACTION_STATE_LOG_MIN_ISR=1 \ + -e KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS=0 \ + -e KAFKA_NUM_PARTITIONS=3 \ + kafka:latest + +Specifying this many environment variables on the command line gets cumbersome. It's simpler to instead use [Docker Compose](https://docs.docker.com/compose/) to specify and manage Kafka in Docker. Depending on how you installed Docker, you may already have Docker Compose. You can verify that it's available by checking if this command succeeds, and refer to the Docker Compose installation documentation [here](https://docs.docker.com/compose/install/) if it doesn't: + + docker compose version + +To run Kafka with Docker Compose and override the default number of topic partitions to be 3, first copy the following into a file named `docker-compose.yml`: + +```yaml +services: + broker: + image: kafka:latest + container_name: broker + environment: + KAFKA_NODE_ID: 1 + KAFKA_PROCESS_ROLES: broker,controller + KAFKA_LISTENERS: PLAINTEXT://localhost:9092,CONTROLLER://localhost:9093 + KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092 + KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER + KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT + KAFKA_CONTROLLER_QUORUM_VOTERS: 1@localhost:9093 + KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 + KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1 + KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1 + KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0 + KAFKA_NUM_PARTITIONS: 3 +``` + +Now, from the directory containing this file, bring Kafka up in detached mode so that the containers run in the background: + + docker compose up -d + +The above [quick start](#quick-start) steps will work if you'd like to test topic creation and producing / consuming messages. + +When you are finished, stop and remove the container by running the following command on your host machine from the directory containing the `docker-compose.yml` file: + + docker compose down + +## External clients + +The examples up to this point run Kafka client commands from within Docker. In order to run clients from outside Docker, two additional steps are needed when running one container in combined mode (it gets a little more complicated in the next section on multiple brokers). + +First, map the port that Kafka listens on to the same port on your host machine, either by passing `-p 9092:9092` to the `docker run` command: + + docker run -d -p 9092:9092 --name broker kafka:latest + +Or, if using Docker Compose, add the port mapping to the `broker` container spec: + + ports: + - 9092:9092 + +Second, download and unzip the [latest Kafka release](https://kafka.apache.org/documentation/#quickstart_download). The console producer and consumer CLI tools are included in the unzipped distribution's `bin` directory. The above [quick start](#quick-start) steps will work from your host machine; it's just that `localhost` refers to your host machine as opposed to the within-container `localhost`. + +## Multiple nodes + +In this section you will explore a more realistic Kafka deployment consisting of three brokers and three controllers running in their own containers (i.e., KRaft [isolated mode](https://kafka.apache.org/documentation/#kraft_role)). We'll also configure it such that we can connect to Kafka from within Docker or from the host machine. Bear in mind that doing this exercise in Docker is convenient to learn about multi-broker configurations and the Kafka protocol, but this Docker Compose example isn't appropriate for a production deployment. + +Compared to a single-node Kafka deployment, there is a bit more to do on the configuration front: + +1. `KAFKA_PROCESS_ROLES` is either `broker` or `controller` depending on the container's role, not the KRaft combined mode value `broker,controller` +2. `KAFKA_CONTROLLER_QUORUM_VOTERS` is a comma-separated list of the three controllers +3. We accept the default values for `KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR` (3), `KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR` (3), and `KAFKA_TRANSACTION_STATE_LOG_MIN_ISR` (2) now that there are enough brokers to support the default settings, so we don't specify these configurations (a partition's replicas must reside on different brokers for fault tolerance) +4. Brokers have two listeners: one for communicating within the Docker network, and one for connecting from the host machine. Because Kafka clients connect directly to brokers after initially connecting (bootstrapping), one listener uses the container name because it is a resolvable name for all containers on the Docker network. This listener is also used for inter-broker communication. The second listener uses `localhost` on a unique port that gets mapped on the host (29092 for `broker-1`, 39092 for `broker-2`, and 49092 for `broker-3`). With one node, a single listener on `localhost` works because the `localhost` name is conveniently correct from within the container and from the host machine, but this doesn't apply in a multi-node setup. + +To deploy this six-node setup on your machine, copy the following into a file named `docker-compose.yml`: + +```yaml +services: + controller-1: + image: kafka:latest + container_name: controller-1 + environment: + KAFKA_NODE_ID: 1 + KAFKA_PROCESS_ROLES: controller + KAFKA_LISTENERS: CONTROLLER://:9093 + KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT + KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER + KAFKA_CONTROLLER_QUORUM_VOTERS: 1@controller-1:9093,2@controller-2:9093,3@controller-3:9093 + KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0 + + controller-2: + image: kafka:latest + container_name: controller-2 + environment: + KAFKA_NODE_ID: 2 + KAFKA_PROCESS_ROLES: controller + KAFKA_LISTENERS: CONTROLLER://:9093 + KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT + KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER + KAFKA_CONTROLLER_QUORUM_VOTERS: 1@controller-1:9093,2@controller-2:9093,3@controller-3:9093 + KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0 + + controller-3: + image: kafka:latest + container_name: controller-3 + environment: + KAFKA_NODE_ID: 3 + KAFKA_PROCESS_ROLES: controller + KAFKA_LISTENERS: CONTROLLER://:9093 + KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT + KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER + KAFKA_CONTROLLER_QUORUM_VOTERS: 1@controller-1:9093,2@controller-2:9093,3@controller-3:9093 + KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0 + + broker-1: + image: kafka:latest + container_name: broker-1 + ports: + - 29092:9092 + environment: + KAFKA_NODE_ID: 4 + KAFKA_PROCESS_ROLES: broker + KAFKA_LISTENERS: 'PLAINTEXT://:19092,PLAINTEXT_HOST://:9092' + KAFKA_ADVERTISED_LISTENERS: 'PLAINTEXT://broker-1:19092,PLAINTEXT_HOST://localhost:29092' + KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT + KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER + KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT + KAFKA_CONTROLLER_QUORUM_VOTERS: 1@controller-1:9093,2@controller-2:9093,3@controller-3:9093 + KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0 + depends_on: + - controller-1 + - controller-2 + - controller-3 + + broker-2: + image: kafka:latest + container_name: broker-2 + ports: + - 39092:9092 + environment: + KAFKA_NODE_ID: 5 + KAFKA_PROCESS_ROLES: broker + KAFKA_LISTENERS: 'PLAINTEXT://:19092,PLAINTEXT_HOST://:9092' + KAFKA_ADVERTISED_LISTENERS: 'PLAINTEXT://broker-2:19092,PLAINTEXT_HOST://localhost:39092' + KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT + KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER + KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT + KAFKA_CONTROLLER_QUORUM_VOTERS: 1@controller-1:9093,2@controller-2:9093,3@controller-3:9093 + KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0 + depends_on: + - controller-1 + - controller-2 + - controller-3 + + broker-3: + image: kafka:latest + container_name: broker-3 + ports: + - 49092:9092 + environment: + KAFKA_NODE_ID: 6 + KAFKA_PROCESS_ROLES: broker + KAFKA_LISTENERS: 'PLAINTEXT://:19092,PLAINTEXT_HOST://:9092' + KAFKA_ADVERTISED_LISTENERS: 'PLAINTEXT://broker-3:19092,PLAINTEXT_HOST://localhost:49092' + KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT + KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER + KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT + KAFKA_CONTROLLER_QUORUM_VOTERS: 1@controller-1:9093,2@controller-2:9093,3@controller-3:9093 + KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0 + depends_on: + - controller-1 + - controller-2 + - controller-3 +``` + +Start the containers from the directory containing the `docker-compose.yml` file: + + docker compose up -d + +Now, the following commands will work to produce and consume from within the Docker network. First, open a shell on any of the nodes: + + docker exec --workdir /opt/kafka/bin/ -it broker-1 sh + +Now run these commands in the container shell to create a topic, produce to it, and consume from it: + + ./kafka-topics.sh --bootstrap-server broker-1:19092,broker-2:19092,broker-3:19092 --create --topic test-topic + + ./kafka-console-consumer.sh --bootstrap-server broker-1:19092,broker-2:19092,broker-3:19092 --topic test-topic --from-beginning + + ./kafka-console-producer.sh --bootstrap-server broker-1:19092,broker-2:19092,broker-3:19092 --topic test-topic + +Alternatively, you can run the client programs from your host machine by navigating to your Kafka distribution's `bin` directory and running: + + ./kafka-topics.sh --bootstrap-server localhost:29092,localhost:39092,localhost:49092 --create --topic test-topic2 + + ./kafka-console-producer.sh --bootstrap-server localhost:29092,localhost:39092,localhost:49092 --topic test-topic2 + + ./kafka-console-consumer.sh --bootstrap-server localhost:29092,localhost:39092,localhost:49092 --topic test-topic2 --from-beginning + +When you are finished, stop and remove the Kafka deployment by running the following command on your host machine from the directory containing the `docker-compose.yml` file: + + docker compose down + +## Additional resources + +- [Apache Kafka documentation](https://kafka.apache.org/documentation/) +- [Introduction to Kafka Streams](https://kafka.apache.org/documentation/streams/), Apache Kafka's library for developing stream processing applications on the JVM +- [Introduction to Kafka Connect](https://kafka.apache.org/documentation/#connect), Apache Kafka's framework for configuration-based connectors to move data from external systems into Kafka (source connectors) or from Kafka into external systems (sink connectors) +- [Books and papers](https://kafka.apache.org/books-and-papers) on Kafka and streaming in general +- [Slides and recordings of conference talks on streaming](https://www.kafka-summit.org/past-events) diff --git a/kafka/get-help.md b/kafka/get-help.md new file mode 100644 index 000000000000..332599b389ff --- /dev/null +++ b/kafka/get-help.md @@ -0,0 +1 @@ +[Official Apache Kafka Mailing lists](https://kafka.apache.org/contact) and [StackOverflow (tag `apache-kafka`)](https://stackoverflow.com/questions/tagged/apache-kafka) diff --git a/kafka/github-repo b/kafka/github-repo new file mode 100644 index 000000000000..412041d69299 --- /dev/null +++ b/kafka/github-repo @@ -0,0 +1 @@ +https://github.com/apache/kafka diff --git a/kafka/issues.md b/kafka/issues.md new file mode 100644 index 000000000000..8e1a4bb237b9 --- /dev/null +++ b/kafka/issues.md @@ -0,0 +1 @@ +https://issues.apache.org/jira/browse/KAFKA diff --git a/kafka/license.md b/kafka/license.md new file mode 100644 index 000000000000..9001299cdf8a --- /dev/null +++ b/kafka/license.md @@ -0,0 +1,5 @@ +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Apache Kafka, Kafka, Apache, the Apache kafka project logo, and the Apache feather logo are either registered trademarks or trademarks of [The Apache Software Foundation](https://apache.org/). diff --git a/kafka/logo.png b/kafka/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..3b3a1cf7e7945a7ae58fdaca950915602bbf342b GIT binary patch literal 5357 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 Date: Fri, 21 Jun 2024 15:31:27 +0530 Subject: [PATCH 2/7] replacing kafka logo --- kafka/logo.png | Bin 5357 -> 38865 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/kafka/logo.png b/kafka/logo.png index 3b3a1cf7e7945a7ae58fdaca950915602bbf342b..a0061aa9df23453da3305c77ea4222d447cffff3 100644 GIT binary patch literal 38865 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 literal 5357 zcmVc6N59rKJrG4Lv&kWII+v@{VCZ!l z46B5SY>nB%66!SipRXcNm84E~)+Is|<$Ui>UkEv`BfY+)s)hI-m6_h6b*5H5%Asua z&~y-2mqy)5@6BFTd|0n%>-B3~7aFrZpUfwa_UV6wE1o@1jI@gX3tTr36Dx(#y^oda zU{hsj76jwwx^rS>Ul|j>#?^z-vunVbOpc|T&ESPKUst@5RQBftTa+t~yorD-! zHezMpm@I{w@5J?;q{@*hCpb?i5RMV^Qm29-FD+cRm5{pbU+YmV^?GLIGyHLV?6MI*k4tQT*jTnRAjsv-;AlY}GX+SjpiJB5TgcRo_Cg#!4C ziwxNtK1wd}p#W}hk*V(dAG}d=#fs}OGKw6jPVpiBNv__;FU_@4Mpx+vpzl@wDYsZ! z#xH$Yk0vhpt{&x!NGb9geOaL*$v?V%2L8X)qrPP?H|mGL^%$$hRunnjRQaD#FhYG^ z_`2T+)hAOFIXx+^jCXuo9)D9@@9N=2k@c|l$i~R!6Yy$;Rc2n~ROe2!T*vn%>USCz zmq#P4GUaiuyh~VqLZ-C2GP{LXcN!L#N0Hup6og4e=s|yUS$E=@cBLOM8r^O46nb*7 zT)tr~e{2uC!*PRhj@;xDB!1POw>qy+AibFn{8qB2eSFuAhFq%%~`)sjo>WX$ei z^chdv?fn90gu~>@5+^*V)TgCn)DX(*OQK*iOtIo^J>fy%CHJ2?!pq1VceH}R>*iP~G--w(0nyW69wGiFr-l&IKh3-r?e4ugj z%mlHxpyg}-)MQuK)yl4fF^vyQpYO&6hNdi(55)!M8$qtIF>;k+d?eSPr%!POd7dJ1;hhlj}TBin=)LPS? zc^>$Crz-pT`~4w`o0Gr}iF;L!*Ah49SSV{v`{#+3=7|b-ds!QUIN37K4vHe6ZvLJ) zLgK2Nq$O@HkWi0t^W4DRIjHjVsw*7p`=1f1Mt_pPG@YA)#mzk`n#|=)x2T$1d^EC` zGVf*>MONEJ3{0P=UfVo}O>yb2F0$B$X}HA(+5OP$l(-FRGI6Q+Ri@$$S z;+Opw0!7Ma4GfB_$;EVDT9JWqHM^KxrC&7tAP2@J%vQMB@1iIQ_fF6D$L8 zocI?*ipIhU9ityt`m#(&lH_hS`?Gnw-`*u;h;h9bz4*xD@=x%qo_vxC`CcIN6_*m- zX;54eY^PievO@i+Qwb4Qd8gsd2k<%S8xjXs4Bh>_&Nbk94nEj~lZA8?nS-19X;fTL z?!B|fV4S@FJlDm8p(jDvI1twoDEPo0RmXAZdh@RSUggrxx~9^}&19hRs+`R3YZYP= z2BJgWztw~S6jgYP8}Ag@kE6DbzOG%UW8BM!3}b*E9xgN1(MT{wyyfStcm^Dsxjg^aIIT1Ccj@);i!7t*8t60crl^!ZKF zsyM(!@`*F~M>jw&)X=h?-sJK*s?CR3-Ki2v!aSw9wJ|_0g1v&NzAWeRIhvQ4HA4#R zP$v7w(pi7n%u@$<*!CqZBGM%!{*!TYYEBJ$Ir#amGm?gmsWqE0tM$~eY^`Q+vSaryR#bWz&)!JxRZ zo4S`|LpnOT3Ont&KP;}MxveT~88tm?RRz5*7JqR@LWjlWo1?RZl~3(u^wrG0-Q{*> z5Tf33L58>9JpDUyr%k!EBkPL&J*@)SLFsd0?G7pLPC-vp zOjD0nYo{0vD9!SRmd*kMc3^FOY_$gKD?hd#dwYnR=a(dQjCs0*)c^vm&v`6fPC5Dq zRI6Llp~cP1ie&Ne34$mOi(|wkZXuvAmMhRpW5!25kOArQNGSJ0MQOR-<}*!L;ZXxF z0V*;@Twah2oXa!k!Io|sCl|q79yo;qyU0W1Vs#v|=Bn41RxtVS+hHqL zg1P9ZzAu~0^R?4^i@30%Go-jVanGM;UTxID<5wBvD~Bc-J*(XNe;qehFZ&FALkZRA z!D=CfosI7vRr&^nC5by}>l+Ys>8fua{tlJjVP0jibh6_5u!J&rstG19lmx|{eDL8s zMBdQ!d6m+m@&LSTQ;W-R8SIydmoD*Kh<)Gsd|zCVsUc3&I#+VSzkj?u8}dmoOfFla z-?Q4jbFFsT(Cp<>C~~b?+bp&6Sa8WEM^)Bv$*}xUl~C+n!u-5cVU)7dq#sVP%ydcU zu>4V_P~7NjOO-iNJ=i@7^EP4q`wzcA7}BO`g_Fr&Ul^mmaEU&}v|;qWJZ|2@y0+FS zqkCdpCWBW?B(pR7^Uvp;E`HDPl8nl)E;5Jec;D5NSl0Mq zhU~)4HRSmK#iR9*d_+a|xt=2XKu5`?_c4ROd0u3ZsImHI_h)M^@)`4^3@*GsTPC5G ztrV-Ge(XGsd_q_?2Tbp|QVwotgO%*>pe|HqXdxact{2}Bg8i~WQrxMym31d-Z1GY& zp5lFAs&dwZih|ifU~zw2j}p>=(DG;a*`Ufpbj`?O~|pWn1o;HT1s2cY+!AOG@Y z(!iyc>5Y;r`!al&|Lg^({En2%mx1k{pTlKi<;sn=rMUujm2VC^dM+;?0)p4o=Js>) zd3(FMkGb@Wk!7@8MUkT&kU5 zR}X`sDsq+n#rfvH5I65%=zDSV-d<9b2666fOMCr}-dk}wT7IL@DD?UNJ1*Z7#X9WY z;i@)??4K*YH1J}9)|-3c$GH47DN;)N<%+`jZ60nu@?5BTNRk9U#6`o&L!NHc(QEy1 zC36)*-?3b1^6-(Rhvzr(Q(XGMkmXlgMnB)qg=UG~m0VR?SoPI|Dd;*HMIx><&QEC* z;>JF0J03_5T=dJMQO-X<1@Xf;r@2CQ)?iq*5S0TRPb`gPz+v8uG}lzt?$o9tvc8%?0}eHgMItaFdHOk_}~r0&tNZ zpmF@tvcQ$E=vuG$Py6+{3g4j}cr^TD7cS#fltr%IBh7aVpRHG`_3V(bc^FcZ9ALI?u%poW>P)T(-gfY@VW4vBYyj{_KhuF`t#`0B`RLd)cKQ;sdajs`4p2)Fb7qfWi#s zLuSA8)x=7T`e6dY_m*ld&#@&gT)qY_#nM^t^+^b`OhQs}`SzJuS$are3fo=I<=B*d z*T6+#*~*dV-pRGB>HwGDe}fC}@{*E@%Xx;`WO7<+;U=zz`a&nauX2w;!40130CvsES#LHaq}4ckZ*7$upT2+LMZ8{oG=irJE?IbNOf)$R8T0GMR1SWq*8~P0eX?Oy-?| z__(HOK8@U&-F{wQnLZ){G%n}9F3+!xUmn^_aG_NMPa>=B_Mk?y+LkPc3yoi{XgAgm z17u?CiH=djtoVFGnj)L!=L*Hfq?E9_J=UYt;{v2_;8TlU;y{JO@y<=FC|9Fc9;T;k zhwE&nLiakj-WWGWdK806g)=RLYBaA?Uk$5y!i)CwZrESxhl&1JH<5%-0&0JzvdTx{ z{oQ6-K_noAxI7mZdSx>PLa3Wkhhu9c64h8oE*|Ume@Z2&elWVg{_dUyHq-kUXrV9l zd9?8zJ}Cp853tfplhuvTTHkJ5D_9--e1q37>(20$m|PhGd}EhzL8F>dBt&566XQR(VTh&O&88_#u zU@-ixh(torxQQeF&Gn1kRkxQh=o=8)wzwtlMXQ_2;X1ckITs;P5@8^UZ_gSyiKp zOY3)+alt8Ua|uGa8t1UJp}JEbbSXP>QP3Vvp5{V33dVM?3+|u`?JrQ$?qH`ND7vNL z_(=2Z$Q1~x-`*Q&p@Fs;4vyV{^g}MSE1{S-;PKRX`al$QCwv}uS1ykl#jLm(_&aQE zZG|tmhzm@u4SY;kr8Bq$LynftTprr4a;dd7q;#{|WC&zPU+f0};|R5=Hp<)L#_V`Weo_7}xg9=5+6Tm<6gLh@?ixD>UxIa1K?NGZj!y}aW^ZhjXM8Cxjr zh$utbh)bx)8F6y~L${8j3vSxWMP6=|Gvip(HBoVMp;)@b%{>lkxIz#;6FT%OXy{cA62;|Yd&!nN_2spqT`itsPciA z{X?T0djk6Md0f)+XGq~St!zYG->5I_PmW|2uWa1E94V~laQUd8DE&`a*Bmz;&kEY( zx47V4zI#Cx!Ex_6e+n<<^3d@YRn*3pksEB@*{*EoLfutn*H)3K)b-38P)X0_3OwBb zJ_u4y8Kl&8UhbBBj|;`k(bN*AB8mL9?vu~=Skhh{HCcn`%{kC~0H&m#G?&jnv(Iyj z0b201zApM@#{*<9w{i(Iex-|Pk=|~oj{FjDUS>|8-qF0Tz#y9!3d-G6DY($fd!s7n zO%F}f52}Ye-B+V%VG(XC$>}20adXO+xL@2H{A^ey@73j7>KeaXaR)R>6`p8@>hVl7 zo^027+9p9U$3fasaG|oQ@gwS6ujz}yXeBIuU9V@e^*XHHf<5V=!#s0UWcA=u#5J=5 zUJ{qIaNnOjA6o?mw2*7xIYBeci*a5TGNufwn~!Urxw+Zdz~-5MgUb}Ua$UKuT))QU z9KZZpKd*(xvrekxeDog>;%yV~`I$ll@pq{FUs`W&sR&M?f3ok~aMz7qxvpGSt}EBM zTs;his>oI9wBFny)W>@BA72UH;kq7#dR Date: Fri, 5 Jul 2024 16:52:26 +0530 Subject: [PATCH 3/7] content changes for pr comments --- kafka/content.md | 50 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/kafka/content.md b/kafka/content.md index e0dd40167fdd..8494ac953ccf 100644 --- a/kafka/content.md +++ b/kafka/content.md @@ -2,7 +2,7 @@ Apache Kafka is an open-source event streaming platform used to collect, process, store, and integrate data at scale in real time. It powers numerous use cases including stream processing, data integration, and pub/sub messaging. -Kafka was originally developed at LinkedIn, was open sourced in 2011, and became an Apache Software Foundation project in 2012. It is used by thousands of organizations globally to power mission-critical real-time applications, from stock exchanges, to e-commerce applications, to IoT monitoring & analytics, to name a few. +Kafka was originally developed at LinkedIn, was open sourced in 2011, and became an Apache Software Foundation project in 2012. It is used by thousands of organizations globally to power mission-critical real-time applications, from stock exchanges, to e-commerce applications, to IoT monitoring & analytics, to name a few. %%LOGO%% @@ -10,31 +10,35 @@ Kafka was originally developed at LinkedIn, was open sourced in 2011, and became Start a Kafka broker: -```noformat +```console docker run -d --name broker kafka:latest ``` Open a shell in the broker container: -```noformat +```console docker exec --workdir /opt/kafka/bin/ -it broker sh ``` A *topic* is a logical grouping of events in Kafka. From inside the container, create a topic called `test-topic`: -```noformat +```console ./kafka-topics.sh --bootstrap-server localhost:9092 --create --topic test-topic ``` Write two string events into the `test-topic` topic using the console producer that ships with Kafka: +```console ./kafka-console-producer.sh --bootstrap-server localhost:9092 --topic test-topic +``` This command will wait for input at a `>` prompt. Enter `hello`, press `Enter`, then `world`, and press `Enter again`. Enter `Ctrl+C` to exit the console producer. Now read the events in the `test-topic` topic from the beginning of the log: +```console ./kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test-topic --from-beginning +``` You will see the two strings that you previously produced: @@ -45,14 +49,17 @@ The consumer will continue to run until you exit out of it by entering `Ctrl+C`. When you are finished, stop and remove the container by running the following command on your host machine: +```console docker rm -f broker +``` ## Overriding the default broker configuration -Apache Kafka supports a broad set of broker configurations that you may override via environment variables. The environment variables must begin with `KAFKA_`, and any dots in broker configurations should be specified as underscores in the corresponding environment variable. For example, to set the default number of partitions in topics, [`num.partitions`](https://kafka.apache.org/documentation/#brokerconfigs_num.partitions), set the environment variable `KAFKA_NUM_PARTITIONS`. See [here](https://github.com/apache/kafka/blob/trunk/docker/examples/README.md) for more information on overriding broker configuration in Docker. +Apache Kafka supports a broad set of broker configurations that you may override via environment variables. The environment variables must begin with `KAFKA_`, and any dots in broker configurations should be specified as underscores in the corresponding environment variable. For example, to set the default number of partitions in topics, [`num.partitions`](https://kafka.apache.org/documentation/#brokerconfigs_num.partitions), set the environment variable `KAFKA_NUM_PARTITIONS`. See the [Kafka Docker Image Usage Guide](https://github.com/apache/kafka/blob/trunk/docker/examples/README.md) for more information on overriding broker configuration in Docker. -It's important to note that, if you are overriding *any* configuration, then *none* of the default configurations will be used. For example, to run Kafka in KRaft [combined mode](https://kafka.apache.org/documentation/#kraft_role) (meaning that the broker handling client requests and the controller handling cluster coordination both run in the same container) and set the default number of topic partitions to 3 instead of the default 1, we would specify `KAFKA_NUM_PARTITIONS` in addition to other required configurations: +It's important to note that if you are overriding *any* configuration, then *none* of the default configurations will be used. For example, to run Kafka in KRaft [combined mode](https://kafka.apache.org/documentation/#kraft_role) (meaning that the broker handling client requests and the controller handling cluster coordination both run in the same container) and set the default number of topic partitions to 3 instead of the default 1, we would specify `KAFKA_NUM_PARTITIONS` in addition to other required configurations: +```console docker run -d \ --name broker \ -e KAFKA_NODE_ID=1 \ @@ -68,10 +75,13 @@ It's important to note that, if you are overriding *any* configuration, then *no -e KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS=0 \ -e KAFKA_NUM_PARTITIONS=3 \ kafka:latest +``` Specifying this many environment variables on the command line gets cumbersome. It's simpler to instead use [Docker Compose](https://docs.docker.com/compose/) to specify and manage Kafka in Docker. Depending on how you installed Docker, you may already have Docker Compose. You can verify that it's available by checking if this command succeeds, and refer to the Docker Compose installation documentation [here](https://docs.docker.com/compose/install/) if it doesn't: +```console docker compose version +``` To run Kafka with Docker Compose and override the default number of topic partitions to be 3, first copy the following into a file named `docker-compose.yml`: @@ -97,13 +107,17 @@ services: Now, from the directory containing this file, bring Kafka up in detached mode so that the containers run in the background: +```console docker compose up -d +``` The above [quick start](#quick-start) steps will work if you'd like to test topic creation and producing / consuming messages. When you are finished, stop and remove the container by running the following command on your host machine from the directory containing the `docker-compose.yml` file: +```console docker compose down +``` ## External clients @@ -111,12 +125,16 @@ The examples up to this point run Kafka client commands from within Docker. In o First, map the port that Kafka listens on to the same port on your host machine, either by passing `-p 9092:9092` to the `docker run` command: +```console docker run -d -p 9092:9092 --name broker kafka:latest +``` Or, if using Docker Compose, add the port mapping to the `broker` container spec: +```yaml ports: - 9092:9092 +``` Second, download and unzip the [latest Kafka release](https://kafka.apache.org/documentation/#quickstart_download). The console producer and consumer CLI tools are included in the unzipped distribution's `bin` directory. The above [quick start](#quick-start) steps will work from your host machine; it's just that `localhost` refers to your host machine as opposed to the within-container `localhost`. @@ -234,31 +252,49 @@ services: Start the containers from the directory containing the `docker-compose.yml` file: +```console docker compose up -d +``` Now, the following commands will work to produce and consume from within the Docker network. First, open a shell on any of the nodes: +```console docker exec --workdir /opt/kafka/bin/ -it broker-1 sh +``` Now run these commands in the container shell to create a topic, produce to it, and consume from it: +```console ./kafka-topics.sh --bootstrap-server broker-1:19092,broker-2:19092,broker-3:19092 --create --topic test-topic +``` +```console ./kafka-console-consumer.sh --bootstrap-server broker-1:19092,broker-2:19092,broker-3:19092 --topic test-topic --from-beginning +``` +```console ./kafka-console-producer.sh --bootstrap-server broker-1:19092,broker-2:19092,broker-3:19092 --topic test-topic +``` Alternatively, you can run the client programs from your host machine by navigating to your Kafka distribution's `bin` directory and running: +```console ./kafka-topics.sh --bootstrap-server localhost:29092,localhost:39092,localhost:49092 --create --topic test-topic2 - +``` + +```console ./kafka-console-producer.sh --bootstrap-server localhost:29092,localhost:39092,localhost:49092 --topic test-topic2 +``` +```console ./kafka-console-consumer.sh --bootstrap-server localhost:29092,localhost:39092,localhost:49092 --topic test-topic2 --from-beginning +``` When you are finished, stop and remove the Kafka deployment by running the following command on your host machine from the directory containing the `docker-compose.yml` file: +```console docker compose down +``` ## Additional resources From 5df0d0bd4ba4a1399c17e7d089cbd8f0e74377f6 Mon Sep 17 00:00:00 2001 From: KrishVora01 Date: Fri, 5 Jul 2024 17:11:58 +0530 Subject: [PATCH 4/7] PR markdown fix --- kafka/content.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kafka/content.md b/kafka/content.md index 8494ac953ccf..d051bd8389fc 100644 --- a/kafka/content.md +++ b/kafka/content.md @@ -267,11 +267,11 @@ Now run these commands in the container shell to create a topic, produce to it, ```console ./kafka-topics.sh --bootstrap-server broker-1:19092,broker-2:19092,broker-3:19092 --create --topic test-topic ``` - + ```console ./kafka-console-consumer.sh --bootstrap-server broker-1:19092,broker-2:19092,broker-3:19092 --topic test-topic --from-beginning ``` - + ```console ./kafka-console-producer.sh --bootstrap-server broker-1:19092,broker-2:19092,broker-3:19092 --topic test-topic ``` @@ -285,7 +285,7 @@ Alternatively, you can run the client programs from your host machine by navigat ```console ./kafka-console-producer.sh --bootstrap-server localhost:29092,localhost:39092,localhost:49092 --topic test-topic2 ``` - + ```console ./kafka-console-consumer.sh --bootstrap-server localhost:29092,localhost:39092,localhost:49092 --topic test-topic2 --from-beginning ``` From 2c4070085540e6a5aec3e4b273634bbed644af6f Mon Sep 17 00:00:00 2001 From: KrishVora01 Date: Fri, 5 Jul 2024 17:18:38 +0530 Subject: [PATCH 5/7] PR markdown fix yaml formatting --- kafka/content.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kafka/content.md b/kafka/content.md index d051bd8389fc..d116cfdebe82 100644 --- a/kafka/content.md +++ b/kafka/content.md @@ -132,8 +132,8 @@ First, map the port that Kafka listens on to the same port on your host machine, Or, if using Docker Compose, add the port mapping to the `broker` container spec: ```yaml - ports: - - 9092:9092 +ports: + - 9092:9092 ``` Second, download and unzip the [latest Kafka release](https://kafka.apache.org/documentation/#quickstart_download). The console producer and consumer CLI tools are included in the unzipped distribution's `bin` directory. The above [quick start](#quick-start) steps will work from your host machine; it's just that `localhost` refers to your host machine as opposed to the within-container `localhost`. From 4aad36c2b99c1c0e17882891ee579a6656838e40 Mon Sep 17 00:00:00 2001 From: KrishVora01 Date: Mon, 8 Jul 2024 20:12:18 +0530 Subject: [PATCH 6/7] PR comments fix --- kafka/content.md | 64 ++++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/kafka/content.md b/kafka/content.md index d116cfdebe82..65d14ae94277 100644 --- a/kafka/content.md +++ b/kafka/content.md @@ -29,15 +29,15 @@ A *topic* is a logical grouping of events in Kafka. From inside the container, c Write two string events into the `test-topic` topic using the console producer that ships with Kafka: ```console - ./kafka-console-producer.sh --bootstrap-server localhost:9092 --topic test-topic +./kafka-console-producer.sh --bootstrap-server localhost:9092 --topic test-topic ``` -This command will wait for input at a `>` prompt. Enter `hello`, press `Enter`, then `world`, and press `Enter again`. Enter `Ctrl+C` to exit the console producer. +This command will wait for input at a `>` prompt. Enter `hello`, press `Enter`, then `world`, and press `Enter` again. Enter `Ctrl+C` to exit the console producer. Now read the events in the `test-topic` topic from the beginning of the log: ```console - ./kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test-topic --from-beginning +./kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test-topic --from-beginning ``` You will see the two strings that you previously produced: @@ -50,7 +50,7 @@ The consumer will continue to run until you exit out of it by entering `Ctrl+C`. When you are finished, stop and remove the container by running the following command on your host machine: ```console - docker rm -f broker +docker rm -f broker ``` ## Overriding the default broker configuration @@ -60,27 +60,27 @@ Apache Kafka supports a broad set of broker configurations that you may override It's important to note that if you are overriding *any* configuration, then *none* of the default configurations will be used. For example, to run Kafka in KRaft [combined mode](https://kafka.apache.org/documentation/#kraft_role) (meaning that the broker handling client requests and the controller handling cluster coordination both run in the same container) and set the default number of topic partitions to 3 instead of the default 1, we would specify `KAFKA_NUM_PARTITIONS` in addition to other required configurations: ```console - docker run -d \ - --name broker \ - -e KAFKA_NODE_ID=1 \ - -e KAFKA_PROCESS_ROLES=broker,controller \ - -e KAFKA_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093 \ - -e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://localhost:9092 \ - -e KAFKA_CONTROLLER_LISTENER_NAMES=CONTROLLER \ - -e KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT \ - -e KAFKA_CONTROLLER_QUORUM_VOTERS=1@localhost:9093 \ - -e KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 \ - -e KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR=1 \ - -e KAFKA_TRANSACTION_STATE_LOG_MIN_ISR=1 \ - -e KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS=0 \ - -e KAFKA_NUM_PARTITIONS=3 \ - kafka:latest +docker run -d \ + --name broker \ + -e KAFKA_NODE_ID=1 \ + -e KAFKA_PROCESS_ROLES=broker,controller \ + -e KAFKA_LISTENERS=PLAINTEXT://:9092,CONTROLLER://:9093 \ + -e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://localhost:9092 \ + -e KAFKA_CONTROLLER_LISTENER_NAMES=CONTROLLER \ + -e KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT \ + -e KAFKA_CONTROLLER_QUORUM_VOTERS=1@localhost:9093 \ + -e KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 \ + -e KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR=1 \ + -e KAFKA_TRANSACTION_STATE_LOG_MIN_ISR=1 \ + -e KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS=0 \ + -e KAFKA_NUM_PARTITIONS=3 \ + kafka:latest ``` Specifying this many environment variables on the command line gets cumbersome. It's simpler to instead use [Docker Compose](https://docs.docker.com/compose/) to specify and manage Kafka in Docker. Depending on how you installed Docker, you may already have Docker Compose. You can verify that it's available by checking if this command succeeds, and refer to the Docker Compose installation documentation [here](https://docs.docker.com/compose/install/) if it doesn't: ```console - docker compose version +docker compose version ``` To run Kafka with Docker Compose and override the default number of topic partitions to be 3, first copy the following into a file named `docker-compose.yml`: @@ -108,7 +108,7 @@ services: Now, from the directory containing this file, bring Kafka up in detached mode so that the containers run in the background: ```console - docker compose up -d +docker compose up -d ``` The above [quick start](#quick-start) steps will work if you'd like to test topic creation and producing / consuming messages. @@ -116,7 +116,7 @@ The above [quick start](#quick-start) steps will work if you'd like to test topi When you are finished, stop and remove the container by running the following command on your host machine from the directory containing the `docker-compose.yml` file: ```console - docker compose down +docker compose down ``` ## External clients @@ -126,7 +126,7 @@ The examples up to this point run Kafka client commands from within Docker. In o First, map the port that Kafka listens on to the same port on your host machine, either by passing `-p 9092:9092` to the `docker run` command: ```console - docker run -d -p 9092:9092 --name broker kafka:latest +docker run -d -p 9092:9092 --name broker kafka:latest ``` Or, if using Docker Compose, add the port mapping to the `broker` container spec: @@ -253,47 +253,47 @@ services: Start the containers from the directory containing the `docker-compose.yml` file: ```console - docker compose up -d +docker compose up -d ``` Now, the following commands will work to produce and consume from within the Docker network. First, open a shell on any of the nodes: ```console - docker exec --workdir /opt/kafka/bin/ -it broker-1 sh +docker exec --workdir /opt/kafka/bin/ -it broker-1 sh ``` Now run these commands in the container shell to create a topic, produce to it, and consume from it: ```console - ./kafka-topics.sh --bootstrap-server broker-1:19092,broker-2:19092,broker-3:19092 --create --topic test-topic +./kafka-topics.sh --bootstrap-server broker-1:19092,broker-2:19092,broker-3:19092 --create --topic test-topic ``` ```console - ./kafka-console-consumer.sh --bootstrap-server broker-1:19092,broker-2:19092,broker-3:19092 --topic test-topic --from-beginning +./kafka-console-consumer.sh --bootstrap-server broker-1:19092,broker-2:19092,broker-3:19092 --topic test-topic --from-beginning ``` ```console - ./kafka-console-producer.sh --bootstrap-server broker-1:19092,broker-2:19092,broker-3:19092 --topic test-topic +./kafka-console-producer.sh --bootstrap-server broker-1:19092,broker-2:19092,broker-3:19092 --topic test-topic ``` Alternatively, you can run the client programs from your host machine by navigating to your Kafka distribution's `bin` directory and running: ```console - ./kafka-topics.sh --bootstrap-server localhost:29092,localhost:39092,localhost:49092 --create --topic test-topic2 +./kafka-topics.sh --bootstrap-server localhost:29092,localhost:39092,localhost:49092 --create --topic test-topic2 ``` ```console - ./kafka-console-producer.sh --bootstrap-server localhost:29092,localhost:39092,localhost:49092 --topic test-topic2 +./kafka-console-producer.sh --bootstrap-server localhost:29092,localhost:39092,localhost:49092 --topic test-topic2 ``` ```console - ./kafka-console-consumer.sh --bootstrap-server localhost:29092,localhost:39092,localhost:49092 --topic test-topic2 --from-beginning +./kafka-console-consumer.sh --bootstrap-server localhost:29092,localhost:39092,localhost:49092 --topic test-topic2 --from-beginning ``` When you are finished, stop and remove the Kafka deployment by running the following command on your host machine from the directory containing the `docker-compose.yml` file: ```console - docker compose down +docker compose down ``` ## Additional resources From b62a31171d05238d2ce235d345e49e21a0cfdb89 Mon Sep 17 00:00:00 2001 From: KrishVora2912 Date: Thu, 1 Aug 2024 19:22:01 +0530 Subject: [PATCH 7/7] comma fix --- kafka/content.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kafka/content.md b/kafka/content.md index 65d14ae94277..39df80810a42 100644 --- a/kafka/content.md +++ b/kafka/content.md @@ -140,14 +140,14 @@ Second, download and unzip the [latest Kafka release](https://kafka.apache.org/d ## Multiple nodes -In this section you will explore a more realistic Kafka deployment consisting of three brokers and three controllers running in their own containers (i.e., KRaft [isolated mode](https://kafka.apache.org/documentation/#kraft_role)). We'll also configure it such that we can connect to Kafka from within Docker or from the host machine. Bear in mind that doing this exercise in Docker is convenient to learn about multi-broker configurations and the Kafka protocol, but this Docker Compose example isn't appropriate for a production deployment. +In this section, you will explore a more realistic Kafka deployment consisting of three brokers and three controllers running in their own containers (i.e., KRaft [isolated mode](https://kafka.apache.org/documentation/#kraft_role)). We'll also configure it such that we can connect to Kafka from within Docker or from the host machine. Bear in mind that doing this exercise in Docker is convenient to learn about multi-broker configurations and the Kafka protocol, but this Docker Compose example isn't appropriate for a production deployment. Compared to a single-node Kafka deployment, there is a bit more to do on the configuration front: 1. `KAFKA_PROCESS_ROLES` is either `broker` or `controller` depending on the container's role, not the KRaft combined mode value `broker,controller` 2. `KAFKA_CONTROLLER_QUORUM_VOTERS` is a comma-separated list of the three controllers 3. We accept the default values for `KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR` (3), `KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR` (3), and `KAFKA_TRANSACTION_STATE_LOG_MIN_ISR` (2) now that there are enough brokers to support the default settings, so we don't specify these configurations (a partition's replicas must reside on different brokers for fault tolerance) -4. Brokers have two listeners: one for communicating within the Docker network, and one for connecting from the host machine. Because Kafka clients connect directly to brokers after initially connecting (bootstrapping), one listener uses the container name because it is a resolvable name for all containers on the Docker network. This listener is also used for inter-broker communication. The second listener uses `localhost` on a unique port that gets mapped on the host (29092 for `broker-1`, 39092 for `broker-2`, and 49092 for `broker-3`). With one node, a single listener on `localhost` works because the `localhost` name is conveniently correct from within the container and from the host machine, but this doesn't apply in a multi-node setup. +4. Brokers have two listeners: one for communicating within the Docker network and one for connecting from the host machine. Because Kafka clients connect directly to brokers after initially connecting (bootstrapping), one listener uses the container name because it is a resolvable name for all containers on the Docker network. This listener is also used for inter-broker communication. The second listener uses `localhost` on a unique port that gets mapped on the host (29092 for `broker-1`, 39092 for `broker-2`, and 49092 for `broker-3`). With one node, a single listener on `localhost` works because the `localhost` name is conveniently correct from within the container and from the host machine, but this doesn't apply in a multi-node setup. To deploy this six-node setup on your machine, copy the following into a file named `docker-compose.yml`: