JUST WRITE

Trino 한번 써보겠습니다(2) - Hive Metastore와 AWS S3 연결 본문

Data

Trino 한번 써보겠습니다(2) - Hive Metastore와 AWS S3 연결

천재보단범재 2023. 8. 9. 19:26

Hive Metastore와 AWS S3 연결

Trino 한번 써보겠습니다(2)

분산 Query Engine 중 가장 핫한 Trino를 설치해 보았습니다.

 

Trino 한번 써보겠습니다(1) - Kubernetes에 Trino 설치

Trino 한번 써보겠습니다(1) RDB에서 데이터를 조회할 때 SQL를 통해 조회하였습니다. 데이터는 방대해져서 빅데이터가 생겼고, RDB뿐만 아니라 Storage의 종류도 다양해졌습니다. 데이터 조회는 다양

developnote-blog.tistory.com

이제 Data Source에 연결해서 Trino를 통해 데이터를 조회해 보려고 합니다.

이번 시리즈에서 선택한 Data Source는 AWS S3입니다.

  1. Trino 설치
  2. Hive Metastore와 AWS S3 연결
  3. Trino로 CSV 데이터 조회

AWS S3에 CSV 파일을 업로드하고 파일의 데이터를 조회하려고 합니다.

Trino가 AWS S3와 연결하려면 Hive Metastore가 필요합니다.

이번 포스팅에서는 Hive Metastore 세팅과 Trino의 AWS S3 연결을 정리해 보겠습니다.

Hive Metastore 세팅

먼저 Hive Metastore 세팅을 진행하겠습니다.

Binary로 설치할 수도 있지만 Trino도 Kubernetes에 한 김에 Metastore도 Kubernetes에 세팅해 보겠습니다.

Hive Metastore 이미지 생성부터 진행하겠습니다.

Hive Metastore 이미지 생성

Hive Binary 파일로 세팅해도 되지만 Metastore standalone을 따로 Download 할 수 있습니다.

아래 사이트에서 Download 가능하며 이번 포스팅에서는 3.1.3 버전으로 진행하였습니다.

 

Central Repository: org/apache/hive/hive-standalone-metastore

 

repo1.maven.org

Hive Metastore를 실행하기 위해서는 Hadoop이 필요합니다.

Hadoop은 최소 2.6 이상 버전이 필요합니다.

이번 포스팅에서는 Hadoop 3.2.4 버전으로 진행하였습니다.

아래 내용은 $HIVE_METASTORE_HOME/bin/base 파일입니다.

HADOOP=$HADOOP_HOME/bin/hadoop
if [ ! -f ${HADOOP} ]; then
  echo "Cannot find hadoop installation: \$HADOOP_HOME or \$HADOOP_PREFIX must be set or hadoop must be in the path";
  exit 4;
fi

if [ "$SKIP_HADOOPVERSION" = false ]; then
  # Make sure we're using a compatible version of Hadoop
  if [ "x$HADOOP_VERSION" == "x" ]; then
      HADOOP_VERSION=$($HADOOP version 2>&2 | awk -F"\t" '/Hadoop/ {print $0}' | cut -d' ' -f 2);
  fi

  # Save the regex to a var to workaround quoting incompatabilities
  # between Bash 3.1 and 3.2
  hadoop_version_re="^([[:digit:]]+)\.([[:digit:]]+)(\.([[:digit:]]+))?.*$"

  if [[ "$HADOOP_VERSION" =~ $hadoop_version_re ]]; then
      hadoop_major_ver=${BASH_REMATCH[1]}
      hadoop_minor_ver=${BASH_REMATCH[2]}
      hadoop_patch_ver=${BASH_REMATCH[4]}
  else
      echo "Unable to determine Hadoop version information."
      echo "'hadoop version' returned:"
      echo `$HADOOP version`
      exit 5
  fi

  if [ "$hadoop_major_ver" -lt "2" ] || [ "$hadoop_major_ver" -eq "2" -a "$hadoop_minor_ver" -lt "6" ]; then
      echo "Standalone metastore requires Hadoop 2.6 or later."
      echo "'hadoop version' returned:"
      echo `$HADOOP version`
      exit 6
  fi
