AWS Glue ETLライブラリにて、ローカルPCにGlue開発環境をつくる
aws-glue-libs を利用するば、ローカルPC上でGlue開発環境を用意できるとのこと、試してみます。
aws-glue-libs
This repository contains libraries used in the AWS Glue service. These libraries extend Apache Spark with additional data types and operations for ETL workflows. They are used in code generated by the AWS Glue service and can be used in scripts submitted with Glue jobs.
下記のマニュアルを参考にしています。
AWS Glue ETLライブラリを使用したETLスクリプトのローカルでの開発とテスト
利用可能Glueバージョン
aws-glue-libsでは、以下バージョンのGlue環境を作成できます。
Glue | Spark | Python |
---|---|---|
0.9 | 2.2.1 | 2.7 |
1.0 | 2.4.3 | 2.7 3.6 |
今回はGlue1.0の環境を、Python3.6を使って用意してみます。
環境作成
Dockerfileを作成しているので、実際に必要となる処理については、Dockerfile内の記載を確認してください。
FROM centos:7 # python 3.6.9 WORKDIR /usr/local RUN yum -y update && yum -y groupinstall --skip-broken "Development tools" \ && yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel bsdtar git \ && rm -rf /var/cache/yum/* \ && yum clean all \ && curl -fsSL https://www.python.org/ftp/python/3.6.9/Python-3.6.9.tar.xz -o /usr/local/Python-3.6.9.tar.xz \ && tar -Jxf /usr/local/Python-3.6.9.tar.xz \ && rm -rf /usr/local/Python-3.6.9.tar.xz \ && cd /usr/local/Python-3.6.9/ \ && ./configure --prefix=/usr/local/python369 --with-ensurepip=install --enable-optimizations \ && make && make install && make clean # java 1.8.0 RUN yum -y install java-1.8.0-openjdk java-1.8.0-openjdk-devel \ && rm -rf /var/cache/yum/* \ && yum clean all ENV JAVA_HOME /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.232.b09-0.el7_7.x86_64/jre # glue-common/apache-maven-3.6.0 WORKDIR /opt RUN curl -fsSL https://aws-glue-etl-artifacts.s3.amazonaws.com/glue-common/apache-maven-3.6.0-bin.tar.gz -o /opt/apache-maven-3.6.0-bin.tar.gz \ && tar -xzvf /opt/apache-maven-3.6.0-bin.tar.gz \ && rm -f /opt/apache-maven-3.6.0-bin.tar.gz ENV PATH $PATH:/opt/apache-maven-3.6.0/bin # glue-1.0/spark-2.4.3 RUN curl -fsSL https://aws-glue-etl-artifacts.s3.amazonaws.com/glue-1.0/spark-2.4.3-bin-hadoop2.8.tgz -o /opt/spark-2.4.3-bin-hadoop2.8.tgz \ && bsdtar -xzvf /opt/spark-2.4.3-bin-hadoop2.8.tgz \ && rm -f /opt/spark-2.4.3-bin-hadoop2.8.tgz ENV SPARK_HOME /opt/spark-2.4.3-bin-spark-2.4.3-bin-hadoop2.8 # aws-glue-libs RUN git clone -b glue-1.0 https://github.com/awslabs/aws-glue-libs ENV PATH $PATH:/opt/aws-glue-libs/bin RUN unlink /bin/python \ && ln -s /usr/local/python369/bin/python3 /bin/python \ && ln -s /usr/local/python369/bin/pip3 /bin/pip RUN localedef -f UTF-8 -i ja_JP ja_JP.UTF-8 ENV LANG "ja_JP.UTF-8" ENV LC_CTYPE "ja_JP.UTF-8" ENV LC_NUMERIC "ja_JP.UTF-8" ENV LC_TIME "ja_JP.UTF-8" ENV LC_COLLATE "ja_JP.UTF-8" ENV LC_MONETARY "ja_JP.UTF-8" ENV LC_MESSAGES "ja_JP.UTF-8" ENV LC_PAPER "ja_JP.UTF-8" ENV LC_NAME "ja_JP.UTF-8" ENV LC_ADDRESS "ja_JP.UTF-8" ENV LC_TELEPHONE "ja_JP.UTF-8" ENV LC_MEASUREMENT "ja_JP.UTF-8" ENV LC_IDENTIFICATION "ja_JP.UTF-8" ENV LC_ALL "ja_JP.UTF-8" # aws cli RUN pip install awscli ENV PATH $PATH:/usr/local/python369/bin # https://github.com/awslabs/aws-glue-libs/issues/25 RUN ln -s ${SPARK_HOME}/jars /opt/aws-glue-libs/jarsv1 RUN /opt/aws-glue-libs/bin/gluepyspark
pythonをmake installしてるのと、mavenの処理で、buildにすっごい時間がかかります。
トラブルシューティング
gluepyspark
コマンド実行時に、以下のエラーが出てきて正常にpysparkが起動してくれず、困りました。
Py4JJavaError: An error occurred while calling None.org.apache.spark.api.java.JavaSparkContext. : java.lang.NoSuchMethodError: io.netty.buffer.PooledByteBufAllocator.defaultNumHeapArena()I at org.apache.spark.network.util.NettyUtils.createPooledByteBufAllocator(NettyUtils.java:113) at org.apache.spark.network.client.TransportClientFactory.<init>(TransportClientFactory.java:106) at org.apache.spark.network.TransportContext.createClientFactory(TransportContext.java:99) at org.apache.spark.rpc.netty.NettyRpcEnv.<init>(NettyRpcEnv.scala:71) at org.apache.spark.rpc.netty.NettyRpcEnvFactory.create(NettyRpcEnv.scala:461) at org.apache.spark.rpc.RpcEnv$.create(RpcEnv.scala:57) at org.apache.spark.SparkEnv$.create(SparkEnv.scala:249) at org.apache.spark.SparkEnv$.createDriverEnv(SparkEnv.scala:175) at org.apache.spark.SparkContext.createSparkEnv(SparkContext.scala:257) at org.apache.spark.SparkContext.<init>(SparkContext.scala:424) at org.apache.spark.api.java.JavaSparkContext.<init>(JavaSparkContext.scala:58) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at py4j.reflection.MethodInvoker.invoke(MethodInvoker.java:247) at py4j.reflection.ReflectionEngine.invoke(ReflectionEngine.java:357) at py4j.Gateway.invoke(Gateway.java:238) at py4j.commands.ConstructorCommand.invokeConstructor(ConstructorCommand.java:80) at py4j.commands.ConstructorCommand.execute(ConstructorCommand.java:69) at py4j.GatewayConnection.run(GatewayConnection.java:238) at java.lang.Thread.run(Thread.java:748)
そのため、Dockerfile内で以下の記載を追加しています。
RUN ln -s ${SPARK_HOME}/jars /opt/aws-glue-libs/jarsv1
以下を参考にしています。
gluepyspark errors on local development
AWS Glueの開発エンドポイントがそこそこお高いのでローカル開発環境を用意しました
コンテナ起動
作成したイメージを起動します。ローカルPCにあるDocker-machine上で起動することを想定しています。
コンテナ起動時に、AWSの認証情報(IAMユーザのアクセスキー)を渡してあげることになります。なので、そのためのENVファイルを用意しておきます。下記みたくですね。Glue開発環境で利用される認証情報のため、Glue Data CatalogやS3への権限をもたせてあげてください。
AWS_ACCESS_KEY_ID=XXXXXXXXXXXXXXXXXXXXXX AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXXXXXXXXX AWS_REGION=ap-northeast-1
コンテナ起動します。
> docker run -itd --name glue --env-file (envfile) -v /c/Users/zunda/Desktop/volume:/mnt/volume (image) /bin/bash
コンテナに入ると、Glue環境のSparkを利用可能となります。
> docker exec -it (container_id) /bin/bash $ gluepyspark ... ... Setting default log level to "WARN". To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel). Welcome to ____ __ / __/__ ___ _____/ /__ _\ \/ _ \/ _ `/ __/ '_/ /__ / .__/\_,_/_/ /_/\_\ version 2.4.3 /_/ Using Python version 3.6.9 (default, Nov 29 2019 11:08:08) SparkSession available as 'spark'. >>> import sys >>> from awsglue.transforms import * >>> from awsglue.utils import getResolvedOptions >>> from pyspark.context import SparkContext >>> from awsglue.context import GlueContext >>> >>> glueContext = GlueContext(SparkContext.getOrCreate()) >>> voiceloid = glueContext.create_dynamic_frame.from_catalog( database="voiceloid", table_name="classifier_voiceloid") >>> voiceloid.printSchema() root |-- voiceroid_id: long |-- name: string |-- japanese_name: string >>>