정말로 많은 삽질이 있었습니다.
하....
그래도 덕분에 하둡 클러스터의 구조와 하이브 간의 소통방식을 어느 정도 이해한 것 같아요. 하둡 클러스터를 구축하고, 하이브가 이것과 통신하게 하고, 여기에 웹 UI인 Hue 를 설치하는 과정까지 한번 진행해 보겠습니다.
하둡 클러스터와 하이브 구조
먼저 결과적으로 구축한 하둡 클러스터와 하이브의 구조를 살펴보면 아래와 같습니다.
- 서로 통신하는 아이들끼리 화살표로 표기했습니다.
- 각 통신하는 모듈별로 구분을 쉽게 하기 위해 화살표 색을 다르게 했습니다.
위 그림에서 보는 것처럼, 총 8개의 노드가 필요합니다.
노드 이름 | 역할 |
namenode | HDFS 메타데이터 저장, data노드 관리 |
datanode 2개 | HDFS 데이터 저장, resourcemanager 에서 할당하는 job 수행 |
datanode 1개 | HDFS 데이터 저장, 하이브 메타스토어 관리 |
datanode 1개 | HDFS 데이터 저장, hiveserver 구동 (TEZ 포함) |
resourcemanager | 클러스터 자원 관리, datanode 2개에 실행 중인 nodemanager 통해 job 할당 및 관리 |
hue | hue 설치 및 실행 |
hue DB | hue를 구동하기 위한 DB 설치 |
각 노드의 역할을 제가 이해한 하둡 아키텍처와 맞물려서 설명하면 다음과 같습니다.
- namenode / datanode : HDFS에 데이터를 저장하고, 저장된 데이터를 관리하는 역할을 합니다. 이 노드들은 그냥 데이터의 저장과만 관련되어 있고, 이 노드들의 리소스 (CPU, Memory) 를 이용하여 분산 처리를 수행하려면 yarn 이 필요합니다.
- resource manager : yarn을 실행할 노드입니다. 리소스를 실행할 노드들을 관리해 주고 제출된 job를 각 노드에 분배해 줍니다.
- nodemanager : yarn은 node manager가 실행 중인 노드에 대해서만 리소스를 할당합니다. 그러니까 위 처럼 데이터노드가 4개 있어도, 실제 job이 제출될 경우 실행하는 노드는 노드매니저가 실행 중인 2개뿐입니다.
- hue / hue DB : 웹 ui인 hue와, 이를 실행해줄 DB가 설치된 노드입니다. hue는 그냥 좀 편하게 쿼리를 작성하고 HDFS 에 저장된 파일을 조회할 목적이므로, 굳이 없어도 됩니다.
제가 이해한 바로는, 위와 같이 하둡 클러스터는 job의 실행과 파일의 저장이 분리된 역할로 수행합니다. job의 실행은 resourcemanager에 의해 관리되고 저장 등 IO는 namenode 에 의해 관리됩니다. 실제로 어떤 데이터노드에도 nodemanager를 실행시키지 않으면 yarn 에서 잡을 할당하지 못해서 쿼리가 실행되지 않다가 타임아웃이 납니다.
이제부터는 실제로 어떻게 구축했는지를 알아보고, 글 마지막에는 제출된 job이 어떤 경로로 실행하는지를 적어보겠습니다.
하둡-하이브 클러스터 구축 과정
가장 먼저 도커 이미지를 하나 받아서 하둡을 도커에 올려줘야 합니다. 저는 bde2020/hadoop-xxx 시리즈를 이용했습니다. 근데 이게 이미지가 오래되다보니 그대로 쓰기에는 여러가지 문제가 있습니다.
- 하둡 버전이 낮음
- 하둡 - 하이브 클러스터를 구축하려는데 하이브, 테즈가 이미지 내에 없음
그래서 이미지를 다시 빌드하기로 했습니다.
하둡 도커 이미지 빌드
bde2020/hadoop 이미지 시리즈는 bde2020/hadoop-base 이미지를 기초로 해서 namenode, datanode 등 각 요소마다 필요한 부분만을 후에 이미지에 추가해준 형태로 되어 있습니다. 필요한 건 base, namenode, datanode, resourcemanager, historyserver 입니다. 일단 레포는 다음과 같습니다.
레포에 들어가면 여러 폴더가 있는데요, 여기에서 이미지는 총 5개가 필요하고 각 이미지별로 빌드하기 위해 필요한 파일은 다음과 같습니다. 이를 다운받습니다.
이미지 | 필요한 파일 |
base | Dockerfile, entrypoint.sh |
namenode datanode resourcemanager historyserver |
Dockerfile, run.sh |
베이스 이미지 파일 생성
Dockerfile 을 아래와 같이 수정합니다. 보면 몇군데 수정한 건 없고, OS를 debian 에서 ubuntu 로 변경하고 기타 유용한 여러 툴 (vim, wget) 설치를 추가했습니다. entrypoint.sh 는 변경하지 않으셔도 됩니다.
FROM ubuntu:focal
MAINTAINER YOUR NAME
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends openjdk-8-jdk net-tools curl wget procps netcat vim systemctl gnupg libsnappy-dev && rm -rf /var/lib/apt/lists/*
ENV JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/
RUN curl -O https://dist.apache.org/repos/dist/release/hadoop/common/KEYS
RUN gpg --import KEYS
ENV HADOOP_VERSION 3.3.6
ENV HADOOP_URL https://downloads.apache.org/hadoop/common/hadoop-$HADOOP_VERSION/hadoop-$HADOOP_VERSION.tar.gz
RUN set -x && curl -fSL "$HADOOP_URL" -o /tmp/hadoop.tar.gz && curl -fSL "$HADOOP_URL.asc" -o /tmp/hadoop.tar.gz.asc && gpg --verify /tmp/hadoop.tar.gz.asc && tar -xvf /tmp/hadoop.tar.gz -C /opt/ && rm /tmp/hadoop.tar.gz* && mv /opt/hadoop-$HADOOP_VERSION/ /opt/hadoop/
RUN ln -s /opt/hadoop/etc/hadoop /etc/hadoop
RUN mkdir /opt/hadoop/logs
RUN mkdir /hadoop-data
ENV HADOOP_HOME=/opt/hadoop
ENV HADOOP_CONF_DIR=/etc/hadoop
ENV MULTIHOMED_NETWORK=1
ENV USER=root
ENV PATH $HADOOP_HOME/bin/:$PATH
ADD entrypoint.sh /entrypoint.sh
RUN chmod a+x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
이렇게 저장한 후, 다음 명령어로 도커 이미지를 빌드합니다. myproject 부분에는 원하는 걸 아무거나 넣으셔도 되고, 그냥 안넣으셔도 됩니다. (예시. hadoop:3.3.6)
docker build --tag myproject/hadoop:3.3.6 .
명령어 맨 끝에 "." 을 넣는 걸 잊지 마세요. Dockerfile의 경로를 나타내는데, 현재 이 명령어를 실행하는 폴더에 있는 걸로 이미지를 만들라는 뜻입니다. 그러니까 위 명령어는 좀아까 만든 Dockerfile이 있는 경로에서 실행하셔야 합니다.
위 베이스 이미지에는 entrypoint 까지만 있고, 생성 후 마지막에 명령어를 실행하는 부분이 없습니다. 이제 저 공통 하둡 이미지를 가지고 필요한 부분을 실행해 주는 이미지를 만들겠습니다.
네임노드 이미지 파일 생성
가장 먼저 네임노드를 생성해 줍니다. 마찬가지로 Dockerfile 을 아래와 같이 생성합니다. 원래 bde2020 레포에서 바뀐 건 사실 첫번째 줄에 FROM 밖에 없습니다. 나머지는 모두 동일하게 작성되었습니다. run.sh 는 컨테이너를 실행할 때 필요한 파일이므로 안 건드리셔도 됩니다.
FROM myproject/hadoop:3.3.6
MAINTAINER YOUR NAME
HEALTHCHECK CMD curl -f http://localhost:9870/ || exit 1
ENV HDFS_CONF_dfs_namenode_name_dir=file:///hadoop/dfs/name
RUN mkdir -p /hadoop/dfs/name
VOLUME /hadoop/dfs/name
ADD run.sh /run.sh
RUN chmod a+x /run.sh
EXPOSE 9870
CMD ["/run.sh"]
이후에는 베이스 이미지와 마찬가지로 이미지를 빌드합니다.
docker build --tag myproject/hadoop-namenode:3.3.6 .
데이터노드 이미지 생성
데이터노드에는 조금 더 작업을 해보겠습니다. 두가지 버전으로 만들 겁니다. 데이터노드만 띄울 이미지와, 데이터노드와 hive를 함께 띄울 이미지 버전으로 해보고자 합니다. 먼저 데이터노드만 띄우는 이미지는 네임노드와 거의 유사합니다. Dockerfile을 다음과 같이 만듭니다. 이미지를 빌드하는 명령어는 생략하겠습니다. 위 내용을 참고해서 이미지를 빌드해 주세요.
FROM myproject/hadoop:3.3.6
MAINTAINER YOUR NAME
HEALTHCHECK CMD curl -f http://localhost:9864/ || exit 1
ENV HDFS_CONF_dfs_datanode_data_dir=file:///hadoop/dfs/data
RUN mkdir -p /hadoop/dfs/data
VOLUME /hadoop/dfs/data
ADD run.sh /run.sh
RUN chmod a+x /run.sh
EXPOSE 9864
CMD ["/run.sh"]
데이터노드 + 하이브 이미지 생성
데이터노드와 하이브가 함께 있는 이미지를 생성합니다. 이 노드는 데이터노드 역할도 하면서 하이브 및 하이브 메타스토어 역할도 함께 합니다. 이때, 하둡 - 하이브 - 테즈 버전을 모두 호환되게끔 맞춰줘야 합니다. 각각 호환되는 버전은 다음과 같이 맞췄습니다.
- hadoop 3.3.6
- hive 4.0.0-beta-1
- tez 0.10.3
테즈 버전이 하둡과 안 맞아서 (0.10.2) 라이브러리가 없다는 둥 한참 고생을 했으니 잘 맞춰서 만들어 주세요. 아래와 같습니다. base 이미지에서 하둡을 설치했고, 이 이미지에만 추가적으로 hive 와 tez 를 설치하는 방식입니다.
FROM myproject/hadoop:3.3.6
MAINTAINER YOUR NAME
ENV HIVE_VERSION 4.0.0-beta-1
ENV HIVE_URL https://downloads.apache.org/hive/hive-$HIVE_VERSION/apache-hive-$HIVE_VERSION-bin.tar.gz
ENV TEZ_VERSION 0.10.3
ENV TEZ_URL https://downloads.apache.org/tez/$TEZ_VERSION/apache-tez-$TEZ_VERSION-bin.tar.gz
RUN set -x && curl -fSL "$HIVE_URL" -o /tmp/hive.tar.gz && tar -xvf /tmp/hive.tar.gz -C /opt/ && rm /tmp/hive.tar.gz* && mv /opt/apache-hive-$HIVE_VERSION-bin/ /opt/hive/ && curl -fSL "$TEZ_URL" -o /tmp/tez.tar.gz && tar -xvf /tmp/tez.tar.gz -C /opt/ && rm /tmp/tez.tar.gz* && mv /opt/apache-tez-$TEZ_VERSION-bin/ /opt/tez/
ENV HIVE_HOME=/opt/hive
ENV HIVE_CONF_DIR=$HIVE_HOME/conf
ENV TEZ_JARS=/opt/tez
ENV TEZ_CONF_DIR=$TEZ_JARS/conf
ENV HADOOP_CLASSPATH=$TEZ_JARS/*:$TEZ_JARS/lib/*:$HADOOP_CLASSPATH
ENV PATH $HIVE_HOME/bin:$PATH
HEALTHCHECK CMD curl -f http://localhost:9864/ || exit 1
ENV HDFS_CONF_dfs_datanode_data_dir=file:///hadoop/dfs/data
RUN mkdir -p /hadoop/dfs/data
VOLUME /hadoop/dfs/data
ADD run.sh /run.sh
RUN chmod a+x /run.sh
EXPOSE 9864 10000 10002 9083
CMD ["/run.sh"]
리소스 매니저 이미지 생성
Dockerfile은 다음과 같습니다.
FROM myproject/hadoop:3.3.6
MAINTAINER YOUR NAME
HEALTHCHECK CMD curl -f http://localhost:8088/ || exit 1
ADD run.sh /run.sh
RUN chmod a+x /run.sh
EXPOSE 8088
CMD ["/run.sh"]
히스토리 서버 이미지 생성
Dockerfile은 다음과 같습니다.
FROM myproject/hadoop:3.3.6
MAINTAINER YOUR NAME
HEALTHCHECK CMD curl -f http://localhost:8188/ || exit 1
ENV YARN_CONF_yarn_timeline___service_leveldb___timeline___store_path=/hadoop/yarn/timeline
RUN mkdir -p /hadoop/yarn/timeline
VOLUME /hadoop/yarn/timeline
ADD run.sh /run.sh
RUN chmod a+x /run.sh
EXPOSE 8188
CMD ["/run.sh"]
이렇게 모든 이미지의 준비가 끝나면 1단계는 마무리가 되었습니다. 아니지 이제 0단계 마무리인가...?
아무튼 다음 단계로 넘어가 볼게요.
도커 컨테이너 만들기 (docker-compose)
컨테이너를 만들 이미지를 만들었으니까, 이제 그 이미지로 컨테이너를 만들 docker-compose.yml 파일을 구성할 차례입니다. 저는 세단계로 만들었습니다.
- 하둡 클러스터 컨테이너 띄우기 : namenode, datanode, resourcemanager, historyserver
- 하이브 관련 컨테이너 띄우기 : postgresql, metastore, hiveserver2
- Hue 관련 컨테이너 띄우기 : mysql, hue
차례대로 살펴보겠습니다.
하둡 클러스터 컨테이너
docker-compose.yml 은 다음과 같습니다. 일단은 이렇게 작성해 주시고, 주의점은 다음과 같습니다.
- 각 컨테이너끼리 통신할 수 있도록 networks 는 모두 동일한 이름으로 생성
- 컨테이너 밖에서 (즉, 내 로컬 컴퓨터에서) 접속 가능해야 하는 포트는 ports 에서 매핑 (로컬포트:컨테이너포트)
- hadoop.env 를 잘 설정
- datanode 는 하이브가 포함되어 있지 않은 버전으로 띄우기
version: '3.7' # 있어도 그만 없어도 그만
services:
namenode:
image: myproject/hadoop-namenode:3.3.6
container_name: namenode
hostname: namenode
volumes:
- hadoop_namenode:/hadoop/dfs/name
env_file:
- ./hadoop/hadoop.env # 이 파일 설정이 엄청나게 중요합니다
environment:
- CLUSTER_NAME=my_hadoop
ports:
- "9870:9870"
- "9000:9000"
networks:
- bigdata-network
datanode-1:
image: myproject/hadoop-datanode:3.3.6
container_name: datanode-1
hostname: datanode-1
volumes:
- hadoop_datanode-1:/hadoop/dfs/data
environment:
SERVICE_PRECONDITION: "namenode:9870"
env_file:
- ./hadoop/hadoop.env
networks:
- bigdata-network
datanode-2:
image: myproject/hadoop-datanode:3.3.6
container_name: datanode-2
hostname: datanode-2
volumes:
- hadoop_datanode-2:/hadoop/dfs/data
environment:
SERVICE_PRECONDITION: "namenode:9870"
env_file:
- ./hadoop/hadoop.env
networks:
- bigdata-network
resourcemanager:
image: myproject/hadoop-resourcemanager:3.3.6
container_name: resourcemanager
hostname: resourcemanager
environment:
SERVICE_PRECONDITION: "namenode:9000 namenode:9870 datanode-1:9864 datanode-2:9864"
env_file:
- ./hadoop/hadoop.env
ports:
- "8088:8088"
networks:
- bigdata-network
historyserver:
image: myproject/hadoop-historyserver:3.3.6
container_name: historyserver
hostname: historyserver
environment:
SERVICE_PRECONDITION: "namenode:9000 namenode:9870 datanode-1:9864 datanode-2:9864 resourcemanager:8088"
env_file:
- ./hadoop/hadoop.env
volumes:
- hadoop_historyserver:/hadoop/yarn/timeline
ports:
- "8188:8188"
networks:
- bigdata-network
networks:
bigdata-network:
driver: bridge
volumes:
hadoop_namenode:
hadoop_datanode-1:
hadoop_datanode-2:
hadoop_historyserver:
하다 보니까, docker-compose.yml 은 이미지마다 천지차이라 뭐가 맞다고 할 수는 없는 거 같고, bde2020 기준으로만 보면 env_file 안의 저 hadoop.env 파일을 불러와서 환경변수로 등록을 한 후에 해당 환경변수에 맞추어서 하둡 설정 (hdfs-site.xml, yarn-site.xml, core-site.xml, mapred-site.xml) 파일을 변경해 주는 역할을 합니다.
그러니까 컨테이너를 아래처럼 띄워 놔도, 하둡 설정이 제대로 되어 있지 않으면 오만 에러가 다 뜨고 서로 노드끼리 통신도 안되고 그렇더라구구요. 그러면 이제 제가 이것저것 만져서 설정해 놓은 hadoop.env 입니다.
CORE_CONF_fs_defaultFS=hdfs://namenode:9000 #namenode 에서 기본적으로 통신하는 포트를 적음
CORE_CONF_hadoop_http_staticuser_user=root
CORE_CONF_hadoop_proxyuser_hue_hosts=*
CORE_CONF_hadoop_proxyuser_hue_groups=*
CORE_CONF_io_compression_codecs=org.apache.hadoop.io.compress.SnappyCodec
HDFS_CONF_dfs_webhdfs_enabled=true
HDFS_CONF_dfs_permissions_enabled=false
HDFS_CONF_dfs_namenode_datanode_registration_ip___hostname___check=false
HDFS_CONF_dfs_namenode_acls_enabled=true
YARN_CONF_yarn_log___aggregation___enable=true
YARN_CONF_yarn_log_server_url=http://historyserver:8188/applicationhistory/logs/
YARN_CONF_yarn_resourcemanager_recovery_enabled=true
YARN_CONF_yarn_resourcemanager_store_class=org.apache.hadoop.yarn.server.resourcemanager.recovery.FileSystemRMStateStore
YARN_CONF_yarn_resourcemanager_scheduler_class=org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler
YARN_CONF_yarn_scheduler_capacity_root_default_maximum___allocation___mb=8192
YARN_CONF_yarn_scheduler_capacity_root_default_maximum___allocation___vcores=4
YARN_CONF_yarn_resourcemanager_fs_state___store_uri=/rmstate
YARN_CONF_yarn_resourcemanager_system___metrics___publisher_enabled=true
YARN_CONF_yarn_resourcemanager_hostname=resourcemanager
YARN_CONF_yarn_resourcemanager_address=resourcemanager:8032
YARN_CONF_yarn_resourcemanager_scheduler_address=resourcemanager:8030
YARN_CONF_yarn_resourcemanager_resource__tracker_address=resourcemanager:8031
YARN_CONF_yarn_timeline___service_enabled=true
YARN_CONF_yarn_timeline___service_generic___application___history_enabled=true
YARN_CONF_yarn_timeline___service_hostname=historyserver
YARN_CONF_mapreduce_map_output_compress=true
YARN_CONF_mapred_map_output_compress_codec=org.apache.hadoop.io.compress.SnappyCodec
YARN_CONF_yarn_nodemanager_resource_memory___mb=32768
YARN_CONF_yarn_nodemanager_resource_cpu___vcores=8
YARN_CONF_yarn_nodemanager_disk___health___checker_max___disk___utilization___per___disk___percentage=98.5
YARN_CONF_yarn_nodemanager_remote___app___log___dir=/app-logs
YARN_CONF_yarn_nodemanager_aux___services=mapreduce_shuffle
MAPRED_CONF_mapreduce_framework_name=yarn-tez # tez 를 쓰기 위해 yarn-tez로 설정해야 함. yarn이 기본값
MAPRED_CONF_mapred_child_java_opts=-Xmx4096m
MAPRED_CONF_mapreduce_map_memory_mb=4096
MAPRED_CONF_mapreduce_reduce_memory_mb=8192
MAPRED_CONF_mapreduce_map_java_opts=-Xmx3072m
MAPRED_CONF_mapreduce_reduce_java_opts=-Xmx6144m
MAPRED_CONF_yarn_app_mapreduce_am_env=HADOOP_MAPRED_HOME=/opt/hadoop/
MAPRED_CONF_mapreduce_map_env=HADOOP_MAPRED_HOME=/opt/hadoop/
MAPRED_CONF_mapreduce_reduce_env=HADOOP_MAPRED_HOME=/opt/hadoop/
일단 여기까지 해 놓고 실제로 띄우는 건 아래에서 할 테니, 하이브 컨테이너들 설정으로 넘어가겠습니다.
하이브 컨테이너
하이브나 하이브메타스토어는 데이터노드를 관리하는 네임노드보다는 데이터노드에 띄워놓고 사용자 명령을 리스닝하게 해 두는게 좋다고 합니다. 그래서 위의 이미지 생성에서 데이터노드를 두가지 버전으로 생성을 했었습니다. 이번에는 하이브를 포함한 이미지에서 생성해보겠습니다. 위에서 만들지 않은 이미지는 아래의 yml 파일을 참고해서 pull 후에 사용하시면 됩니다.
version: '3.7'
services:
hive-postgres:
image: postgres:12.18-bullseye
container_name: hive-postgres
hostname: hive-postgres
environment:
POSTGRES_DB: 'metastore_db'
POSTGRES_USER: 'hive'
POSTGRES_PASSWORD: 'hive'
ports:
- '5432:5432'
volumes:
- hive-db:/var/lib/postgresql
networks:
- bigdata-network
hive-metastore:
image: myproject/hadoop-datanode-hive-tez:3.3.6-4.0.0-0.10.3
depends_on:
- hive-postgres
container_name: hive-metastore
hostname: hive-metastore
environment:
SERVICE_PRECONDITION: "namenode:9870"
env_file:
- ./hadoop/hadoop.env
ports:
- '9083:9083'
volumes:
- hive-metastore:/hadoop/dfs/data
- type: bind
source: /d/docker/hive/postgresql-42.5.1.jar
target: /opt/hive/lib/postgres.jar
- type: bind
source: /d/docker/hive/hive-site.xml
target: /opt/hive/conf/hive-site.xml
- type: bind
source: /d/docker/hive/tez-site.xml
target: /opt/tez/conf/tez-site.xml
networks:
- bigdata-network
hiveserver2:
image: myproject/hadoop-datanode-hive-tez:3.3.6-4.0.0-0.10.3
restart: unless-stopped
container_name: hiveserver2
hostname: hiveserver2
ports:
- '10000:10000'
- '10002:10002'
env_file:
- ./hadoop/hadoop.env
volumes:
- hiveserver2:/hadoop/dfs/data
- type: bind
source: /d/docker/hive/hive-site.xml
target: /opt/hive/conf/hive-site.xml
- type: bind
source: /d/docker/hive/tez-site.xml
target: /opt/tez/conf/tez-site.xml
- type: bind
source: /d/docker/hive/postgresql-42.5.1.jar
target: /opt/hive/lib/postgres.jar
networks:
- bigdata-network
networks:
bigdata-network:
driver: bridge
volumes:
hive-db:
hive-metastore:
hiveserver2:
위의 yml 파일에서 보시면, hive-metastore와 hiveserver2 에는 volumes 부분을 바인드해 주는 걸 보실 수 있습니다. hive-metastore 에서는 postgres 에 접근해야 하므로 이를 핸들링하기 위한 jdbc 드라이버를 넣어주는 것이구요, hiveserver2 에는 hadoop과 통신하기 위한 설정을 담고 있는 파일은 hive-site.xml 과 tez-site.xml 파일을 별도로 설정해서 올바른 위치에 넣어줍니다.
이런 식으로 bind 하게 되면 로컬 컴퓨터에서 파일을 수정하면 컨테이너 내부의 파일에도 즉시 반영됩니다. 하지만 metastore 나 hiveserver2 같은 서비스 자체는 껐다가 다시 켜야 해당 설정이 다시 적용됩니다.
이번에도 마찬가지로 저 yml 보다도 각 설정 파일이 훨씬 중요하니까, 그걸 살펴보겠습니다. 아래 파일에서 대략 설정해 준 내용을 보면 다음과 같습니다.
- 하이브 실행 엔진 설정 : tez - 위의 hadoop.env 에서 yarn-tez 로 설정되어 있어야 정상적으로 돌아갑니다.
- metastore DB 타입 설정 : postgres
- metastore DB 설정 : DB 서버, 접속 주소, DB, id, pw
- 메타스토어 주소 및 포트 설정
- hive thrift 포트 및 호스트 설정
- hdfs config 설정
이렇게 설정해 줌으로써, 하이브가 메타스토어와도 통신할 수 있고, 하둡 (hdfs, yarn) 과도 통신할 수 있게 됩니다.
<!-- hive-site.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<property><name>hive.server2.enable.doAs</name><value>false</value></property>
<property><name>hive.exec.scratchdir</name><value>/tmp/hive</value></property>
<property><name>hive.user.install.directory</name><value>/user/</value></property>
<!-- excute engine : tez, mr -->
<property><name>hive.execution.engine</name><value>tez</value></property>
<!-- metastor DB config -->
<property><name>hive.metastore.db.type</name><value>postgres</value></property>
<property><name>javax.jdo.option.ConnectionDriverName</name><value>org.postgresql.Driver</value></property>
<property><name>javax.jdo.option.ConnectionURL</name><value>jdbc:postgresql://hive-postgres:5432/metastore_db</value></property>
<property><name>javax.jdo.option.ConnectionUserName</name><value>hive</value></property>
<property><name>javax.jdo.option.ConnectionPassword</name><value>hive</value></property>
<!-- metastore config -->
<property><name>hive.metastore.port</name><value>9083</value></property>
<property><name>hive.metastore.uris</name><value>thrift://hive-metastore:9083</value></property>
<!-- hiveserver2 config -->
<property><name>hive.server2.transport.mode</name><value>binary</value></property>
<property><name>hive.server2.thrift.port</name><value>10000</value></property>
<property><name>hive.server2.thrift.bind.host</name><value>hiveserver2</value></property>
<!-- hdfs config -->
<property><name>hive.metastore.warehouse.dir</name><value>hdfs://namenode:9000/user/hive/warehouse</value></property>
<property><name>hive.metastore.event.db.notification.api.auth</name><value>false</value></property>
<!-- <property><name>hive.notification.event.poll.interval</name><value>-1</value></property> -->
<!-- mapreduce config -->
<!-- <property><name>hive.exec.reducers.bytes.per.reducer</name><value>256000000</value></property> -->
<!-- <property><name>hive.exec.reducers.max</name><value>1009</value></property> -->
</configuration>
<!-- tez-site.xml -->
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property><name>tez.local.mode</name><value>false</value></property>
<property><name>tez.runtime.optimize.local.fetch</name><value>false</value></property>
<property><name>tez.lib.uris</name><value>hdfs://namenode:9000/apps/tez/tez.tar.gz</value></property>
<property><name>tez.am.client.heartbeat.timeout.secs</name><value>1000</value></property>
<property><name>tez.am.session.min.held-containers</name><value>0</value></property>
<property><name>tez.am.mode.session</name><value>false</value></property>
<property><name>tez.task.resource.memory.mb</name><value>1024</value></property>
<property><name>tez.task.resource.cpu.vcores</name><value>1</value></property>
<property><name>tez.am.container.reuse.new-containers.enabled</name><defaultValue>false</defaultValue>
<type>boolean</type>
</property>
</configuration>
hue 컨테이너
hue는 yaml는 별거 없습니다. 이것도 hue.ini 라고 hue 설정파일이 엄청 중요해요. 일단 yml 파일 구성부터 보겠습니다.
version: '3'
services:
hue-database:
image: mysql:latest
container_name: hue-database
hostname: hue-database
dns: 8.8.8.8
ports:
- "13306:3306"
command: --init-file /data/application/init.sql
volumes:
- hue_data:/var/lib/mysql
- type: bind
source: /d/docker/hue/init.sql
target: /data/application/init.sql
environment:
MYSQL_ROOT_USER: root
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: hue
MYSQL_USER: admin
MYSQL_PASSWORD: secret
networks:
- bigdata-network
hue:
image: gethue/hue:latest
depends_on:
- hue-database
container_name: hue
ports:
- "8888:8888"
volumes:
- type: bind
source: /d/docker/hue/hue.ini
target: /usr/share/hue/desktop/conf/hue.ini
networks:
- bigdata-network
networks:
bigdata-network:
driver: bridge
volumes:
hue_data:
다음으로 위 yaml 에서 바인딩해 준 hue.ini 설정인데요, 이건 설정 파일이 너무 기니까 그냥 첨부로 대체하겠습니다. 변경점은 다음과 같습니다.
- 타임존 변경 : LA → Seoul
- hue database 설정 변경 : sqllite3 → mysql - sqlite3 를 쓰게 되면 뭔가 에러가 나더라구요? 그래서 mysql 로 바꿨습니다.
- hdfs 접근 url 및 port
- hiveserver2 접근 호스트명 및 port
- hive metastore 접근 호스트명 및 port
이제 이미지 생성하고 컨테이너 실행 준비까지 끝났습니다. 실제로 이제 컨테이너를 올려서 하둡 클러스터를 띄워보겠습니다.
하둡 - 하이브 클러스터 띄우기
이번에는 명령어로 한번 쭉 살펴보겠습니다. 한줄한줄씩 하셔야 해요. 위의 yml 파일들을 모두 이름을 다르게 저장하시고 하나의 폴더에 있다고 가정하고 해보겠습니다.
#######################################################
# 컨테이너 띄우기
# 하둡 띄우기
# -f 옵션은 docker-compose.yml 파일의 이름이 docker-compose 가 아닐 때 이름을 설정해주는 옵션
docker-compose -p hadoop -f .\hadoop-compose.yml up -d
# 하이브 띄우기
docker-compose -p hadoop -f .\hive-compose.yml up -d
# hue 띄우기
docker-compose -p hadoop -f .\hue-compose.yml up -d
#######################################################
# 서비스 실행 준비 : 하이브
# hive 에서 인식하기 위해서는 /user/hive/warehouse 라는 폴더가 hdfs 에 있어야 함
docker exec -it hive-metastore hdfs dfs -mkdir -p /user/hive/warehouse
docker exec -it hive-metastore hdfs dfs -chmod 777 /
docker exec -it hive-metastore hdfs dfs -chmod 777 /user
docker exec -it hive-metastore hdfs dfs -chmod 777 /user/hive
docker exec -it hive-metastore hdfs dfs -chmod 777 /user/hive/warehouse
# 그 폴더를 hdfs 가 소유하고 있어야 hue가 경고를 안함
docker exec -it hive-metastore hdfs dfs -chown hdfs:supergroop /
docker exec -it hive-metastore hdfs dfs -chown hdfs:supergroop /user
docker exec -it hive-metastore hdfs dfs -chown hdfs:supergroop /user/hive
docker exec -it hive-metastore hdfs dfs -chown hdfs:supergroop /user/hive/warehouse
# 테즈를 사용하기 위해서는 tez.tar.gz 파일이 hdfs 에 있어야 yarn 에서 알 수 있음
docker exec -it hive-metastore hdfs dfs -mkdir -p /apps/tez
docker exec -it hive-metastore hdfs dfs -chmod 777 /apps
docker exec -it hive-metastore hdfs dfs -chmod 777 /apps/tez
docker exec -it hive-metastore hdfs dfs -put /opt/tez/share/tez.tar.gz /apps/tez/tez.tar.gz
#######################################################
# 서비스 실행 : hive, nodemanager
# 하이브 메타스토어 실행
# 현재 하이브 메타스토어 컨테이너도 datanode 로써 떠 있는 것이기 때문에, 직접 metastore 를 실행해야 함
docker exec -it hive-metastore bash
# 최초 실행 시 아래와 같이 스키마 초기화를 해줌
$HIVE_HOME/bin/schematool -dbType postgres -initOrUpgradeSchema
# 서비스 실행
$HIVE_HOME/bin/hive --skiphadoopversion --skiphbasecp --service metastore
# 하이브 실행
docker exec -it hiveserver2 bash
$HIVE_HOME/bin/hive --skiphadoopversion --skiphbasecp --service hiveserver2
# yarn에서 리소스를 사용하게 할 노드들에 nodemanager 실행
docker exec -it datanode-1 /opt/hadoop/bin/yarn --config /etc/hadoop nodemanager
docker exec -it datanode-2 /opt/hadoop/bin/yarn --config /etc/hadoop nodemanager
위와 같이 하면 하둡, 하이브, Hue 까지 모두 연동된 하둡 클러스터가 뜨게 됩니다. 이거 한다고 정말 삽질을 많이 했네요. 다음에는 스파크를 추가로 띄워서 하둡 클러스터에서 하이브, 테즈, 스파크 모두 사용할 수 있도록 구축해 보겠습니다.
댓글