[英]Connect to Kafka running in Docker
我在本地機器上設置了一個單節點 Kafka Docker 容器,就像Confluent 文檔中描述的那樣(步驟 2-3)。
此外,我還暴露了 Zookeeper 的 2181 端口和 Kafka 的 9092 端口,這樣我就可以從本地機器上運行的客戶端連接到它們:
$ docker run -d \
-p 2181:2181 \
--net=confluent \
--name=zookeeper \
-e ZOOKEEPER_CLIENT_PORT=2181 \
confluentinc/cp-zookeeper:4.1.0
$ docker run -d \
--net=confluent \
--name=kafka \
-p 9092:9092 \
-e KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181 \
-e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092 \
-e KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 \
confluentinc/cp-kafka:4.1.0
問題:當我嘗試從主機連接到 Kafka 時,連接失敗,因為它can't resolve address: kafka:9092
。
這是我的 Java 代碼:
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:9092");
props.put("client.id", "KafkaExampleProducer");
props.put("key.serializer", LongSerializer.class.getName());
props.put("value.serializer", StringSerializer.class.getName());
KafkaProducer<Long, String> producer = new KafkaProducer<>(props);
ProducerRecord<Long, String> record = new ProducerRecord<>("foo", 1L, "Test 1");
producer.send(record).get();
producer.flush();
例外:
java.io.IOException: Can't resolve address: kafka:9092
at org.apache.kafka.common.network.Selector.doConnect(Selector.java:235) ~[kafka-clients-2.0.0.jar:na]
at org.apache.kafka.common.network.Selector.connect(Selector.java:214) ~[kafka-clients-2.0.0.jar:na]
at org.apache.kafka.clients.NetworkClient.initiateConnect(NetworkClient.java:864) [kafka-clients-2.0.0.jar:na]
at org.apache.kafka.clients.NetworkClient.ready(NetworkClient.java:265) [kafka-clients-2.0.0.jar:na]
at org.apache.kafka.clients.producer.internals.Sender.sendProducerData(Sender.java:266) [kafka-clients-2.0.0.jar:na]
at org.apache.kafka.clients.producer.internals.Sender.run(Sender.java:238) [kafka-clients-2.0.0.jar:na]
at org.apache.kafka.clients.producer.internals.Sender.run(Sender.java:176) [kafka-clients-2.0.0.jar:na]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_144]
Caused by: java.nio.channels.UnresolvedAddressException: null
at sun.nio.ch.Net.checkAddress(Net.java:101) ~[na:1.8.0_144]
at sun.nio.ch.SocketChannelImpl.connect(SocketChannelImpl.java:622) ~[na:1.8.0_144]
at org.apache.kafka.common.network.Selector.doConnect(Selector.java:233) ~[kafka-clients-2.0.0.jar:na]
... 7 common frames omitted
問題:如何連接運行在Docker的Kafka? 我的代碼是從主機運行的,而不是 Docker。
注意:我知道理論上我可以嘗試使用 DNS 設置和/etc/hosts
但這是一種解決方法 - 它不應該那樣。
這里也有類似的問題,但是它是基於ches/kafka
圖像的。 我使用不一樣的基於confluentinc
的圖像。
tl;dr - 從容器到主機的簡單端口轉發將不起作用,並且不應修改任何主機文件。 您想連接到哪個確切的 IP/主機名 + 端口? 確保該值在代理上設置為
advertised.listeners
。 確保作為bootstrap.servers
一部分列出的地址和服務器實際上是可解析的(ping
IP/主機名,使用netcat
檢查端口...)
要驗證端口在主機上是否正確映射,請確保
docker ps
顯示 kafka 容器是從0.0.0.0:<host_port> -> <advertised_listener_port>/tcp
映射的。 如果嘗試從 Docker 網絡外部運行客戶端,則端口必須匹配。
以下答案使用
confluentinc
docker 圖像來解決所提出的問題,而不是wurstmeister/kafka
。 更具體地說,盡管后者是最受歡迎的 Kafka docker 圖像之一,但它的維護並不好。
以下部分嘗試匯總使用另一個圖像所需的所有詳細信息。 對於其他常用的 Kafka 映像,它們都是在容器中運行的Apache Kafka 。
您只依賴於它的配置方式。 以及哪些變量使它如此。
wurstmeister/kafka
請參閱他們關於偵聽器配置的 README 部分,另 請閱讀他們的 Connectivity wiki 。
bitnami/kafka
如果你想要一個小容器,試試這些。 圖像比 Confluent 小得多,並且比
wurstmeister
維護得更好。 請參閱他們的 README以了解偵聽器配置。
debezium/kafka
此處提到了有關它的文檔。
注意:不推薦使用廣告主機和端口設置。 廣告聽眾涵蓋兩者。 與 Confluent 容器類似,Debezium 可以使用
KAFKA_
前綴代理設置來更新其屬性。
其他
spotify/kafka
已棄用且已過時。
fast-data-dev
或lensesio/box
非常適合多合一的解決方案,但如果你只想要 Kafka,那就太臃腫了
您自己的Dockerfile
- 為什么? 這些其他的東西不完整嗎? 從拉取請求開始,而不是從頭開始。
如需補充閱讀、功能齊全的docker-compose
和網絡圖,請參閱@rmoff 的此博客
Confluent 快速入門 (Docker) 文檔假定所有生產和消費請求都在 Docker 網絡內。
您可以通過在其自己的容器中運行您的 Kafka 客戶端代碼來解決連接到kafka:9092
的問題,因為它使用 Docker 網橋,但否則您需要添加更多環境變量以在外部公開容器,同時仍然具有它在 Docker 網絡中工作。
首先添加 PLAINTEXT_HOST PLAINTEXT_HOST:PLAINTEXT
PLAINTEXT 的協議映射,它將 map 偵聽器協議映射到 Kafka 協議
鍵: KAFKA_LISTENER_SECURITY_PROTOCOL_MAP
值: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
然后在不同的端口上設置兩個通告的偵聽器。 (這里的kafka
指的是 docker 容器名稱;它也可能被命名為broker
,因此請仔細檢查您的服務 + 主機名)。 注意協議匹配上面映射的右側值
鍵: KAFKA_ADVERTISED_LISTENERS
值: PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092
運行容器時,添加-p 29092:29092
用於主機端口映射。
(以上設置)
如果仍然無法正常工作,可以將KAFKA_LISTENERS
設置為包含<PROTOCOL>://0.0.0.0:<PORT>
,其中兩個選項都與廣告設置和 Docker 轉發的端口匹配
如您所料,廣告 localhost 和相關端口將讓您連接到容器外部。
換句話說,當在 Docker 網絡之外運行任何 Kafka 客戶端時(包括您可能已經在本地安裝的 CLI 工具),使用localhost:29092
作為引導服務器,使用localhost:2181
作為 Zookeeper(需要 Docker 端口轉發)
如果嘗試從外部服務器連接,您需要公布主機的外部主機名/ip以及/代替 localhost 。
簡單地使用端口轉發來通告 localhost 是行不通的,因為 Kafka 協議仍將繼續通告您已配置的偵聽器。
如果不在同一個本地網絡中,此設置需要 Docker 端口轉發和路由器端口轉發(以及防火牆/安全組更改),例如,您的容器在雲中運行並且您希望從本地計算機與其交互。
這是最不容易出錯的配置; 您可以直接使用 DNS 服務名稱。
在 Docker 網絡中運行應用程序時,對引導服務器使用kafka:9092
(參見上面公布的PLAINTEXT
偵聽器配置),對 Zookeeper 使用zookeeper:2181
,就像任何其他 Docker 服務通信一樣(不需要任何端口轉發)
如果使用單獨docker run
命令,或者 Compose 文件,則需要手動定義共享network
有關完整的 Confluent 堆棧或單個代理的更多最小堆棧,請參閱示例 Compose 文件。
從 Docker (ksqlDB) 連接到主機上的 Kafka
對於任何對Kubernetes部署感興趣的人: https://operatorhub.io/?keyword=Kafka
When you first connect to a kafka node, it will give you back all the kafka node and the url where to connect. Then your application will try to connect to every kafka directly.
Issue is always what is the kafka will give you as url ? It's why there is the KAFKA_ADVERTISED_LISTENERS
which will be used by kafka to tell the world how it can be accessed.
Now for your use-case, there is multiple small stuff to think about:
Let say you set plaintext://kafka:9092
kafka
that is resolvable through the docker network.kafka
name cannot be resolved.==> To fix this, you need to have a specific DNS server like a service discovery one, but it is big trouble for small stuff. Or you set manually the kafka
name to the container ip in each /etc/hosts
If you set plaintext://localhost:9092
==> If you have this and wish to use a kafka client in another container, one way to fix this is to share the network for both container (same ip)
Last option : set an IP in the name: plaintext://x.y.z.a:9092
( kafka advertised url cannot be 0.0.0.0 as stated in the doc https://kafka.apache.org/documentation/#brokerconfigs_advertised.listeners )
This will be ok for everybody... BUT how can you get the x.y.z.a name ?
The only way is to hardcode this ip when you launch the container: docker run .... --net confluent --ip 10.x.y.z ...
. Note that you need to adapt the ip to one valid ip in the confluent
subnet.
在動物園管理員之前
卡夫卡之后
在 kafka 消費者和生產者配置中
@Bean public ProducerFactory<String, String> producerFactory() { Map<String, Object> configProps = new HashMap<>(); configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.8.128:9092"); configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class); configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class); return new DefaultKafkaProducerFactory<>(configProps); } @Bean public ConsumerFactory<String, String> consumerFactory() { Map<String, Object> props = new HashMap<>(); props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.8.128:9092"); props.put(ConsumerConfig.GROUP_ID_CONFIG, "group_id"); props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); return new DefaultKafkaConsumerFactory<>(props); }
我按照這些規定運行我的項目。 祝你好運伙計。
我與 Kafka/Zookeeper/Schema-Registry 在 Mac M1 上的碼頭和客戶端上分享我的 Mac M1 經驗。 此設置要求必須從 Mac 使用端口 9092,而不是從 docker,因此應交換端口
這邊走
Key: KAFKA_ADVERTISED_LISTENERS Value: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092
加上端口轉發:
ports - "9092:9092"
最后,再次,對於我的設置,我必須以這種方式設置 listeners 鍵
Key: KAFKA_LISTENERS Value: PLAINTEXT://0.0.0.0:29092,PLAINTEXT_HOST://0.0.0.0:9092
解決此問題的最簡單方法是使用 -h 選項向您的代理添加自定義主機名
docker run -d \
--net=confluent \
--name=kafka \
-h broker-1 \
-p 9092:9092 \
-e KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181 \
-e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092 \
-e KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 \
confluentinc/cp-kafka:4.1.0
並編輯您的 /etc/hosts
127.0.0.1 broker-1
並使用:
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "broker-1:9092");
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.