1. Docker에서 Kafka 연결 문제와 해결 방법
Docker로 Kafka를 실행할 때, **외부 애플리케이션(호스트 머신)**에서 Kafka에 연결하려면 적절한 네트워크 설정이 필요합니다. 기본적으로 Docker 컨테이너는 자체 네트워크 브리지를 사용하므로, 외부에서 직접적으로 접근할 수 없습니다.
이 문서에서는 Docker에서 Kafka에 연결하는 방법을 단계별로 설명합니다.
2. 문제 상황
Kafka를 다음과 같이 Docker 컨테이너에서 실행한다고 가정합니다:
2.1 Kafka 및 Zookeeper 설정 예제
# Zookeeper 실행
docker run -d \
-p 2181:2181 \
--net=confluent \
--name=zookeeper \
-e ZOOKEEPER_CLIENT_PORT=2181 \
confluentinc/cp-zookeeper:4.1.0
# Kafka 실행
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에 연결하려고 할 때, 다음과 같은 에러가 발생할 수 있습니다:
java.io.IOException: Can't resolve address: kafka:9092
3. 문제 원인
3.1 Docker 네트워크 문제
컨테이너 내부에서는 kafka:9092
로 접근이 가능하지만, 호스트 머신(외부 클라이언트)에서는 이 도메인을 해석할 수 없습니다. 이는 Kafka가 호스트 네트워크 대신 Docker 브리지 네트워크를 사용하기 때문입니다.
3.2 KAFKA_ADVERTISED_LISTENERS
설정
Kafka는 클라이언트와 통신할 때 **광고된 리스너 주소(advertised.listeners
)**를 참조합니다. 기본 설정값이 컨테이너 내부 주소인 **kafka:9092
**로 되어 있으므로, 외부 클라이언트는 연결할 수 없습니다.
4. 해결 방법
Kafka가 외부와 통신할 수 있도록 Docker 컨테이너의 네트워크 설정을 조정해야 합니다.
4.1 KAFKA_ADVERTISED_LISTENERS
를 업데이트
컨테이너 외부에서 Kafka에 접근하려면 외부 호스트 주소를 포함한 리스너 설정이 필요합니다. 이를 위해 두 가지 리스너를 설정합니다:
- 내부 Docker 네트워크를 위한
PLAINTEXT
리스너. - 호스트 머신에서 접근 가능한
PLAINTEXT_HOST
리스너.
명령어 예제
docker run -d \
--net=confluent \
--name=kafka \
-p 9092:9092 -p 29092:29092 \
-e KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181 \
-e KAFKA_LISTENER_SECURITY_PROTOCOL_MAP=PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT \
-e KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092 \
-e KAFKA_LISTENERS=PLAINTEXT://0.0.0.0:9092,PLAINTEXT_HOST://0.0.0.0:29092 \
-e KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 \
confluentinc/cp-kafka:4.1.0
4.2 클라이언트 연결
외부 클라이언트는 PLAINTEXT_HOST
리스너를 통해 연결할 수 있습니다.
Java 코드 예제
Properties props = new Properties();
props.put("bootstrap.servers", "localhost:29092"); // 외부 호스트와 포트
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();
5. 자주 발생하는 문제와 해결법
5.1 Can't resolve address: kafka:9092
- 원인: 클라이언트가 Docker 내부 주소(
kafka:9092
)를 해석하지 못함. - 해결 방법:
KAFKA_ADVERTISED_LISTENERS
에localhost:29092
를 추가.
5.2 클라이언트 연결 시간 초과
- 원인:
KAFKA_LISTENERS
설정이 잘못됨. - 해결 방법: 내부와 외부 리스너 모두 정확히 설정되었는지 확인.
6. 결론
Docker에서 Kafka에 연결하려면 다음을 명심하세요:
- 적절한 리스너 설정: 내부(Docker 네트워크)와 외부(호스트 머신) 모두를 지원해야 함.
- 포트 매핑 확인: Docker 컨테이너와 호스트 머신 간의 포트가 정확히 매핑되어야 함.
- 클라이언트 코드 수정: 외부 리스너 주소를
bootstrap.servers
에 추가.
이 가이드를 따르면 Docker에서 Kafka에 성공적으로 연결할 수 있습니다. 적절한 네트워크 설정으로 Kafka를 손쉽게 운영하세요!