クラスメソッドのAWS Glueをローカル環境で実行してみた をやってみましたが、バージョン違いの設定で大変でした。二年半くらい経っているから当然なのかも。以下、エラー回避のメモ。
うまく行ったときのバージョン
- Ubuntu 20.04
- Python 3.7
- aws-cli/2.4.11
- Apach maven 3.6.3
- Java java-8-openjdk-amd64
- Apach Spark spark-2.4.3-bin-hadoop2.8
- LocalStack 0.14.0
- docker-compose version 1.29.2
https://github.com/localstack/localstack
https://github.com/awslabs/aws-glue-libs
https://docs.aws.amazon.com/ja_jp/glue/latest/dg/aws-glue-programming-etl-libraries.html#develop-local-python
SPARK
対応するバージョンをダウンロードして、SPARK_HOMEを設定するだけでよい。
SPARK_HOME=自分のフォルダ.../spark-2.4.3-bin-spark-2.4.3-bin-hadoop2.8
aws-glue-libs
glueのバージョンに合わせてブランチを選んでclone
https://github.com/awslabs/aws-glue-libs
ここでは、フォルダ名を変えている。/aws-glue-libs-2.0/
LocalStack
こちらを参考にした。
https://zenn.dev/s_ryuuki/articles/412b5f004595b7
awslocalを使う
endpointを解決してくれるので便利
--endpoint-url http://localhost:45xx という指定を省いてよい。
https://github.com/localstack/awscli-local
--profile localstack を使って以下のようなコマンドで操作
awslocal dynamodb create-table \
--table-name aws-glue-local-test-table \
--attribute-definitions \
AttributeName=Id,AttributeType=S \
--key-schema AttributeName=Id,KeyType=HASH \
--provisioned-throughput ReadCapacityUnits=1,WriteCapacityUnits=1 \
--profile localstack
awslocal dynamodb put-item \
--table-name aws-glue-local-test-table \
--item \
'{"Id": {"S": "test"}, "Column1": {"S": "test1"}, "Column2": {"S": "test2"}, "Column3": {"S": "test3"}}' \
--profile localstack
awslocal s3api create-bucket \
--bucket aws-glue-local-test-bucket \
--profile localstack
awslocal s3api list-buckets \
--profile localstack
awslocal s3api list-objects \
--bucket aws-glue-local-test-bucket \
--profile localstack
エンドポイントが合っていないというエラー
あとでも出てくる
Connection was closed before we received a valid response from endpoint URL:
"http://localhost:4572/aws-glue-local-test-bucket".
ports:
- "4566:4566"
- "4571:4571"
にするとできた。
4566は全てのサービスのポート?TODO
OKのとき
docker container ls
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
89b2de708a51 localstack/localstack "docker-entrypoint.sh" 2 minutes ago Up 2 minutes 0.0.0.0:4566->4566/tcp, 4510-4559/tcp, 5678/tcp, 0.0.0.0:4571->4571/tcp localstack
NGのとき
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b7a6a3bf62f6 localstack/localstack "docker-entrypoint.sh" 53 seconds ago Up 49 seconds 4510-4559/tcp, 0.0.0.0:4569->4569/tcp, 4566/tcp, 0.0.0.0:4572->4572/tcp, 5678/tcp, 0.0.0.0:8080->8080/tcp localstack
実行
./bin/gluesparksubmit ./src/sample.py --JOB_NAME='dummy'
最初はGlue ETLライブラリのバイナリをダウンロードするので時間かかる。
37分だった。
logが多数でるが、INFO、WARNは軽く読んでERRORに対処する。
WARNだとこういうのもあったが無視した。
https://aws.amazon.com/jp/premiumsupport/knowledge-center/ec2-expired-token/
JDKが入っていないので、/jre/tools.jarがないというエラー
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 37:51 min
[INFO] Finished at: 2022-02-17T11:07:06+09:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal on project AWSGlueETLPython: Could not resolve dependencies for project com.amazonaws:AWSGlueETLPython:jar:3.0.0: Could not find artifact jdk.tools:jdk.tools:jar:1.8 at specified path /usr/lib/jvm/java-8-openjdk-amd64/jre/../lib/tools.jar -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/DependencyResolutionException
インストールする
sudo apt-get install openjdk-8-jdk
確認
/usr/lib/jvm/java-8-openjdk-amd64$ find ./ -type f | grep tools
./lib/tools.jar が出るはず
BUILDは成功するがその後でエラー
再実行。同じコマンド(./bin/gluesparksubmit ./src/sample.py
--JOB_NAME='dummy')で
2分くらいでできた。
sample.pyでjob.initがおかしいらしい
22/02/17 12:58:57 INFO BlockManagerMaster: Registered BlockManager
BlockManagerId(driver, 192.168.10.105, 41321, None)
22/02/17 12:58:57 INFO BlockManager: Initialized BlockManager:
BlockManagerId(driver, 192.168.10.105, 41321, None)
22/02/17 12:58:57 INFO GlueContext: GlueMetrics not configured
22/02/17 12:58:57 INFO GlueContext: fs.s3.impl hadoop configuration is not
set. Setting fs.s3.impl to org.apache.hadoop.fs.s3a.S3AFileSystem
Traceback (most recent call last):
File ".../aws-glue-libs/./src/sample.py", line 19, in <module>
job.init(JOB_NAME, args)
File ".../aws-glue-libs/PyGlue.zip/awsglue/job.py", line 42, in init
File
"/home/shimo/Desktop/app/spark-2.2.1-bin-hadoop2.7/python/lib/py4j-0.10.4-src.zip/py4j/java_gateway.py",
line 1133, in __call__
File
"/home/shimo/Desktop/app/spark-2.2.1-bin-hadoop2.7/python/lib/pyspark.zip/pyspark/sql/utils.py",
line 63, in deco
File
"/home/shimo/Desktop/app/spark-2.2.1-bin-hadoop2.7/python/lib/py4j-0.10.4-src.zip/py4j/protocol.py",
line 319, in get_return_value
py4j.protocol.Py4JJavaError: An error occurred while calling
z:com.amazonaws.services.glue.util.Job.init.
: java.lang.NoSuchMethodError: scala.Product.$init$(Lscala/Product;)V
tokenがエラー( The security token included in the request is invalid)
An error occurred (UnrecognizedClientException) when calling the CreateTable
operation: The security token included in the request is invalid.
これは認証というよりエンドポイントの問題だった
Python2.7, glue 0.9にしたがNG
sudo pip2 install pyspark
Python2.7用にしようかとglue0.9を入れたりしたが、submit実行してもうまく行かず。このエラーのdynamicframeが見つからないというのは、モジュールのルートの選択がおかしいようですが、いまいち進めず。
rm: cannot remove '.../aws-glue-libs-0.9/conf/spark-defaults.conf': No such
file or directory
.../aws-glue-libs-0.9
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in
[jar:file:.../aws-glue-libs-0.9/jars/slf4j-log4j12-1.7.10.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in
[jar:file:/home/shimo/Desktop/app/spark-2.2.1-bin-hadoop2.7/jars/slf4j-log4j12-1.7.16.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.slf4j.impl.Log4jLoggerFactory]
Using Spark's default log4j profile:
org/apache/spark/log4j-defaults.properties
22/02/17 14:06:58 WARN Utils: Your hostname, v3268 resolves to a loopback
address: 127.0.1.1; using 192.168.10.105 instead (on interface enp2s0)
22/02/17 14:06:58 WARN Utils: Set SPARK_LOCAL_IP if you need to bind to
another address
Traceback (most recent call last):
File ".../aws-glue-libs-0.9/./src/sample.py", line 2, in
<module>
from awsglue.transforms import ApplyMapping
File ".../aws-glue-libs-0.9/PyGlue.zip/awsglue/__init__.py", line 13,
in <module>
ModuleNotFoundError: No module named 'dynamicframe'
awsglue2.0, Python3.7にする
改めてやり直して実行してエラー。
22/02/17 15:30:31 WARN EC2MetadataUtils: Unable to retrieve the requested
metadata (/latest/dynamic/instance-identity/document). Failed to connect to
service endpoint:
com.amazonaws.SdkClientException: Failed to connect to service endpoint:
22/02/17 15:49:35 ERROR Executor: Exception in task 0.0 in stage 0.0 (TID 0)
java.lang.RuntimeException: Could not lookup table aws-glue-local-test-table
in DynamoDB.
この一文によると、us-east-1にアクセスしている→これはエンドポイントの指定ができていないときのデフォルトだった
22/02/17 15:49:34 INFO DynamoDBUtil: Using endpoint for DynamoDB:
dynamodb.us-east-1.amazonaws.com
spark-defaults.confを正しく設定すると動いた
あれこれエラーが出ていたけど、これで直った。(他にも効いているかもしれないけど)
confにポートの情報を入れているけど、上書きされて消えている
.../aws-glue-libs-2.0/conf/spark-defaults.conf
bin/glue-setup.shがconfファイルをいじっているようなので、ここらへんをコメントアウト
mkdir $SPARK_CONF_DIR
rm $SPARK_CONF_DIR/spark-defaults.conf
Generate spark-defaults.conf
echo "spark.driver.extraClassPath $GLUE_JARS_DIR/*"
>>$SPARK_CONF_DIR/spark-defaults.conf
echo "spark.executor.extraClassPath $GLUE_JARS_DIR/*"
>>$SPARK_CONF_DIR/spark-defaults.conf
docker-compose.ymlのポート部分を変えている
version: "3.3"
services:
localstack:
container_name: localstack
image: localstack/localstack
ports:
- "4566:4566"
- "4571:4571"
environment:
- DOCKER_HOST=unix:///var/run/docker.sock
- DEFAULT_REGION=ap-northeast-1
- SERVICES=dynamodb,s3
spark-defaults.conf
はこうしておく
spark.hadoop.dynamodb.endpoint http://localhost:4566
spark.hadoop.fs.s3a.endpoint http://localhost:4566
spark.hadoop.fs.s3a.path.style.access true
spark.hadoop.fs.s3a.signing-algorithm S3SignerType
どちらもlocalhost:4566 にした。他のポートでもできるのかもTODO