Docker 위에 Kafka를 standalone으로 실행하기

smpl published on
5 min, 910 words

동기

Kafka를 자주 테스트할 일이 있어서, Dockerfile을 이용해 컨테이너를 만드는 방법을 알아보고 정리해 보았다.

더 나은 방법이 분명 더 있을텐데... 다른 글에서 docker compose를 이용해서 좀더 개선을 해볼 예정이다.

사전 지식

이제 막 공부를 시작한 입장에서, 사전지식이라고 정리할 내용은 거의 없으나.. 그래도 조금이라도 정리를 해본다.

docker 명령어

  • sudo service docker start : 도커 데몬 시작
  • docker pull <image name> : 도커 이미지 내려받기
  • docker images : 도커 이미지 목록 보기
  • docker ps : 도커 컨테이너 목록 보기
  • docker ps --all : 모든 도커 컨테이너 목록 보기 (멈춘 컨테이너까지 보여준다.)
  • docker rmi <image name> : 도커 이미지 삭제
  • docker rm <container name> : 도커 컨테이너 삭제
  • docker stop <container name> : 도커 컨테이너 중지
  • docker run --rm --name <container name> -p <host port>:<container port> --network <network name> <image name> : 도커 이미지를 컨테이너로 실행(인스턴스화)하기
    • rm 옵션 : 컨테이너가 종료되면 바로 삭제한다.
    • name 옵션 : 컨테이너 이름을 지정한다.
    • p 옵션 : 호스트 포트에 컨테이너 포트를 맵핑한다. 부가적으로, 대문자 P 옵션은 Dockerfile에 EXPOSE 설정된 포트를 임의의 호스트 포트에 자동으로 맵핑하는 옵션이다.
    • network 옵션 : 컨테이너가 속할 네트워크 이름을 지정한다.
  • docker exec -it <container name> /bin/bash : 컨테이너에 /bin/bash의 새 프로세스를 띄우고, 호스트의 표준입출력을 연결해 접속할 수 있게 해준다.
  • docker build -t <image name> <dockerfile path> : Dockerfile을 이미지로 빌드한다.
  • docker network create <network name> : 네트워크를 생성한다.
  • docker network inspect <network name> : 네트워크 구성을 확인한다.
  • docker network list : 네트워크 목록을 확인한다.
  • docker network prune : 아무 컨테이너도 참여하고 있지 않은, 미사용 상태의 네트워크를 정리한다.

Dockerfile 명령어

  • FROM <image name> : 특정 이미지를 상속받아 시작한다.
  • ENV <key>=<value> : 환경변수를 지정한다.
  • EXPOSE <port> : 호스트와 연결할 포트를 명시한다.
  • RUN <command> : 빌드타임에 커맨드를 실행한다.
  • WORKDIR <path> : 현재 작업 디렉토리를 변경한다.
  • COPY <source> <destinatoin> : 빌드타임에 파일을 복사한다.
  • CMD <command> : 런타임에 커맨드를 실행한다.

구조

로컬에서 개발 테스트에 사용할 목적이므로, Kafka는 클러스터를 구성하지 않고, 스탠드얼론으로 설치할 예정이다.

이미지는 주키퍼 서버 1대, 카프카 서버 1대, 카프카 클라이언트/콘솔 용도 1대로 총 3개의 이미지를 작성할 예정이다.

+-- zk : 주키퍼 서버 이미지 작성용
|   +-- Dockerfile
+-- kf : 카프카 서버 이미지 작성용
|   +-- Dockerfile
|   +-- server.properties
+-- kfcli : 카프카 클라이언트/콘솔 용도 이미지 작성용
    +-- Dockerfile

외부 접속 허용을 위한 포트 열기

다음과 같이 관리자 권한을 받은 powershell에서 실행해준다.

netsh interface portproxy delete v4tov4 listenport="2181"
netsh interface portproxy delete v4tov4 listenport="9092"

$wslIp=(wsl -d Ubuntu -e sh -c "ip addr show eth0 | grep 'inet\b' | awk '{print `$2}' | cut -d/ -f1")

netsh interface portproxy add v4tov4 listenport="2181" connectaddress="$wslIp" connectport="2181"
netsh interface portproxy add v4tov4 listenport="9092" connectaddress="$wslIp" connectport="9092"

network 생성

컨테이너들이 참여하여 서로 연결할 수 있는 네트워크를 미리 만들어준다.

docker network create kfnet

zk/Dockerfile

주키퍼 서버 이미지의 Dockerfile은 다음과 같다.

FROM ubuntu:20.04
ENV TZ=Asia/Seoul
EXPOSE 2181

RUN apt-get update
RUN apt-get install -y curl openjdk-13-jre

WORKDIR /root
RUN mkdir -p /var/kafka
RUN curl https://dlcdn.apache.org/kafka/2.8.0/kafka_2.13-2.8.0.tgz --output kafka.tgz
RUN tar xvzf kafka.tgz --directory=/var/kafka --strip-components=1

CMD /var/kafka/bin/zookeeper-server-start.sh /var/kafka/config/zookeeper.properties

이 Dockerfile은 docker build -t zk zk/ 와 같이 명령을 주어 빌드할 예정이고, 다음과 같이 실행한다.

docker run --rm --name zk-inst -p 2181:2181 --network kfnet zk

kf/Dockerfile 과 kf/server.properties

카프카 서버 이미지의 Dockerfile은 다음과 같다.

FROM ubuntu:20.04
ENV TZ=Asia/Seoul
EXPOSE 9092

RUN apt-get update
RUN apt-get install -y curl openjdk-13-jre

WORKDIR /root
RUN mkdir -p /var/kafka
RUN curl https://dlcdn.apache.org/kafka/2.8.0/kafka_2.13-2.8.0.tgz --output kafka.tgz
RUN tar xvzf kafka.tgz --directory=/var/kafka --strip-components=1

COPY server.properties /var/kafka/config/server.properties
CMD /var/kafka/bin/kafka-server-start.sh /var/kafka/config/server.properties

카프카 서버는 주키퍼 서버에 연결해야 하는데, 이를 위해 server.properties를 수정하여 주키퍼 서버의 주소를 설정해주어야 한다.

같은 네트워크에 속한 컨테이너들끼리는, 컨테이너 이름으로 서로를 찾을 수 있기 때문에, 컨테이너 이름을 주키퍼 주소에 지정해준다.

...(기본 server.properties에서 아래만 추가/수정해준다.)...
listeners=PLAINTEXT://:9092
zookeeper.connect=zk-inst:2181

이미지 빌드는 docker build -t kf kf/와 같이 명령을 주어 빌드하고, 다음과 같이 컨테이너를 실행한다.

docker run --rm --name kf-inst -p 9092:9092 --network kfnet kf

kfcli/Dockerfile

이제 마지막으로 카프카 클라이언트 이미지를 작성해준다.

FROM ubuntu:20.04
ENV TZ=Asia/Seoul

RUN apt-get update
RUN apt-get install -y curl openjdk-13-jre

WORKDIR /root
RUN mkdir -p /var/kafka
RUN curl https://dlcdn.apache.org/kafka/2.8.0/kafka_2.13-2.8.0.tgz --output kafka.tgz
RUN tar xvzf kafka.tgz --directory=/var/kafka --strip-components=1

WORKDIR /var/kafka

ENTRYPOINT /bin/bash

역시 docker build -t kfcli kfcli/ 처럼 빌드하고, 다음과 같이 컨테이너화 하여 실행하면, 해당 쉘 안에서 카프카 클라이언트 실행이 가능하다.

docker run --rm --name kfcli-inst --network kfnet -it kfcli

간단하게, 아래처럼 토픽을 생성해보면 잘 동작하는 것을 알 수 있다.

bin/kafka-topics.sh --bootstrap-server kf-inst:9092 --create --topic hello-kafka
bin/kafka-topics.sh --bootstrap-server kf-inst:9092 --list

참고자료