java - Conéctate a Kafka ejecutando en Docker desde una máquina local
apache-kafka confluent (2)
Configuré el Despliegue de Kafka Básico de Nodo Único utilizando la ventana acoplable en mi máquina local, como se describe en la documentación de Confluente Kafka (pasos 2-3).
Además, también expuse el puerto 2181 del zookeeper y el puerto 9092 de kafka para poder conectarme desde el cliente Java que se ejecuta en la máquina local:
$ 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
Problema: cuando intento conectarme a kafka desde la máquina host, la conexión falla porque no puede resolver la dirección: kafka: 9092.
Aquí está mi código de 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();
La excepción:
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
Pregunta: ¿Cómo conectarse a kafka que se ejecuta en Docker desde la máquina host?
Nota: Sé que en teoría podría jugar con la configuración de DNS y
/etc/hosts
pero es una solución, no debería ser así.
También hay una pregunta similar
here
, sin embargo, se basa en la imagen
ches/kafka
.
Uso una imagen basada en
confluent
que no es lo mismo.
Descargo de responsabilidad : lo siguiente utiliza imágenes de
wurstmeister/kafka
confluentinc
, nowurstmeister/kafka
, aunque hay una configuración similar , no la he probado. Si usas esa imagen, lee su wiki de Conectividad .
debezium/kafka
documentos dedebezium/kafka
en él se mencionan aquí .He intentado las imágenes de
bitnami
, y tengo que trabajar con esta configuraciónAl final del día, todo es lo mismo que Apache Kafka se ejecuta en un contenedor. Sólo dependes de cómo está configurado .
Para leer los diagramas de red y de lectura suplementarios, vea este blog por @rmoff
Ese documento de inicio rápido de Confluent asume que todas las solicitudes de producción y consumo estarán dentro de la red Docker.
Puede solucionar el problema ejecutando su código de cliente Kafka dentro de su propio contenedor, pero de lo contrario deberá agregar algunas más variables de entorno para exponer el contenedor de manera externa, mientras aún funciona en la red Docker.
Primero agregue un mapeo de protocolo de
PLAINTEXT_HOST:PLAINTEXT
que
PLAINTEXT_HOST:PLAINTEXT
el protocolo de escucha a un protocolo Kafka
-e KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
Luego, configure dos escuchas anunciados en diferentes puertos.
(
kafka:9092
aquí se refiere al nombre del contenedor de la
kafka:9092
acoplable).
Observe que los protocolos coinciden con los valores del lado derecho de las asignaciones anteriores
-e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092
Al ejecutar el contenedor, agregue
-p 29092:29092
para la asignación de puertos del host
tl; dr (con los ajustes anteriores)
Cuando ejecute cualquier Cliente Kafka
fuera de
la red de Docker (incluidas las herramientas de CLI que pueda haber instalado localmente), use
localhost:29092
para servidores bootstrap y
localhost:2181
para Zookeeper
Cuando ejecute una aplicación
en la red Docker
, use
kafka:9092
para servidores bootstrap y
zookeeper:2181
para Zookeeper
Vea el ejemplo del archivo Compose para la pila completa de Confluent
Cuando te conectas por primera vez a un nodo kafka, te devolverá todo el nodo kafka y la url donde conectarte. Entonces su aplicación intentará conectarse a cada kafka directamente.
El problema es siempre ¿qué es el kafka que te dará como url?
Es por eso que hay
KAFKA_ADVERTISED_LISTENERS
que serán utilizados por kafka para decirle al mundo cómo se puede acceder.
Ahora para su caso de uso, hay varias cosas pequeñas en las que pensar:
Digamos que configuras
plaintext://kafka:9092
-
Esto está bien si tiene una aplicación en su ventana acoplable que utiliza kafka.
Esta aplicación obtendrá de kafka la URL con
kafka
que se puede resolver a través de la red docker. -
Si intenta conectarse desde su sistema principal o desde otro contenedor que no está en la misma red de conexión, esto fallará, ya que el nombre
kafka
no se puede resolver.
==> Para solucionar esto, necesita tener un servidor DNS específico como un descubrimiento de servicio, pero es un gran problema para cosas pequeñas.
O establece manualmente el nombre
kafka
a la ip del contenedor en cada
/etc/hosts
Si establece
plaintext://localhost:9092
- Esto estará bien en tu sistema si tienes un mapeo de puertos (-p 9092: 9092 al iniciar kafka)
- Esto fallará si realiza la prueba desde una aplicación en un contenedor (la misma red docker o no) (localhost es el contenedor en sí, no el kafka)
==> Si tiene esto y desea utilizar un cliente kafka en otro contenedor, una forma de solucionarlo es compartir la red para ambos contenedores (la misma ip)
Última opción: establezca una IP en el nombre:
plaintext://xyza:9092
Esto estará bien para todos ... PERO, ¿cómo puede obtener el nombre xyza?
La única forma es codificar esta ip cuando
docker run .... --net confluent --ip 10.xyz ...
el contenedor: la
docker run .... --net confluent --ip 10.xyz ...
Tenga en cuenta que necesita adaptar la ip a una ip válida en la subred
confluent
.