首頁  >  文章  >  後端開發  >  連接到在 Docker 中運行的 Kafka

連接到在 Docker 中運行的 Kafka

PHPz
PHPz轉載
2024-02-14 23:42:081011瀏覽

连接到在 Docker 中运行的 Kafka

在當今的軟體開發領域,容器化技術成為了越來越流行的部署方式。而Docker作為最受歡迎的容器化解決方案之一,為開發者提供了便捷的環境隔離和部署方式。對於使用Kafka作為訊息佇列系統的開發者來說,將Kafka與Docker結合起來,可以更靈活和有效率地進行開發和部署。在這篇文章中,php小編西瓜將為大家介紹如何在Docker中運行Kafka,讓您輕鬆享受容器化帶來的​​便利。

問題內容

我在本機電腦上設定了一個單節點 kafka docker 容器,如 confluence 文件所述(步驟 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 時,連線失敗,因為 無法解析位址: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 圖片。我使用基於 confluenceinc 的圖像,這是不一樣的。

解決方法

tl;dr - 從容器到主機的簡單連接埠轉送將不起作用...主機檔案(例如* NIX 系統上的 /etc/hosts )不應修改以解決Kafka 網路問題,因為此解決方案無法移植。

1) 您想要連接到哪個確切的 IP/主機名稱 連接埠?確保該值在代理程式上設定為 advertished.listeners (不是 advertished.host.nameadvertished.port,因為這些已被棄用)。如果您看到諸如 Connection to node -1 (localhost/127.0.0.1:9092) 之類的錯誤,則表示您的應用程式容器嘗試連接到自身。您的應用程式容器是否也在執行 Kafka 代理程式?可能不是。

2) 確保作為 bootstrap.servers 一部分列出的伺服器實際上是可解析的。例如ping IP/主機名,使用netcat 檢查連接埠...如果您的用戶端位於容器中,則需要從容器執行此操作,而不是(僅)從主機執行此操作。如果容器沒有立即崩潰以存取其 shell,請使用 docker exec

3) 如果從主機而不是另一個容器運行進程,要驗證連接埠是否在主機上正確映射,請確保docker ps 顯示kafka 容器是從0.0.0.0 對應的: 50c5a3c9bd6141bda139d1e2f6e9d778 -> cd3356af2f6e059e7bd54cd1ababa980 /tcp.如果嘗試從Docker 網路外部執行用戶端,則連接埠必須符合。兩個容器之間不需要連接埠轉送;使用連結/docker網路

下面的答案使用 confluenceinc docker 映像來解決所提出的問題,不是 wurstmeister/kafka。如果您設定了 KAFKA_ADVERTISED_HOST_NAME 變量,請將其刪除(這是已棄用的屬性)

以下部分嘗試匯總使用其他圖像所需的所有詳細資訊。對於其他常用的 Kafka 映像,都是在容器中執行的 Apache Kafka
您只依賴它的配置方式。以及哪些變數導致了這種情況。

wurstmeister/kafka

自 2023 年 10 月起,DockerHub 中不再存在此內容。無論如何,2022 年後就不再維護了。

請參閱有關監聽器設定的自述文件部分 a>,另外閱讀他們的 Connectivity wiki

bitnami/kafka

如果您想要一個小容器,請嘗試這些。這些映像比 Confluence 小得多,並且比 wurstmeister 維護得更好。 參考他們的監聽器配置的自述文件

debezium/kafka

此處提到了相關文件此處

注意:已棄用已公佈的主機和連接埠設定。廣告聽眾涵蓋了兩者。與 Confluence 容器類似,Debezium 可以使用 KAFKA_ 前綴的代理設定來更新其屬性。

其他

  • ubuntu/kafka 要求您透過Docker 映像參數新增--overrideadvertising.listeners=kafka:9092...我發現它不如環境變數可移植,因此不推薦
  • spotify/kafka 已棄用且過時。
  • fast-data-devlensesio/box 非常適合一體化解決方案,具有架構註冊表、Kafka Connect 等,但如果您想要Kafka,則顯得臃腫。另外,這是一種在一個容器中執行多個服務的 Docker 反模式
  • 您自己的 Dockerfile - 為什麼?這些其他的東西是否不完整?從拉取請求開始,而不是從頭開始。

有關補充閱讀、功能齊全 docker-compose 和網絡圖,請參閱 此部落格作者:@rmoff

#回答

Confluence 快速入門 (Docker) 文件 假設所有生產和消費要求將在 Docker 網路內進行。

您可以透過在自己的容器中執行Kafka 用戶端程式碼(使用Docker 橋接器)來解決連接到kafka:9092 的問題,但否則您需要新增更多環境變數以將容器公開到外部,同時仍然讓它在Docker 網路中運作。

首先新增 PLAINTEXT_HOST:PLAINTEXT 的協定映射,它將偵聽器協定映射到 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 進行主機連接埠映射,並通告 PLAINTEXT_HOST 監聽器。

所以...(使用上述設定

如果仍然不起作用,可以將KAFKA_LISTENERS 設定為包含9625b882931466931ca10eb1a60367b3://0.0.0.0:a3b0c87895079be75e30be94102cc20b,其中兩個選項都與廣告設定和Docker 轉送的連接埠相符

客戶端位於同一台機器上,而不是在容器中

廣告本機主機和關聯的連接埠將允許您在容器外部進行連接,正如您所期望的那樣。

換句話說,當在Docker 網路之外執行任何Kafka 用戶端(包括您可能在本機安裝的CLI 工具)時,請使用localhost:29092 作為引導伺服器,使用 localhost:2181 作為Zookeeper(需要Docker)連接埠轉送)

另一台機器上的客戶端

如果嘗試從外部伺服器連接,您需要公佈主機的外部主機名稱/IP(例如 192.168.x.y以及/取代 localhost #。
簡單地透過連接埠轉送來通告 localhost 是行不通的,因為 Kafka 協定仍將繼續通告您設定的偵聽器。

如果不在同一個本機網路中,此設定需要Docker 連接埠轉送路由器連接埠轉送(以及防火牆/安全性群組變更),例如,您的容器在雲端中運行,並且您想要從本機與其互動。

同一主機上容器中的客戶端(或另一個代理程式)

這是最不容易出錯的設定;您可以直接使用 DNS 服務名稱。

在Docker 網路中執行應用程式時,使用kafka:9092(請參閱上面廣告的PLAINTEXT 偵聽器設定)作為引導伺服器,使用zookeeper:2181 作為Zookeeper,就像任何其他Docker 服務通訊一樣(不不需要任何連接埠轉送)

如果您使用單獨的docker run 命令或Compose 文件,則需要使用compose networks 部分或docker network --create 手動定義共享network

請參閱完整 Confluence 堆疊的範例 Compose 檔案針對單一經紀商的更簡單的

如果使用多個代理,那麼它們需要使用唯一的主機名稱 廣告偵聽器。 查看範例一个>

相關問題

從 Docker (ksqlDB) 連線到主機上的 Kafka

附錄

對於任何對 Kubernetes 部署感興趣的人:

以上是連接到在 Docker 中運行的 Kafka的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:stackoverflow.com。如有侵權,請聯絡admin@php.cn刪除