在當今的軟件開發領域,容器化技術成為了一種越來越流行的部署方式。而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 producer = new kafkaproducer(props); producerrecord 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.name
和 advertished.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 映射的: -> /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-dev
或 lensesio/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
設置為包含 ://0.0.0.0:
,其中兩個選項都與廣告設置和 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 部署感興趣的人:
訪問 Kafka
操作員(推薦):https://www.php.cn/link/61b07251e835d37322b7460d2b88c05b
Helm Artifact 中心:https://artifacthub.io/packages/search ?ts_query_web=kafka&sort=stars&page=1