본문 바로가기

프로그래밍/Docker

Apache Kafka 실습환경을 Docker에 구성해보기(feat. 아파치 카프카 입문)

내가 구독해서 보는 Youtue 채널 중에 SKplanet Tacademy 란 채널이 있다. 원래 T Academy는 모바일 앱 개발 관련 교육으로 알려졌는데 최근에는 모바일 앱개발에만 그치지 않고 프런트엔드, 백엔드 등 여러 다양한 분야에 대한 교육을 진행하고 있는걸로 보인다. 거기서 하는 교육중 아파치 카프카 입문 교육이 있었는데 거기서 했던 내용이 Youtube에 올라와서 Kafka를 공부해보고 싶은 맘에 한번 보게 되었다. 문제는 여기서 사용한 실습환경이 AWS 이다보니 AWS를 사용할 수 없는 개발자 입장에서는 따라하기에 한계가 있다. github에서 실습코드 받는거야 정말 별문제는 아니지만 실행환경이 AWS면 나 같은 사람에게는 이용하는데 한계가 있어서..그래서 이 글에서는 이 환경을 Docker를 통해 실습환경을 만드는 것에 대해 써보고자 한다. Docker로 이 환경을 구성하고 동영상에서 나온 실습코드를 그대로 따라하는데 문제가 전혀 없었다.

 

내 구성 환경은 Windows 10에 Vagrant CentOS7 리눅스 가상머신을 사용하는 상태에서 이 가상머신에 docker를 설치해서 docker 환경을 운영하고 있다. 그러나 Docker for Windows를 설치해서 운영하는 개발자나 요즘 한창 뜰려고 준비중인 WSL2를 이용해서 docker를 구성한 개발자가 해도 문제는 없을꺼라 생각한다.

 

Kafka는 흔히 Kafka 단독으로 구성되는게 아니라 Zookeeper와 같이 운영되는것이 특징이다. 그래서 Docker로 구성할때도 Zookeeper와 같이 구성해줘야 하는데 문제는 Zookeeper는 공식 docker 이미지가 있으나 Kafka는 공식 이미지가 없었다(정확하게 얘기하자면 Apache에서 만든 Kafka Docker 이미지는 없으나 Kafka를 개발했던 개발인력이 별도로 회사를 차려서 운영중인 Confluent에서 나온 Kafka Docker 이미지는 있다) 그래서 검색을 해보니 wurstmeister/kafka 이미지를 많이 사용하는거 같아보여 이걸 사용했다. 근데 이 이미지를 사용하다보니 Zookeeper 또한 wurstmeister가 만든 wurstmeister/zookeeper를 사용하여야 해서 Zookeeper 또한 wurstmeister/zookeeper 이미지를 사용했다. 아래의 내용은 이것을 사용하기 위해 만든 docker-compose.yml 파일이다.

 

version: '3'

services:
  zookeeper:
    image: wurstmeister/zookeeper
    container_name: zookeeper
    ports:
       - "28080:2181"
    networks:
      dockernet:
        ipv4_address: 10.10.20.141
  kafka:
    image: wurstmeister/kafka
    container_name: kafka
    depends_on: 
      - zookeeper
    ports:
      - "9092"
    environment:
      KAFKA_ADVERTISED_HOST_NAME: 10.10.20.142
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
    networks:
      dockernet:
        ipv4_address: 10.10.20.142
networks:
  dockernet:
    external: true

 

설명을 읽지도 않고 이 yml 내용을 복사해서 실행하지 말고 한 3분만 지금부터 얘기하는 내용을 보고 진행했으면 한다. 이걸 실행하기 전에 docker network를 별도로 만들어야 하기 때문이다. docker 를 아는 사람이 내용을 본다면 왜 그러는지 이해가 쉽지만 docker를 모르는 사람이 봤을수도 있기 때문이다. zookeeper와 kafka에 고정 ip를 주어서 실행하고 있는데 그 이유는 이것을 연동하는 Client Application에 IP 주소를 주어 연결하려 하기 위함이다. zookeeper에는 10.10.20.141를 주고 kafka에는 10.10.20.142를 주었다. 그러면 이 10.10.20.X 기반의 네트워크 영역대를 docker에 등록하는 과정이 먼저 있어야 한다. 만약 본인이 기존에 사용하고 있는 docker에 등록해놓은 네트워크 영역대가 있으면 IP 주소를 해당 네트워크 영역대의 IP 것으로 사용해도 된다. 위의 yml에서 정의한 IP 내트워크 영역대를 docker에 등록하기 위해 다음의 명령어를 실행한다. 이걸 먼저 한다음에 위에 있는 docker-compose.yml을 실행해야 한다.

 

docker network create -d bridge --subnet 10.10.20.0/24 --gateway 10.10.20.1 dockernet

 

10.10.20.1을 gateway로 하고 있는 10.10.20.X의 네트워크 영역대를 가진 bridge 네트워크를 dockernet 이라는 이름으로 만들었다. 그리고 docker-compose.yml을 보면 networks.dockernet.external을 true로 줌으로써 외부와의 연결이 허용되도록 하고 있다.

 