fi

Hive Metastore 3.1.3과 Hadoop 3.2.4 Binary를 Download 합니다.

그리고 Metastore를 MySQL로 진행하기 위해서 MySQL JDBC를 Download 합니다.

$ wget https://repo1.maven.org/maven2/org/apache/hive/hive-standalone-metastore/3.1.3/hive-standalone-metastore-3.1.3-bin.tar.gz

$ wget https://dlcdn.apache.org/hadoop/common/hadoop-3.2.4/hadoop-3.2.4.tar.gz

$ wget https://repo1.maven.org/maven2/mysql/mysql-connector-java/8.0.27/mysql-connector-java-8.0.27.jar

Dockerfile를 작성합니다.

기본 이미지는 openjdk:11-slim으로 하였습니다.

Hive Metastore는 Java 8 이상 필요합니다.

FROM openjdk:11-slim

RUN apt-get update -y && apt-get install -y curl --no-install-recommends && rm -rf /var/lib/apt/lists/*

COPY hadoop-3.2.4.tar.gz hive-standalone-metastore-3.1.3-bin.tar.gz mysql-connector-java-8.0.27.jar /opt

WORKDIR /opt

RUN tar xzf hadoop-3.2.4.tar.gz && ln -s /opt/hadoop-3.2.4 /opt/hadoop && tar xzf hive-standalone-metastore-3.1.3-bin.tar.gz && ln -s /opt/apache-hive-metastore-3.1.3-bin /opt/hive-metastore && rm /opt/hadoop-3.2.4.tar.gz /opt/hive-standalone-metastore-3.1.3-bin.tar.gz

RUN rm -r /opt/hadoop/share/doc && ln -s /opt/hadoop/share/hadoop/tools/lib/aws-java-sdk-bundle-1.11.901.jar /opt/hadoop/share/hadoop/common/lib/ && ln -s /opt/hadoop/share/hadoop/tools/lib/hadoop-aws-3.2.4.jar /opt/hadoop/share/hadoop/common/lib/

RUN rm /opt/hive-metastore/lib/guava-19.0.jar && cp /opt/hadoop/share/hadoop/common/lib/guava-27.0-jre.jar /opt/hive-metastore/lib

RUN ln -s /opt/mysql-connector-java-8.0.27.jar /opt/hadoop/share/hadoop/common/lib/ && ln -s /opt/mysql-connector-java-8.0.27.jar /opt/hive-metastore/lib/

ENV HADOOP_VERSION=3.2.4 \
	HIVE_METASTORE_VERSION=3.1.3 \
	HADOOP_HOME="/opt/hadoop" \
	PATH="/opt/hadoop/bin:${PATH}"

해당 Dockerfile로 이미지 생성 후 Dockerhub에 push 하였습니다.

$ docker build -t sang1759/hive-metastore:3.1.3 .
$ docker push sang1759/hive-metastore:3.1.3

Kubernetes에 MySQL 세팅

Hive Metastore를 세팅하기 전에 Metastore로 활용할 MySQL를 세팅합니다.

아래 Object들을 생성합니다.

  • Secret -> MySQL Root Password를 저장
  • PersistentVolumeClaim -> MySQL Data를 저장할 PV 생성
  • Deployment -> MySQL Pod
  • Service

secret에 들어가는 MySQL Root Password는 base64로 encoding 한 값을 넣습니다.

apiVersion: v1
kind: Secret
metadata:
  name: mysql-secrets
  namespace: trino
type: Opaque
data:
  ROOT_PASSWORD: cm9vdA==
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-data-vol
  namespace: trino
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql-deployment
  namespace: trino
  labels:
    app: mysql
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
        - name: mysql
          image: mysql:8.0.27
          ports:
            - containerPort: 3306
          volumeMounts:
            - mountPath: "/var/lib/mysql"
              subPath: "mysql"
              name: mysql-data
          env:
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-secrets
                  key: ROOT_PASSWORD
      volumes:
        - name: mysql-data
          persistentVolumeClaim:
            claimName: mysql-data-vol
---
apiVersion: v1
kind: Service
metadata:
  name: mysql-service
  namespace: trino
spec:
  selector:
    app: mysql
  ports:
    - protocol: TCP
      port: 3306
      targetPort: 3306

해당 yaml로 작성해서 MySQL Object들을 생성합니다.

$ kubectl apply -f mysql.yaml
$ kubectl get all -n trino

NAME                                     READY   STATUS    RESTARTS       AGE
pod/mysql-deployment-6948465c44-xrjqc    1/1     Running   0              112s
pod/trino-coordinator-54bf94c5d5-n2ff2   1/1     Running   1 (177m ago)   3h19m
pod/trino-worker-df8c6b8c9-twwt9         1/1     Running   1 (177m ago)   3h20m

NAME                    TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
service/mysql-service   ClusterIP   10.102.96.24     <none>        3306/TCP         112s
service/trino           NodePort    10.110.205.240   <none>        8080:32157/TCP   23d

NAME                                READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/mysql-deployment    1/1     1            1           112s
deployment.apps/trino-coordinator   1/1     1            1           23d
deployment.apps/trino-worker        1/1     1            1           23d

NAME                                           DESIRED   CURRENT   READY   AGE
replicaset.apps/mysql-deployment-6948465c44    1         1         1       112s
replicaset.apps/trino-coordinator-54bf94c5d5   1         1         1       23d
replicaset.apps/trino-worker-df8c6b8c9         1         1         1       23d

NAME                                               REFERENCE                 TARGETS         MINPODS   MAXPODS   REPLICAS   AGE
horizontalpodautoscaler.autoscaling/trino-worker   Deployment/trino-worker   <unknown>/20%   1         3         1          23d

Hive Metastore initSchema

Metastore로 사용할 MySQL까지 세팅하였으면 MySQL에 Metastore에 관련된 schema를 생성해야 합니다.

위에서 생성한 Metastore 이미지와 Kubernetes Job를 통해서 schema를 생성합니다.

apiVersion: batch/v1
kind: Job
metadata:
  name: hive-initschema
  namespace: trino
spec:
  template:
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: app
                    operator: In
                    values:
                      - mysql
              topologyKey: kubernetes.io/hostname
      containers:
        - name: hivemeta
          image: sang1759/hive-metastore:3.1.3
          command: ["/opt/hive-metastore/bin/schematool"]
          args: ["--verbose" ,"-initSchema" , "-dbType", "mysql" , "-userName", "root",
                 "-passWord", "root" , "-url", "jdbc:mysql://mysql-service.trino.svc.cluster.local:3306/metastore_db?createDatabaseIfNotExist=true&connectTimeout=1000"]
      restartPolicy: Never
  backoffLimit: 4

Metastore에서 schematool command가 있습니다.

실행 시 옵션에 방금 세팅한 MySQL 정보를 입력해 줍니다.

작성한 yaml로 Job을 생성합니다.

$ kubectl apply -f init-schema.yaml
$ kubectl get all -n trino

NAME                                     READY   STATUS      RESTARTS        AGE
pod/hive-initschema-fjqgn                0/1     Completed   0               114s
pod/mysql-deployment-6948465c44-xrjqc    1/1     Running     0               30m
pod/trino-coordinator-54bf94c5d5-n2ff2   1/1     Running     1 (3h25m ago)   3h48m
pod/trino-worker-df8c6b8c9-twwt9         1/1     Running     1 (3h25m ago)   3h48m

NAME                    TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
service/mysql-service   ClusterIP   10.102.96.24     <none>        3306/TCP         30m
service/trino           NodePort    10.110.205.240   <none>        8080:32157/TCP   23d

NAME                                READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/mysql-deployment    1/1     1            1           30m
deployment.apps/trino-coordinator   1/1     1            1           23d
deployment.apps/trino-worker        1/1     1            1           23d

NAME                                           DESIRED   CURRENT   READY   AGE
replicaset.apps/mysql-deployment-6948465c44    1         1         1       30m
replicaset.apps/trino-coordinator-54bf94c5d5   1         1         1       23d
replicaset.apps/trino-worker-df8c6b8c9         1         1         1       23d

NAME                                               REFERENCE                 TARGETS         MINPODS   MAXPODS   REPLICAS   AGE
horizontalpodautoscaler.autoscaling/trino-worker   Deployment/trino-worker   <unknown>/20%   1         3         1          23d

NAME                        COMPLETIONS   DURATION   AGE
job.batch/hive-initschema   1/1           76s        114s

Dbeaver로 MySQL에 접속해보면 Metastore관련 Table들이 생성된 것을 확인할 수 있습니다.

AWS S3 접근 유저 생성

Hive Metastore에서 AWS S3에 접근하려면 권한이 필요합니다.

AWS IAM에서 필요한 유저를 생성합니다.

실습이라 AmazonS3 FullAccess 권한을 가진 유저를 생성하였습니다.

유저를 생성한 후에는 액세스 키를 만듭니다.

access-key와 secret-key를 잘 저장해 둡니다.

Metastore Service 생성

이제 Metastore Service를 생성해 보겠습니다.

먼저 2가지 설정파일을 작성합니다.

  • core-site.xml
  • metastore-site.xml
# core-site.xml
<configuration>
    <property>
        <name>fs.defaultFS</name>
        <value>s3a://******</value>
    </property>
    <property>
        <name>fs.s3a.path.style.access</name>
        <value>true</value>
    </property>
    <property>
        <name>fs.s3a.access.key</name>
        <value>******</value>
    </property>
    <property>
        <name>fs.s3a.secret.key</name>
        <value>******</value>
    </property>
    <property>
        <name>fs.s3a.impl</name>
        <value>org.apache.hadoop.fs.s3a.S3AFileSystem</value>
    </property>
    <property>
        <name>fs.s3a.endpoint</name>
        <value>s3.ap-northeast-2.amazonaws.com</value>
    </property>
    <property>
        <name>fs.s3a.fast.upload</name>
        <value>true</value>
    </property>
</configuration>
# metastore-site.xml
<configuration>
  <property>
    <name>metastore.task.threads.always</name>
    <value>org.apache.hadoop.hive.metastore.events.EventCleanerTask</value>
  </property>
  <property>
    <name>metastore.expression.proxy</name>
    <value>org.apache.hadoop.hive.metastore.DefaultPartitionExpressionProxy</value>
  </property>
  <property>
      <name>javax.jdo.option.ConnectionDriverName</name>
      <value>com.mysql.cj.jdbc.Driver</value>
   </property>
   <property>
      <name>javax.jdo.option.ConnectionURL</name>
      <value>jdbc:mysql://mysql-service.trino.svc.cluster.local:3306/metastore_db?useSSL=false&amp;allowPublicKeyRetrieval=true</value>
   </property>
   <property>
      <name>javax.jdo.option.ConnectionUserName</name>
      <value>root</value>
   </property>
   <property>
      <name>javax.jdo.option.ConnectionPassword</name>
      <value>******</value>
   </property>
   <property>
      <name>metastore.warehouse.dir</name>
      <value>s3a://******/warehouse/</value>
   </property>
