簡體   English   中英

連接到運行在 Docker 的 Kafka

[英]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-devlensesio/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用於主機端口映射。


tl;博士

以上設置

如果仍然無法正常工作,可以將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

  • This is OK if you have an application in your docker compose that use kafka. This application will get from kafka the URL with kafka that is resolvable through the docker network.
  • If you try to connect from your main system or from another container which is not in the same docker network this will fail, as the 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

  • This will be ok on your system if you have a port mapping ( -p 9092:9092 when launching kafka)
  • This will fail if you test from an application on a container (same docker network or not) (localhost is the container itself not the kafka one)

==> 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.

在動物園管理員之前

  1. docker 容器運行 --name zookeeper -p 2181:2181 zookeeper

卡夫卡之后

  1. docker container run --name kafka -p 9092:9092 -e KAFKA_ZOOKEEPER_CONNECT=192.168.8.128:2181 -e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://ip_address_of_your_computer_but_not_localhost: 9092 -e KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 confluentinc/cp-kafka

在 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM