데이터 엔지니어 기술 블로그

[🧙Kafka] 카프카 구축 (1) - 주키퍼 앙상블 쉽게 구축하기 본문

데이터 엔지니어링

[🧙Kafka] 카프카 구축 (1) - 주키퍼 앙상블 쉽게 구축하기

jun_yeong_park 2021. 4. 6. 05:39
반응형

About

카프카 브로커에서 브로커와 토픽의 메타데이터를 저장하기 위해 주키퍼를 사용한다.

 

주키퍼를 단독으로 구성할 수도 있지만, 주키퍼를 클러스터로 구성하여 고가용성을 확보한 것을 주키퍼 앙상블(Zookeeper Ensemble)이라고 한다.

 

주키퍼 서버는 홀수로 구성하는 것을 권고하고 있기 때문에 3대로 구성하려고 한다. 홀수로 구성하는 이유는 예를 들어서 4대로 구성을 했을 때 결함에 대한 장애 대비 기능(failover)가 3대로 구성한 것과 다르지 않기 때문인데, 짝수로 구성해도 다른 큰 문제는 없다.

 

하나의 OS에서 3개의 도커를 띄워 구성해보려고 한다.

 

Tutorial & Example

1. 작업할 폴더를 생성한다.

2. Dockerfile을 아래와 같이 작성한다.

FROM ubuntu:18.04
RUN mkdir -p /root/install
RUN apt-get update

WORKDIR /root/install

# java 설치 준비
ENV DEBIAN_FRONTEND noninteractive
ENV JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64

# java 설치
RUN apt-get install openjdk-8-jdk -y

RUN apt-get install wget -y
RUN apt-get install vim -y

# zookeeper 설치
RUN wget downloads.apache.org/zookeeper/zookeeper-3.7.0/apache-zookeeper-3.7.0-bin.tar.gz
RUN tar -zxvf apache-zookeeper-3.7.0-bin.tar.gz

RUN mv apache-zookeeper-3.7.0-bin /usr/local/zookeeper

# 설정파일 및 초기화 파일 복사
COPY config/zoo.cfg /usr/local/zookeeper/conf/zoo.cfg
COPY config/init.sh init.sh

# windows에서 작업 시 CRLF와 LF 처리 방식 문제 방지
RUN sed -i 's/\r//g' init.sh
RUN sed -i 's/\r//g' /usr/local/zookeeper/conf/zoo.cfg

CMD bash init.sh

3. config 폴더를 Dockerfile이 있는 폴더에 생성한다.

4. config 폴더에 init.sh 파일을 생성 후 아래의 스크립트를 입력한다.

mkdir -p /data

# 주키퍼는 myid 파일로 클러스터를 구분한다. 1~255까지 번호를 지정할 수 있다.
echo $MY_ID > /data/myid

# 주키퍼 서버를 실행한다.
/usr/local/zookeeper/bin/zkServer.sh start

# 자동으로 종료되지 않도록 방지한다.
tail -f /dev/null

5. config 폴더에 zoo.cfg 파일을 생성 후 아래의 스크립트를 입력한다.

 

# 팔로워가 리더에 접속할 수 있는 시간
# initLimit * tickTime = 40초 로 설정된다.
initLimit=10
tickTime=2000

# 리더가 될 수 있는 팔로워의 최대 갯수를 나타낸다.
syncLimit=5

# myid가 저장될 디렉토리 위치이다.
dataDir=/data

# 클라이언트가 접속할 포트 번호이다.
clientPort=2181

# 앙상블을 이루는 서버 정보이다.
# server.X=hostname:peerPort:leaderPort
# peerPort는 앙상블 서버들이 상호 통신하는 데 사용되는 포트 번호이다.
# leaderPort는 리더를 선출하는 데 사용되는 포트 번호이다.
server.1=pipeline-zookeeper-a:2888:3888
server.2=pipeline-zookeeper-b:2888:3888
server.3=pipeline-zookeeper-c:2888:3888

# 자동으로 생성되는 스냅샷을 24시간마다 최대 3개를 유지하고 나머지는 제거한다.
autopurge.snapRetainCount=3
autopurge.purgeInterval=24

6. 네트워크를 생성하기 위해 docker network create zoo명령어를 입력한다. 이렇게 생성하면 zoo 라는 네트워크 안에 있는 컨테이너는 서로 통신이 가능하다. 컨테이너 실행 시 네트워크를 설정할 수 있다.

7. 아까 작성한 Dockerfile이 있는 곳에서 docker build --tag pipeline-zookeeper . 명령어를 입력한다.

8. docker-compose.yml 파일을 생성하고 아래의 스크립트를 입력한다.

   - 볼륨을 공유해주기  위해 개별 볼륨을 생성했고 각 컨테이너에 연결하는 설정을 했다.

   - MY_ID를 환경변수로 넣으면 init.sh에서 /data/myid 파일에 만들면서 저장시킨다.

version: '3.8'
volumes
  pipeline-zookeeper-a-volume:
    name: pipeline-zookeeper-a-volume
  pipeline-zookeeper-b-volume:
    name: pipeline-zookeeper-b-volume
  pipeline-zookeeper-c-volume:
    name: pipeline-zookeeper-c-volume
        
