フューチャー技術ブログ

AWS Glueの開発環境の構築(2021)

概要

AWS Glueの環境構築は過去の記事にあるのですが、公式のDockerイメージが案内されているので改めて、構築してみます。

なお、Glueの公式イメージでもJupyter Notebookは利用できるのですが、使い勝手を考慮し、Jupyterlabに差し替えています。

手順

  1. Dockerfile作成
  2. docker-compose.yml作成
  3. 動作確認

Dockerfile

PySparkのオプションを設定しつつ、gluepysparkを実行していますが、gluepysparkPySparkのwrapperになっているため、こちらの設定で問題なく動作しています。

Dockerfile
# ベースとなる公式イメージ
FROM amazon/aws-glue-libs:glue_libs_1.0.0_image_01

# jupyterlabインストール
RUN pip install jupyterlab

# 起動スクリプト
COPY jupyter_start.sh /home/jupyter
RUN chmod 775 /home/jupyter/jupyter_start.sh

ENV PATH $PATH:/home/aws-glue-libs/bin/:/usr/share/maven/bin:${SPARK_HOME}/bin/
ENV PYTHONPATH $PYTHONPATH:/home/jupyter/jupyter_default_dir

# PySparkからjupyter labを起動するためのオプション設定
ENV PYSPARK_DRIVER_PYTHON jupyter
ENV PYSPARK_DRIVER_PYTHON_OPTS ' lab --allow-root --NotebookApp.token="" --NotebookApp.password="" --no-browser --ip=0.0.0.0'

# dummy
RUN mkdir ~/.aws
COPY aws/config /root/.aws
RUN chmod 600 ~/.aws/config
COPY aws/credentials /root/.aws
RUN chmod 600 ~/.aws/credentials

Dockerfileでコピーしているファイルです。

jupyter_start.sh
#!/bin/bash
/home/aws-glue-libs/bin/gluepyspark
.aws/config
[default]
region = ap-northeast-1
output = json
.aws/credentials
[default]
aws_access_key_id = xxx
aws_secret_access_key = xxx

docker-compose.yml

line10 で、jupyterlabのdefaultのWorkspaceにlocalをマウントしています。
S3(localstack)にアップロードするファイルやソースコードの同期を取ります。

docker-compsoe.yml
version: '3.5'
services:
glue.dev.summary:
container_name: glue.dev
build:
context: ./
dockerfile: ./Dockerfile
volumes:
# jupyterlabのdefaultのWorkspaceにlocalファイルをマウントします。
- ./:/home/jupyter/jupyter_default_dir
environment:
# dummy configure
- AWS_DEFAULT_REGION=ap-northeast-1
- AWS_DEFAULT_OUTPUT=json
- AWS_ACCESS_KEY_ID=xxx
- AWS_SECRET_ACCESS_KEY=xxx
ports:
# jupyterlabのポート
- 8888:8888
# spark uiのポート
- 4040:4040
networks:
- glue.dev.network
command: /home/jupyter/jupyter_start.sh
glue.dev.s3.local:
image: localstack/localstack:0.12.8
environment:
- SERVICES=s3
# dummy configure
- AWS_DEFAULT_REGION=ap-northeast-1
- AWS_DEFAULT_OUTPUT=json
- AWS_ACCESS_KEY_ID=xxx
- AWS_SECRET_ACCESS_KEY=xxx
networks:
- glue.dev.network
networks:
glue.dev.network:
name: glue.dev.network

Docker 起動

docker-compose up --build

動作確認(準備)

Glue/localstack(s3)を初期化し、dynamic frameで取り込んだファイルをdata frameに変換して、spark sqlを実行します。
こちらのスクリプトをjupyterlabで動かします。

import sys
import os
import io
import csv
import boto3
from pyspark.context import SparkContext
from awsglue.context import GlueContext
from awsglue.job import Job
from awsglue.dynamicframe import DynamicFrame
from botocore.client import Config

# glue Initialize
os.environ["TEST_S3_ENDPOINT_URL"] = "http://gule.dev.s3.local:4566"
glueContext = GlueContext(sc)
spark = glueContext.spark_session
job = Job(glueContext)
job.init("JobName")


# Set S3 with localstack parameters
sc._jsc.hadoopConfiguration().set("fs.s3a.endpoint", "http://gule.dev.s3.local:4566")
sc._jsc.hadoopConfiguration().set("fs.s3a.path.style.access", "true")
sc._jsc.hadoopConfiguration().set("fs.s3a.signing-algorithm", "S3SignerType")

# S3 init
s3 = boto3.resource(
"s3",
endpoint_url=os.environ["TEST_S3_ENDPOINT_URL"],
region_name="ap-northeast-1",
use_ssl=False,
config=Config(s3={"addressing_style": "path"}),
)
bucket_name = "test-csv-bucket"
bucket = s3.Bucket(bucket_name)
bucket.create(ACL="public-read-write")

# get dynamic frame and data frame convert
bucket.upload_file("tests/data/sample.json", "sample/sample.json")
p = "s3://test-csv-bucket/sample/".format("input-tables", f"sample.json")
df = glueContext.create_dynamic_frame.from_options(
connection_type="s3",
connection_options={"paths": [p]},
format="json",
).toDF()
df.count()
df.show()

# spark sql exec
df.createOrReplaceTempView("sample")
spark.sql("show tables").show()
spark.sql("select count(*) from sample").show()
spark.sql("select * from sample").show()

動作確認

ブラウザより、http://localhost:8888 を実装し、jupyterlabで動かします。

docker-compose.yml でマウントしたlocalストレージにtests/data/sample.jsonを用意して、実行してみます。
せっかくなので、処理ブロック単位に動かします。

jupyterlabでの操作動画

所感

ローカルでAWSに依存せず、GlueのAPIをインタラクティブに確認できるので、開発効率としては良いのではないでしょうか。