</configuration>

작성한 2가지 설정파일로 ConfigMap을 생성합니다.

kubectl create configmap metastore-cfg --from-file=metastore-site.xml --from-file=core-site.xml -n trino

그리고 Metastore에 Enviorment로 S3 access-key와 secret-key를 secret으로 생성합니다.

kubectl create secret generic my-s3-keys --from-literal=access-key='******' --from-literal=secret-key='******' -n trino

마지막으로 Hive Metastore의 Deployment와 Service를 생성합니다.

apiVersion: v1
kind: Service
metadata:
  name: metastore
  namespace: trino
spec:
  ports:
  - port: 9083
  selector:
    app: metastore
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: metastore
  namespace: trino
spec:
  selector:
    matchLabels:
      app: metastore
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: metastore
    spec:
      containers:
      - name: metastore
        image: sang1759/hive-metastore:3.1.3
        env:
        - name: AWS_ACCESS_KEY_ID
          valueFrom:
            secretKeyRef:
              name: my-s3-keys
              key: access-key
        - name: AWS_SECRET_ACCESS_KEY
          valueFrom:
            secretKeyRef:
              name: my-s3-keys
              key: secret-key
        ports:
        - containerPort: 9083
        volumeMounts:
        - name: metastore-cfg-vol
          mountPath: /opt/hive-metastore/conf/metastore-site.xml
          subPath: metastore-site.xml
        - name: metastore-cfg-vol
          mountPath: /opt/hadoop/etc/hadoop/core-site.xml
          subPath: core-site.xml
        command: ["/opt/hive-metastore/bin/start-metastore"]
        args: ["-p", "9083"]
        resources:
          requests:
            memory: "2G"
            cpu: 2
        imagePullPolicy: Always
      volumes:
        - name: metastore-cfg-vol
          configMap:
            name: metastore-cfg