services:
  pipeline-zookeeper-a:
    image: pipeline-zookeeper
    container_name: pipeline-zookeeper-a
    restart: always
    hostname: pipeline-zookeeper-a
    environment:
      MY_ID: 1
    volumes:
      - pipeline-zookeeper-a-volume:/data

  pipeline-zookeeper-b:
    image: pipeline-zookeeper
    container_name: pipeline-zookeeper-b
    restart: always
    hostname: pipeline-zookeeper-b
    environment:
      MY_ID: 2
    volumes:
      - pipeline-zookeeper-b-volume:/data

  pipeline-zookeeper-c:
    image: pipeline-zookeeper
    container_name: pipeline-zookeeper-c
    restart: always
    hostname: pipeline-zookeeper-c
    environment:
      MY_ID: 3
    volumes:
      - pipeline-zookeeper-c-volume:/data

            
networks:
  default:
    external:
      name: zoo

9. docker-compose.yml파일이 있는 곳에서 docker-compose up -d 명령어를 사용하여 컨테이너들을 실행시킨다. docker-compose down; docker-compose up -d; 으로도 새롭게 실행할 수 있다.

10. 아래의 명령어로 잘 실행이 되었는지 확인한다.

docker exec pipeline-zookeeper-a /usr/local/zookeeper/bin/zkServer.sh status
docker exec pipeline-zookeeper-b /usr/local/zookeeper/bin/zkServer.sh status
docker exec pipeline-zookeeper-c /usr/local/zookeeper/bin/zkServer.sh status

11. 실행 결과는 다음과 같다. 2개의 Mode는 follower이고 1개는 leader 인 것을 확인할 수 있다.

10번 실행 결과

12. 여기에서는 pipeline-zookeeper-c 가 leader이다.

13. 팔로워인 pipeline-zookeeper-a를 restart를 해본다. 종료되었다가 팔로워로 다시 등록이 된 것을 확인할 수 있다.

docker stop pipeline-zookeeper-a
docker-compose up -d
docker exec pipeline-zookeeper-a /usr/local/zookeeper/bin/zkServer.sh status

13번 실행 결과

14. 리더인 pipeline-zookeeper-c를 stop한 결과. pipeline-zookeeper-a가 leader가 된 것을 확인할 수 있다.

docker stop pipeline-zookeeper-c
docker exec pipeline-zookeeper-a /usr/local/zookeeper/bin/zkServer.sh status
docker exec pipeline-zookeeper-b /usr/local/zookeeper/bin/zkServer.sh status

14번 실행 결과

15. 14번에 종료했던 것을 다시 실행하더라도 pipeline-zookeeper-a가 리더로 유지된다.

docker-compose up -d
docker exec pipeline-zookeeper-a /usr/local/zookeeper/bin/zkServer.sh status
docker exec pipeline-zookeeper-b /usr/local/zookeeper/bin/zkServer.sh status
docker exec pipeline-zookeeper-c /usr/local/zookeeper/bin/zkServer.sh status

15번 실행 결과

16. 주키퍼를 유지할 수 있는 최소 갯수 이하로 줄여보려고 한다. 2대를 종료시킨다.

docker stop pipeline-zookeeper-c
docker stop pipeline-zookeeper-b
docker exec pipeline-zookeeper-a /usr/local/zookeeper/bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /usr/local/zookeeper/bin/../conf/zoo.cfg
Client port found: 2181. Client address: localhost. Client SSL: false.
Error contacting service. It is probably not running.

16번 실행 결과

17. 2대가 종료된 상태에서 다시 실행해보았다. 다시 이용 가능한 상태가 된 것을 확인할 수 있다.

docker-compose up -d
docker exec pipeline-zookeeper-a /usr/local/zookeeper/bin/zkServer.sh status
docker exec pipeline-zookeeper-b /usr/local/zookeeper/bin/zkServer.sh status
docker exec pipeline-zookeeper-c /usr/local/zookeeper/bin/zkServer.sh status

17번 실행 결과

18. 완료!

 

 

Issues

CRLF, LF Issue

Dockerfile에서 COPY 명령어를 사용해 windows에서 작성한 파일을 복사 후 동작시켰을 때 문제가 발생했다.

프로그램은 정상적으로 동작하나 /usr/local/zookeeper/bin/zkServer.sh status 명령어로 상태를 가져오려고 했을 때 myid를 찾을 수 없다는 문제가 발생했다. myid는 분명히 존재했고 start 명령어를 사용했을 때는 제대로 동작했다.

그래서 bash -x /usr/local/zookeeper/bin/zkServer.sh status 명령어로 실행 중에 설정파일을 불러오는 곳의 값이 어떻게 들어가는지 확인해본 결과 \r이 남아있는 것을 확인했다.

Dockerfile에서 아래의 코드를 추가하여 CRLF -> LF로 변환해주었고 해결이 되었다.

RUN sed -i 's/\r//g' init.sh
RUN sed -i 's/\r//g' /usr/local/zookeeper/conf/zoo.cfg
반응형
Comments