NodePort 기반 Kafka 외부 접속 구성과 NGINX 연동 전략

Kafka를 Kubernetes 위에서 운영할 때 가장 자주 부딪히는 문제 중 하나는 외부에서 Kafka 브로커에 접근하는 방법입니다. Helm Chart로 클러스터를 구성하는 건 좋은 시작이지만, 클러스터 외부의 Producer나 Consumer가 Kafka와 통신하려면 몇 가지 추가 설정이 필요하죠.

이번 글에서는 Helm Chart 기반 Kafka 환경에서 NodePort를 활용해 외부 접속을 구성하고, NGINX를 통해 이를 안정적으로 라우팅하는 전략을 소개합니다.

1. 왜 외부 접속 구성이 필요한가요?

Kafka는 기본적으로 클러스터 내부 서비스(IP)를 통해 통신하도록 설계되어 있습니다. 그러나 다음과 같은 이유로 외부 접속 구성이 필요합니다:

  • Kafka와 연동하는 외부 애플리케이션이 존재하는 경우
  • 클러스터 외부에서 직접 데이터를 주고받아야 하는 경우
  • 테스트 혹은 로컬 개발환경에서 Kafka를 접근해야 할 경우

이때 선택할 수 있는 대표적인 방식이 NodePort입니다.

2. Kafka values.yaml에 NodePort 설정하기

Helm Chart의 values.yaml에 다음과 같이 설정하면 각 Kafka 브로커에 대해 외부 접근용 포트를 할당할 수 있습니다.

externalAccess:
  enabled: true
  broker:
    service:
      type: NodePort
      nodePorts:
        - 30000
        - 30001
        - 30002

이 설정은 각 Kafka 브로커를 특정 NodePort에 고정하여 외부에서 접근 가능하게 만들어줍니다.

3. NGINX로 외부 트래픽 라우팅하기

NodePort만 열어둔다면 각 브로커의 IP/Port를 클라이언트가 직접 알아야 합니다. 이를 보완하고 로드밸런싱까지 가능하게 하려면 NGINX Stream 모듈을 활용할 수 있습니다.

stream {
  log_format proxy '$remote_addr [$time_local] '
                   '$protocol $status $bytes_sent $bytes_received '
                   '$session_time "$upstream_addr"';

  access_log /etc/nginx/logs/kafka-access.log proxy;
  error_log  /etc/nginx/logs/kafka-error.log;

  upstream kafka_cluster_0 {
      server 192.168.33.101:30000;
  }
  upstream kafka_cluster_1 {
      server 192.168.33.102:30001;
  }
  upstream kafka_cluster_2 {
      server 192.168.33.103:30002;
  }

  server {
      listen 10094;
      proxy_pass kafka_cluster_0;
  }
  server {
      listen 10194;
      proxy_pass kafka_cluster_1;
  }
  server {
      listen 10294;
      proxy_pass kafka_cluster_2;
  }
}
  • 192.168.33.101~103는 각 Kubernetes Node의 IP
  • 30000~30002는 각 브로커가 열어둔 NodePort
  • 10094,10194,10294은 외부 클라이언트가 Kafka에 접속할 포트

이렇게 구성하면 외부에서는 단순히 kafka.mycompany.com:10094 등으로 접근하면 되고, NGINX가 이를 알맞은 브로커로 라우팅해 줍니다.

💡 저자는 HTTP Proxy를 통한 로드밸런싱도 시도했으나, TCP 기반 통신 구조인 Kafka의 특성상 성공적으로 적용하지는 못했습니다. 관련하여 성공적인 사례가 있으신 분들은 댓글로 공유해주시면 감사하겠습니다. 🙏

4. 클라이언트 설정 예시 (Node.js)

Kafkajs 라이브러리를 사용하는 Node.js 클라이언트 예시는 다음과 같습니다:

const { Kafka } = require('kafkajs');

const kafka = new Kafka({
  clientId: 'my-app',
  brokers: ['kafka.mycompany.com:10094'],
  ssl: false, // NGINX가 SSL termination을 하지 않는 경우 false
  connectionTimeout: 10000,
});

const consumer = kafka.consumer({ groupId: 'test-group' });

(async () => {
  await consumer.connect();
  await consumer.subscribe({ topic: 'my-topic', fromBeginning: true });

  await consumer.run({
    eachMessage: async ({ topic, partition, message }) => {
      console.log({
        key: message.key?.toString(),
        value: message.value.toString(),
      });
    },
  });
})();

5. 마무리하며 ✨

NodePort와 NGINX를 조합하면 외부에서도 Kafka 클러스터를 안정적으로 접근할 수 있게 됩니다. 특히 인그레스 컨트롤러가 TCP 스트림을 직접 처리하지 못할 경우, NGINX stream proxy는 좋은 대안이 되어주죠.

다음 포스팅에서는 Kafka 메시지 브로커 설정, 토픽 생성 자동화, 인증 방식 구성 등에 대해서도 다뤄보겠습니다. Kafka 운영, 함께 배워봐요 🙌


댓글 남기기