생성 후 확인해 봅니다.

$ kubectl apply -f metastore.yaml
$ kubectl get all -n trino
NAME                                     READY   STATUS      RESTARTS        AGE
pod/hive-initschema-fjqgn                0/1     Completed   0               57m
pod/metastore-6c4976766f-lr948           1/1     Running     0               6s
pod/mysql-deployment-6948465c44-xrjqc    1/1     Running     0               86m
pod/trino-coordinator-54bf94c5d5-n2ff2   1/1     Running     1 (4h21m ago)   4h44m
pod/trino-worker-df8c6b8c9-twwt9         1/1     Running     1 (4h21m ago)   4h44m

NAME                    TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
service/metastore       ClusterIP   10.99.186.13     <none>        9083/TCP         6s
service/mysql-service   ClusterIP   10.102.96.24     <none>        3306/TCP         86m
service/trino           NodePort    10.110.205.240   <none>        8080:32157/TCP   23d

NAME                                READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/metastore           1/1     1            1           6s
deployment.apps/mysql-deployment    1/1     1            1           86m
deployment.apps/trino-coordinator   1/1     1            1           23d
deployment.apps/trino-worker        1/1     1            1           23d

NAME                                           DESIRED   CURRENT   READY   AGE
replicaset.apps/metastore-6c4976766f           1         1         1       6s
replicaset.apps/mysql-deployment-6948465c44    1         1         1       86m
replicaset.apps/trino-coordinator-54bf94c5d5   1         1         1       23d
replicaset.apps/trino-worker-df8c6b8c9         1         1         1       23d

NAME                                               REFERENCE                 TARGETS         MINPODS   MAXPODS   REPLICAS   AGE
horizontalpodautoscaler.autoscaling/trino-worker   Deployment/trino-worker   <unknown>/20%   1         3         1          23d

NAME                        COMPLETIONS   DURATION   AGE
job.batch/hive-initschema   1/1           76s        57m

$ kubectl logs -n trino pod/metastore-6c4976766f-lr948
2023-08-09 13:21:42: Starting Metastore Server
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/opt/apache-hive-metastore-3.1.3-bin/lib/log4j-slf4j-impl-2.17.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/opt/hadoop-3.2.4/share/hadoop/common/lib/slf4j-reload4j-1.7.35.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory]
2023-08-09 13:21:46,744 main INFO Log4j appears to be running in a Servlet environment, but there's no log4j-web module available. If you want better web container support, please add the log4j-web JAR to your web archive or server lib director

정리

이번 포스팅에서는 Metastore 이미지를 만들고 Kubernetes에 세팅해 보았습니다.

다음 포스팅에서는 Metastore를 통해 S3에 있는 CSV 파일을 Trino로 조회해 보겠습니다.

[참고사이트]

더보기
728x90
반응형
Comments