zookeeper 는 zookeeper 라는 이름을 가진 container로 만들고 있고 kafka는 kafka 라는 이름을 가진 container로 만들고 있다. 다만 kafka가 zookeeper와 연결하는 관계이다보니 먼저 zookeeper가 올라온 다음에 kafka가 연결이 되도록 하기 위해 depends_on 에 zookeeper를 걸어주었다. zookeeper 설정에 보면 ports에 28080:2181 을 볼 수 있는데 2181은 zookeeper가 외부와 통신하기 위해 열어놓은 port이다. 위에서 언급했다시피 구성환경에 Vagrant에서 동작하고 있는 CentOS 에서 docker가 설치되어 있다보니 Vagrant CentOS와 내 PC간에 연결되어 있는 28080 port(Vagrant CentOS 의 28080 port와 내 PC의 28080 port가 연결되어 있는 상태이다)를 사용했다. 이 관계를 정리하면 다음과 같다.

 

내 PC의 28080 port <-> Vagrant CentOS의 28080 port <-> zookeeper의 2181 port

 

이러한 연결관계가 있다고 보면 된다. kafka의 경우는 kafka가 사용하는 port인 9092만 열려있는 상태이다. 그러나 이 동영상을 보고 실습하면서 zookeeper가 하는 역할이 거의 없었다. 나중에 보여주겠지만 실제 실습 내용을 보면 zookeeper를 통해서 접근하는게 아니라 kafka에 직접 접근해서 실습하기 때문에 실제로는 이 구성이 실습과는 약간 맞지 않는 부분이 있었다. 오히려 kafka를 외부 네트워크와 연결이 되게끔 해야 하는 상황이었다. 내 경우는 위에서 설정한 10.10.20.X docker network와 내 PC간에 직접적으로 통신이 되게끔 route 설정을 해둔것이 있어서 실습을 할때는 zookeeper를 접속해서 실습하는게 아니라 바로 kafka와 직접 연결해서 실습하는 방식으로 진행했다.(이러한 설정을 하고자 하길 원할 경우 이 블로그에 있는 docker에 대한 형식없는 정리 글의 30번, 31번, 35번 글을 읽고 진행하면 된다. 31번의 경우는 Docker for Windows를 사용할때이고 35번은 Vagrant 환경을 사용할때이다.)

 

docker-compose.yml의 kafka 쪽 환경변수를 보면 KAFKA_ADVERTISED_HOST_NAME 변수가 있는데 여기에는 kafka가 실행되는 container의 IP를 넣어주면 된다. docker-compose.yml에서 kafka container에 10.10.20.142를 주었기 때문에 이 환경변수에도 10.10.20.142를 주었다. 여러개의 kafka를 설치해서 운영할 경우가 있을수 있어서 이 환경변수를 localhost로 하지 말라고 wurstmeister/kafka 이미지 배포자가 얘기하고 있지만 실습 자체가 여러개를 설치한뒤 이를 클러스터로 구성해서 운영하는 실습을 하는 것은 아니기 때문에 localhost로 해도 될 것 같다고 추측은 하고 있다.

 

이렇게 하면 실습환경이 갖추어지게 된다. 동영상을 보면 client 역할을 위해 또 다른 kafka를 별도로 설치하고 있지만 kafka가 server와 client 모두를 같이 배포하고 있기 때문에 docker-compose를 통해 실행되고 있는 kafka에 직접 들어가서 실행해도 된다. wurstmeister/zookeeper 이미지는 alpine linux 기반의 이미지이기 때문에 기본 shell이 ash 이다. 그래서 다음과 같은 명령어로 container에 직접 들어갈 수 있다.

 

docker exec -it kafka ash

 

위와 같이 실행하면 kafka container 안에 접속해서 명령어를 입력할 수 있게 된다. kafka는 /opt 디렉토리에 kafka란 이름으로 link가 생성되어 있기 때문에 cd 명령어로 /opt/kafka를 실행해서 kafka 디렉토리로 이동할 수 있다. 아래의 그림은 docker exec 설명부터 kafka topic을 생성하는 과정을 그림으로 캡춰한 것이다.

 

kafka container에 들어가서 topic을 생성하는 과정

여기서도 보면 kafka-topics.sh 파일을 실행할때 --bootstrap-server 옵션을 주어서 kafka 서버에 직접 연결해서 하고 있는것을 확인할 수 있다. 그리고 kafka-topics.sh --help를 실행하면 kafka-topics.sh 파일을 실행할때 사용할 수 있는 옵션 항목들을 볼 수 있는데 여기서 보면 --zookeeper 옵션을 통해 zookeeper를 통해서 topic을 생성할 수도 있지만 현재 이 옵션은 DEPRECATED 로 설정되어 있다. 강의 영상을 보면 kafka가 zookeeper 없이 구성되게끔 할려고 변경중이라고 하는데 이러한 의지에 대한 반영이라 보면 될듯하다. 그래서 강의 영상도 zookeeper를 통해 접근하는게 아니라 kafka에 직접 연결해서 하고 있다. 영상에서 보면 kafka 자체가 제공하는 client 뿐만 아니라 자바 클라이언트도 만들어서 실습하고 있는데 이때도 zookeeper를 통해 kafka를 접근하는게 아니라 바로 kafka로 접근하고 있다. 자바 클라이언트를 만들때 사용하는 kafka IP 주소는 docker container IP(10.10.20.142)를 이용하면 된다.

 

지금까지 아파치 카프카 입문 교육 과정을 실습하기 위한 환경을 docker로 구축하는 과정을 알아보았다. 좋은 강의를 해주신 최원영 님에게 감사를 드리며 이 글을 마친다.