Future Tech Blog
フューチャー開発者ブログ

AWS Glueの開発エンドポイントがそこそこお高いのでローカル開発環境を用意しました

  • 村瀬善則

はじめに

こんにちは。TIG DXチームの村瀬です。

AWS Glue利用していますか?ETL処理をする上で大変便利ですよね。しかしながら開発に必要不可欠な開発エンドポイントが少々お高く、もう少し安価に利用できればなーと思っていたところ、さすがAWSさん素敵なリリースをしてくれました。

https://aws.amazon.com/jp/about-aws/whats-new/2019/08/aws-glue-releases-binaries-of-glue-etl-libraries-for-glue-jobs/

AWS Glueとは

過去のこちらの記事もご参考ください。

ローカルPCの環境を汚さない為に

作業を開始する前に確認したところ、Glueバージョン1.0を動かす場合にはSpark2.4.3が必要でそのSparkを動かす為にはJava 8が必要でまたPythonも3.6が必要とのこと。
依存関係が結構ありそうですね。

GlueをローカルPCで動かす為にJavaやPythonのバージョン変えるの嫌だなぁ。チームメンバーも嫌がるだろうし環境構築の為の手順用意するの面倒だしトラブった時に対応したくないなと思ったのでローカルPCの環境を汚さないように今回はDockerで用意してみることにしました。

https://docs.aws.amazon.com/ja_jp/glue/latest/dg/aws-glue-programming-etl-libraries.html
を参考にPython,Java,Glueライブラリ,Maven,Glueアーティファクトを取得・インストールするよう記載したDockerfileを用意して実行してみると…
(※Dockerfileは後ほど出てきます)

ハマリポイント

./aws-glue-libs/bin/gluepyspark 実行時にエラー発生

1
2
3
4
5
6
7
8
9
10
11
12
13
~中略~
py4j.protocol.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)

すんなり行きませんでした。
エラーを確認するとio.netty.buffer.PooledByteBufAllocator.defaultNumHeapArena()なんて無いよと言われていますね。

無いと言われているものを探してみます。
find / -name *netty*

1
2
3
4
5
6
7
8
9
10
11
12
/opt/spark-2.4.3-bin-spark-2.4.3-bin-hadoop2.8/jars/netty-3.9.9.Final.jar
/opt/spark-2.4.3-bin-spark-2.4.3-bin-hadoop2.8/jars/netty-all-4.1.17.Final.jar
~中略~
/aws-glue-libs/jarsv1/netty-3.6.2.Final.jar
/aws-glue-libs/jarsv1/netty-all-4.0.23.Final.jar
/aws-glue-libs/jarsv1/netty-buffer-4.1.17.Final.jar
/aws-glue-libs/jarsv1/netty-codec-4.1.17.Final.jar
/aws-glue-libs/jarsv1/netty-codec-http-4.1.17.Final.jar
/aws-glue-libs/jarsv1/netty-common-4.1.17.Final.jar
/aws-glue-libs/jarsv1/netty-handler-4.1.17.Final.jar
/aws-glue-libs/jarsv1/netty-resolver-4.1.17.Final.jar
/aws-glue-libs/jarsv1/netty-transport-4.1.17.Final.jar

???
いっぱい見つかりますね。

先人の知恵を借りましょう。
stackoverflow Spark 2.3 java.lang.NoSuchMethodError: io.netty.buffer.PooledByteBufAllocator.metric

どうやらNettyのjarのバージョンが合ってないことが原因のようです。
改めて比較して確認してみるとspark側のjarのバージョンの方が新しいですね。

spark
1
2
/netty-3.9.9.Final.jar
/netty-all-4.1.17.Final.jar
aws-glue-libs
1
2
/netty-3.6.2.Final.jar
/netty-all-4.0.23.Final.jar

またまた先人の知恵を借りましょう。
GitHub gluepyspark errors on local development #25

どうやらaws-glue-libsを参照せずにsparkのjarファイルを参照すれば良いようです。
ln -s ${SPARK_HOME}/jars /aws-glue-libs/jarsv1

これでdocker buildがエラーなく成功し、docker runした上でdocker execでコンテナに入り、この状態で以下のコマンドを実行すると
./aws-glue-libs/bin/gluepyspark

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
~中略~
19/10/25 09:58:38 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
Using Spark's default log4j profile: org/apache/spark/log4j-defaults.properties
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.8 (default, Aug 7 2019 17:28:10)
SparkSession available as 'spark'.
>>>

無事にSparkを起動することができました。

Dockerfile

みんなお待ちかねのDockerファイルはこちら

Dockerfile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
FROM centos:7
MAINTAINER Future y.murase

# https://omohikane.com/centos7_docker_python36/ を参考にpythonとjavaをインストール

RUN yum install -y bzip2 bzip2-devel gcc gcc-c++ make openssl-devel readline-devel zlib-devel wget curl unzip vim epel-release git && yum install -y tig jq vim-enhanced bash-completion net-tools bind-utils \
&& yum install -y https://centos7.iuscommunity.org/ius-release.rpm \
&& yum install -y python36u python36u-libs python36u-devel python36u-pip \
&& yum install -y java java-1.8.0-openjdk-devel \
&& rm -rf /var/cache/yum/*

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

# Glueライブラリ取得

RUN git clone -b glue-1.0 --depth 1 https://github.com/awslabs/aws-glue-libs

# Maven取得

RUN curl -OL https://archive.apache.org/dist/maven/maven-3/3.6.2/binaries/apache-maven-3.6.2-bin.tar.gz
RUN tar -xzvf apache-maven-3.6.2-bin.tar.gz
RUN mv apache-maven-3.6.2 /opt/
RUN ln -s /opt/apache-maven-3.6.2 /opt/apache-maven
ENV JAVA_HOME /usr/lib/jvm/java-1.8.0-openjdk/jre/
ENV PATH $PATH:/opt/apache-maven/bin
RUN mvn -version

# Glueアーティファクト取得

RUN curl -OL https://aws-glue-etl-artifacts.s3.amazonaws.com/glue-1.0/spark-2.4.3-bin-hadoop2.8.tgz
RUN tar -xzvf spark-2.4.3-bin-hadoop2.8.tgz
RUN mv spark-2.4.3-bin-spark-2.4.3-bin-hadoop2.8 /opt/
RUN ln -s /opt/spark-2.4.3-bin-spark-2.4.3-bin-hadoop2.8 /opt/spark
ENV SPARK_HOME /opt/spark

# Python3.6を利用する設定

RUN unlink /bin/python
RUN ln -s /bin/python3 /bin/python
RUN ln -s /bin/pip3.6 /bin/pip

# 異なるバージョンのjarがsparkとglueに混在するので適切なバージョンのみを見るよう設定

RUN ln -s ${SPARK_HOME}/jars /aws-glue-libs/jarsv1

RUN ./aws-glue-libs/bin/gluepyspark

ENTRYPOINT ["/bin/sh", "-c", "while :; do sleep 10; done"]

まとめ

少々苦労しましたが先人の知恵を借りて問題解決できました。
これで複数いる開発メンバーにDockerイメージさえ渡せばローカル環境を汚すことなく簡単にかつお財布にやさしくローカルPCにGlueの開発環境が用意できますね。
Glueのローカル開発環境構築にチャレンジしたけどエラーが出て諦めてしまった人の手助けになれたら幸いです。

なお、この記事を作成する上で以下のページを参考にさせていただきました。
https://aws.amazon.com/jp/about-aws/whats-new/2019/08/aws-glue-releases-binaries-of-glue-etl-libraries-for-glue-jobs/
https://docs.aws.amazon.com/ja_jp/glue/latest/dg/aws-glue-programming-etl-libraries.html
https://omohikane.com/centos7_docker_python36/
https://stackoverflow.com/questions/50388919/spark-2-3-java-lang-nosuchmethoderror-io-netty-buffer-pooledbytebufallocator-me
https://github.com/awslabs/aws-glue-libs/issues/25


関連記事: