HAQM Web Services ブログ

Docker コンテナを使って AWS Glue 5.0 のジョブをローカルで開発・テストする

AWS Glue は、さまざまなデータソースからのデータを大規模に処理・統合できるサーバーレスのデータ統合サービスです。Apache Spark ジョブ用の最新バージョンである AWS Glue 5.0 は、バッチ処理とストリーム処理に最適化された Apache Spark 3.5 ランタイム環境を提供します。AWS Glue 5.0 を使えば、パフォーマンスの向上、セキュリティの強化、次世代の HAQM SageMaker のサポート、その他の機能強化が得られます。AWS Glue 5.0 により、データ統合ワークロードの開発、実行、スケーリングが可能になり、より迅速にインサイトを得られるようになります。

AWS Glue は、複数のジョブ作成アプローチを通じて、さまざまな開発方法に対応しています。ダイレクトコーディングがお好きな開発者の方は、AWS Glue ETL ライブラリを使用した Python または Scala での開発が可能です。

本番環境に耐えうるデータプラットフォームを構築するには、堅牢な開発プロセスと継続的インテグレーションおよびデリバリー (CI/CD) パイプラインが必要です。ローカルマシン、HAQM Elastic Compute Cloud (HAQM EC2) 上の Docker コンテナ、その他の環境など、さまざまな開発ニーズに対応するため、AWS は HAQM ECR Public Gallery を通じて公式の AWS Glue Docker イメージを提供しています。このイメージにより、開発者の方は AWS Glue ETL ライブラリを使用しながら、お好きな環境で効率的に作業できます。

この記事では、Docker コンテナを使用して AWS Glue 5.0 ジョブをローカルで開発およびテストする方法を示します。この記事は、Develop and test AWS Glue version 3.0 and 4.0 jobs locally using a Docker container の更新版で、AWS Glue 5.0 を使用しています。

利用可能な Docker イメージ

以下の Docker イメージが HAQM ECR Public Gallery で利用可能です:

  • AWS Glue バージョン 5.0ecr.aws/glue/aws-glue-libs:5

AWS Glue の Docker イメージは、x86_64arm64 の両方に対応しています。

この記事では、public.ecr.aws/glue/aws-glue-libs:5 を使用し、コンテナをローカルマシン (Mac、Windows、Linux) 上で実行します。このコンテナイメージは、AWS Glue 5.0 の Spark ジョブでテストされています。このイメージには以下が含まれています。

コンテナをセットアップするには、ECR Public Gallery からイメージを pull し、コンテナを実行します。要件に応じて、次の方法でコンテナの実行方法を示します:

  • spark-submit
  • REPL シェル (pyspark)
  • pytest
  • Visual Studio Code

前提条件

始める前に、Docker がインストールされていて Docker デーモンが実行中であることを確認してください。インストール手順については、MacWindows、または Linux 向けの Docker ドキュメントを参照してください。また、Docker を実行しているホストに少なくとも 7GB のディスク領域があることを確認してください。

AWS 認証情報の設定

コンテナから AWS API 呼び出しを有効にするには、次の手順で AWS 認証情報を設定します。

  1. AWS 名前付きプロファイルを作成します。
  2. Windows では cmd を、Mac/Linux では端末を開き、次のコマンドを実行します:
PROFILE_NAME="profile_name"

次のセクションでは、この AWS 名前付きプロファイルを使用します。

ECR Public Gallery からイメージを pull

Docker を Windows で実行している場合は、イメージを pull する前に Docker アイコンを右クリックし、Linux コンテナに切り替えるを選択してください。

ECR Public Gallery からイメージを pull するには、次のコマンドを実行してください:

docker pull public.ecr.aws/glue/aws-glue-libs:5

コンテナの実行

これで、このイメージを使ってコンテナを実行できます。要件に応じて、以下のいずれかの方法を選択できます。

spark-submit

AWS Glue ジョブスクリプトは、コンテナ上で spark-submit コマンドを実行することで実行できます。

ジョブスクリプト (sample.py の例) を書き、次のコマンドを使って /local_path_to_workspace/src/ ディレクトリに保存してください:

$ WORKSPACE_LOCATION=/local_path_to_workspace 
$ SCRIPT_FILE_NAME=sample.py 
$ mkdir -p ${WORKSPACE_LOCATION}/src 
$ vim ${WORKSPACE_LOCATION}/src/${SCRIPT_FILE_NAME}

これらの変数は、次の docker run コマンドで使用されます。spark-submit コマンドで使用されるサンプルコード (sample.py) は、この記事の最後の Appendix に含まれています。

次のコマンドを実行して、コンテナ上で spark-submit コマンドを実行し、新しい Spark アプリケーションを送信します:

$ docker run -it --rm \ 
    -v ~/.aws:/home/hadoop/.aws \ 
    -v $WORKSPACE_LOCATION:/home/hadoop/workspace/ \ 
    -e AWS_PROFILE=$PROFILE_NAME \ 
    --name glue5_spark_submit \ 
    public.ecr.aws/glue/aws-glue-libs:5 \ 
    spark-submit /home/hadoop/workspace/src/$SCRIPT_FILE_NAME

REPL シェル (pyspark)

REPL (read-eval-print loop) シェルを使用すると、インタラクティブな開発ができます。コンテナ上で pyspark コマンドを実行し、REPL シェルを起動するには、次のコマンドを実行します。

$ docker run -it --rm \ 
    -v ~/.aws:/home/hadoop/.aws \ 
    -e AWS_PROFILE=$PROFILE_NAME \ 
    --name glue5_pyspark \ 
    public.ecr.aws/glue/aws-glue-libs:5 \ 
    pyspark

次の出力が表示されます:

Python 3.11.6 (main, Jan  9 2025, 00:00:00) [GCC 11.4.1 20230605 (Red Hat 11.4.1-2)] on linux 
 Type "help", "copyright", "credits" or "license" for more information.
 Setting default log level to "WARN".
 To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).
 Welcome to 
      ____              __ 
     / __/__  ___ _____/ /__ 
    _\ \/ _ \/ _ `/ __/  '_/
   /__ / .__/\_,_/_/ /_/\_\   version 3.5.2-amzn-1 
      /_/

 Using Python version 3.11.6 (main, Jan  9 2025 00:00:00)
 Spark context Web UI available at None 
 Spark context available as 'sc' (master = local[*], app id = local-1740643079929).
 SparkSession available as 'spark'.
>>> 

この REPL シェルを使えば、対話的にコーディングとテストができます。

pytest

単体テストには、AWS Glue Spark ジョブスクリプトに対して pytest を使用できます。

次のコマンドを実行して準備をしてください:

$ WORKSPACE_LOCATION=/local_path_to_workspace 
$ SCRIPT_FILE_NAME=sample.py 
$ UNIT_TEST_FILE_NAME=test_sample.py 
$ mkdir -p ${WORKSPACE_LOCATION}/tests 
$ vim ${WORKSPACE_LOCATION}/tests/${UNIT_TEST_FILE_NAME}

次に、docker run を使って pytest を呼び出しましょう:

$ docker run -i --rm \ 
    -v ~/.aws:/home/hadoop/.aws \ 
    -v $WORKSPACE_LOCATION:/home/hadoop/workspace/ \ 
    --workdir /home/hadoop/workspace \ 
    -e AWS_PROFILE=$PROFILE_NAME \ 
    --name glue5_pytest \ 
    public.ecr.aws/glue/aws-glue-libs:5 \ 
    -c "python3 -m pytest --disable-warnings"

pytest がユニットテストの実行を終えると、出力は次のようになります:

============================= test session starts ==============================
 platform linux -- Python 3.11.6, pytest-8.3.4, pluggy-1.5.0 
 rootdir: /home/hadoop/workspace 
 plugins: integration-mark-0.2.0 
 collected 1 item 

 tests/test_sample.py .                                                   [100%] 

======================== 1 passed, 1 warning in 34.28s =========================

Visual Studio Code

Visual Studio Code でコンテナを設定するには、以下の手順を実行してください:

  • Visual Studio Code をインストールしてください。
  • Python をインストールしてください。
  • Dev Containers をインストールしてください。
  • Visual Studio Code でワークスペースフォルダを開いてください。
  • Ctrl+Shift+P (Windows/Linux) または Cmd+Shift+P (Mac) を押してください。
  • Preferences: Open Workspace Settings (JSON) と入力してください。
  • Enter を押してください。
  • 次の JSON を入力して保存してください。
{
    "python.defaultInterpreterPath": "/usr/bin/python3.11",
    "python.analysis.extraPaths": [ 
        "/usr/lib/spark/python/lib/py4j-0.10.9.7-src.zip:/usr/lib/spark/python/:/usr/lib/spark/python/lib/",
    ] 
}

これで、コンテナのセットアップの準備ができました。

  1. Docker コンテナを実行します:
$ docker run -it --rm \ 
    -v ~/.aws:/home/hadoop/.aws \ 
    -v $WORKSPACE_LOCATION:/home/hadoop/workspace/ \ 
    -e AWS_PROFILE=$PROFILE_NAME \ 
    --name glue5_pyspark \ 
    public.ecr.aws/glue/aws-glue-libs:5 \ 
    pyspark
  1. Visual Studio Code を起動します。
  2. ナビゲーションペインで Remote Explorer を選択します。
  3. コンテナ ecr.aws/glue/aws-glue-libs:5 を右クリックし、Attach in Current Window を選択します。

    1. 次のダイアログが表示された場合は  Got it を選択してください。

  1. /home/hadoop/workspace/ を開いてください。

  1. AWS Glue の PySpark スクリプトを作成し、Run を選択します。

AWS Glue の PySpark スクリプトが正常に実行されたことが確認できるはずです。

AWS Glue 4.0 と AWS Glue 5.0 の Docker イメージ間の変更点

AWS Glue 4.0 と Glue 5.0 の Docker イメージ間の主な変更点は次のとおりです。

  • AWS Glue 5.0 では、バッチジョブとストリーミングジョブの両方に単一のコンテナイメージが使用されます。これは AWS Glue 4.0 とは異なり、4.0 ではバッチ用とストリーミング用に別々のイメージがありました。
  • AWS Glue 5.0 では、コンテナのデフォルトユーザー名は hadoop です。AWS Glue 4.0 では、デフォルトユーザー名は glue_user でした。
  • AWS Glue 5.0 では、JupyterLab や Livy などのいくつかの追加ライブラリがイメージから削除されています。手動でインストールすることができます。
  • AWS Glue 5.0 では、Iceberg、Hudi、Delta ライブラリがすべてデフォルトで事前ロードされており、環境変数 DATALAKE_FORMATS は不要になりました。AWS Glue 4.0 までは、環境変数 DATALAKE_FORMATS を使用して、特定のテーブル形式がロードされるかどうかを指定していました。

前述のリストは Docker イメージに固有のものです。AWS Glue 5.0 の更新について詳しくは、Introducing AWS Glue 5.0 for Apache Spark および Migrating AWS Glue for Spark jobs to AWS Glue version 5.0 をご覧ください。

考慮事項

AWS Glue コンテナイメージを使用してジョブスクリプトをローカルで開発する際、以下の機能はサポートされていないことに注意してください:

結論

この投稿では、AWS Glue 5.0 Docker イメージが、お好みの環境で AWS Glue ジョブスクリプトを開発およびテストするための柔軟な基盤を提供することをご紹介しました。HAQM ECR Public Gallery で簡単に入手できるこれらのイメージは、AWS Glue ジョブの開発に一貫したポータブルな環境を提供することで、開発プロセスを合理化します。

エンドツーエンドの開発パイプラインの構築方法の詳細については、End-to-end development lifecycle for data engineers to build a data integration pipeline using AWS Glue をご覧ください。これらの機能を活用し、AWS コミュニティで知見を共有することをお勧めします。


Appendix A: AWS Glue ジョブのテスト用サンプルコード

この Appendix では、テスト目的で AWS Glue ジョブのサンプルコードとして 3 つの異なるスクリプトを紹介します。チュートリアルではこれらのいずれかを使用できます。

以下の sample.py コードは、AWS Glue ETL ライブラリと HAQM Simple Storage Service (HAQM S3) の API 呼び出しを使用しています。このコードには、AWS Identity and Access Management (IAM) での HAQM S3 の権限が必要です。arn:aws:iam::aws:policy/HAQMS3ReadOnlyAccess の IAM 管理ポリシーか、S3 パスに対して ListBucket と GetObject の API 呼び出しを許可するカスタム IAM ポリシーを付与する必要があります。

import sys 
 from pyspark.context import SparkContext 
 from awsglue.context import GlueContext 
 from awsglue.job import Job 
 from awsglue.utils import getResolvedOptions 


 class GluePythonSampleTest:
    def __init__(self):
        params = [] 
        if '--JOB_NAME' in sys.argv:
            params.append('JOB_NAME')
        args = getResolvedOptions(sys.argv, params)

        self.context = GlueContext(SparkContext.getOrCreate())
        self.job = Job(self.context)

        if 'JOB_NAME' in args:
            jobname = args['JOB_NAME'] 
        else:
            jobname = "test"
        self.job.init(jobname, args)

    def run(self):
        dyf = read_json(self.context, "s3://awsglue-datasets/examples/us-legislators/all/persons.json")
        dyf.printSchema()

        self.job.commit()


 def read_json(glue_context, path):
    dynamicframe = glue_context.create_dynamic_frame.from_options(
        connection_type='s3',
        connection_options={
            'paths': [path],
            'recurse': True 
        },
        format='json'
    )
    return dynamicframe 


 if __name__ == '__main__':
    GluePythonSampleTest().run()

以下の test_sample.py コードは、sample.py のユニットテストのサンプルです:


 import pytest 
 from pyspark.context import SparkContext 
 from awsglue.context import GlueContext 
 from awsglue.job import Job 
 from awsglue.utils import getResolvedOptions 
 import sys 
 from src import sample 


@pytest.fixture(scope="module", autouse=True)
 def glue_context():
    sys.argv.append('--JOB_NAME')
    sys.argv.append('test_count')

    args = getResolvedOptions(sys.argv, ['JOB_NAME'])
    context = GlueContext(SparkContext.getOrCreate())
    job = Job(context)
    job.init(args['JOB_NAME'], args)

Appendix B: JDBC ドライバーと Java ライブラリの追加

コンテナ内に現在ない JDBC ドライバーを追加する場合は、ワークスペース内に必要な JAR ファイルを含む新しいディレクトリを作成し、そのディレクトリを docker run コマンドで /opt/spark/jars/ にマウントします。コンテナ内の /opt/spark/jars/ 以下にある JAR ファイルは、自動的に Spark クラスパスに追加され、ジョブ実行中に使用できるようになります。

たとえば、次の docker run コマンドを使用して、JDBC ドライバーの jar ファイルを PySpark REPL シェルに追加できます:

$ docker run -it --rm \ 
    -v ~/.aws:/home/hadoop/.aws \ 
    -v $WORKSPACE_LOCATION:/home/hadoop/workspace/ \ 
    -v $WORKSPACE_LOCATION/jars/:/opt/spark/jars/ \ 
    --workdir /home/hadoop/workspace \ 
    -e AWS_PROFILE=$PROFILE_NAME \ 
    --name glue5_jdbc \ 
    public.ecr.aws/glue/aws-glue-libs:5 \ 
    pyspark

前述のように、customJdbcDriverS3Path 接続オプションは、AWS Glue コンテナイメージにカスタム JDBC ドライバを HAQM S3 からインポートするために使用できません。

Appendix C: Livy と JupyterLab の追加

AWS Glue 5.0 コンテナイメージには、デフォルトで Livy がインストールされていません。AWS Glue 5.0 コンテナイメージを基本とする新しいコンテナイメージを作成できます。次の Dockerfile は、開発およびテスト体験を強化するために必要な追加コンポーネントを含めるように Docker イメージを拡張する方法を示しています。

始めるには、ワークステーションにディレクトリを作成し、そのディレクトリに Dockerfile.livy_jupyter ファイルを配置します。

$ mkdir -p $WORKSPACE_LOCATION/jupyterlab/
$ cd $WORKSPACE_LOCATION/jupyterlab/
$ vim Dockerfile.livy_jupyter

次のコードは Dockerfile.livy_jupyter です:

FROM public.ecr.aws/glue/aws-glue-libs:5 AS glue-base 

 ENV LIVY_SERVER_JAVA_OPTS="--add-opens java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.nio=ALL-UNNAMED --add-opens=java.base/sun.nio.ch=ALL-UNNAMED --add-opens=java.base/sun.nio.cs=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED"

# Download Livy 
 ADD --chown=hadoop:hadoop http://dlcdn.apache.org/incubator/livy/0.8.0-incubating/apache-livy-0.8.0-incubating_2.12-bin.zip ./

# Install and configure Livy 
 RUN unzip apache-livy-0.8.0-incubating_2.12-bin.zip && \ 
 rm apache-livy-0.8.0-incubating_2.12-bin.zip && \ 
 mv apache-livy-0.8.0-incubating_2.12-bin livy && \ 
 mkdir -p livy/logs && \ 
 cat <> livy/conf/livy.conf 
 livy.server.host = 0.0.0.0 
 livy.server.port = 8998 
 livy.spark.master = local 
 livy.repl.enable-hive-context = true 
 livy.spark.scala-version = 2.12 
 EOF && \ 
 cat <> livy/conf/log4j.properties 
 log4j.rootCategory=INFO,console 
 log4j.appender.console=org.apache.log4j.ConsoleAppender 
 log4j.appender.console.target=System.err 
 log4j.appender.console.layout=org.apache.log4j.PatternLayout 
 log4j.appender.console.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss} %p %c{1}: %m%n 
 log4j.logger.org.eclipse.jetty=WARN 
 EOF 

# Switching to root user temporarily to install dev dependency packages 
 USER root 
 RUN dnf update -y && dnf install -y krb5-devel gcc python3.11-devel 
 USER hadoop 

# Install SparkMagic and JupyterLab 
 RUN export PATH=$HOME/.local/bin:$HOME/livy/bin/:$PATH && \ 
 printf "numpy<2\nIPython<=7.14.0\n" > /tmp/constraint.txt && \ 
 pip3.11 --no-cache-dir install --constraint /tmp/constraint.txt --user pytest boto==2.49.0 jupyterlab==3.6.8 IPython==7.14.0 ipykernel==5.5.6 ipywidgets==7.7.2 sparkmagic==0.21.0 jupyterlab_widgets==1.1.11 && \ 
 jupyter-kernelspec install --user $(pip3.11 --no-cache-dir show sparkmagic | grep Location | cut -d" " -f2)/sparkmagic/kernels/sparkkernel && \ 
 jupyter-kernelspec install --user $(pip3.11 --no-cache-dir show sparkmagic | grep Location | cut -d" " -f2)/sparkmagic/kernels/pysparkkernel && \ 
 jupyter server extension enable --user --py sparkmagic && \ 
 cat <> /home/hadoop/.local/bin/entrypoint.sh 
#!/usr/bin/env bash 
 mkdir -p /home/hadoop/workspace/
 livy-server start 
 sleep 5 
 jupyter lab --no-browser --ip=0.0.0.0 --allow-root --ServerApp.root_dir=/home/hadoop/workspace/ --ServerApp.token='' --ServerApp.password=''
 EOF 

# Setup Entrypoint script 
 RUN chmod + x /home/hadoop/.local/bin/entrypoint.sh 

# Add default SparkMagic Config 
 ADD --chown=hadoop:hadoop http://raw.githubusercontent.com/jupyter-incubator/sparkmagic/refs/heads/master/sparkmagic/example_config.json .sparkmagic/config.json 

# Update PATH var 
 ENV PATH=/home/hadoop/.local/bin:/home/hadoop/livy/bin/:$PATH 

 ENTRYPOINT ["/home/hadoop/.local/bin/entrypoint.sh"] 

Docker ビルドコマンドを実行してイメージをビルドします:

docker build \ 
    -t glue_v5_livy \ 
    --file $WORKSPACE_LOCATION/jupyterlab/Dockerfile.livy_jupyter \ 
    $WORKSPACE_LOCATION/jupyterlab/

イメージのビルドが完了したら、次の docker run コマンドを使用して、新しく作成されたイメージを起動できます。

docker run -it --rm \ 
    -v ~/.aws:/home/hadoop/.aws \ 
    -v $WORKSPACE_LOCATION:/home/hadoop/workspace/ \ 
    -p 8998:8998 \ 
    -p 8888:8888 \ 
    -e AWS_PROFILE=$PROFILE_NAME \ 
    --name glue5_jupyter  \ 
    glue_v5_livy

Appendix D: 追加の Python ライブラリの追加

このセクションでは、追加の Python ライブラリを追加し、Python パッケージをインストールする方法について説明します。

ローカル Python ライブラリ

ローカルの Python ライブラリを追加するには、ディレクトリに配置し、パスを $EXTRA_PYTHON_PACKAGE_LOCATION に割り当ててください:

$ docker run -it --rm \ 
    -v ~/.aws:/home/hadoop/.aws \ 
    -v $WORKSPACE_LOCATION:/home/hadoop/workspace/ \ 
    -v $EXTRA_PYTHON_PACKAGE_LOCATION:/home/hadoop/workspace/extra_python_path/ \ 
    --workdir /home/hadoop/workspace \ 
    -e AWS_PROFILE=$PROFILE_NAME \ 
    --name glue5_pylib \ 
    public.ecr.aws/glue/aws-glue-libs:5 \ 
    -c 'export PYTHONPATH=/home/hadoop/workspace/extra_python_path/:$PYTHONPATH ; pyspark'

PYTHONPATH にパスが追加されたことを検証するには、sys.path にそのパスが存在するかどうかを確認できます:

Python 3.11.6 (main, Jan  9 2025, 00:00:00) [GCC 11.4.1 20230605 (Red Hat 11.4.1-2)] on linux 
 Type "help", "copyright", "credits" or "license" for more information.
 Setting default log level to "WARN".
 To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).
 Welcome to 
      ____              __ 
     / __/__  ___ _____/ /__ 
    _\ \/ _ \/ _ `/ __/  '_/
   /__ / .__/\_,_/_/ /_/\_\   version 3.5.2-amzn-1 
      /_/

 Using Python version 3.11.6 (main, Jan  9 2025 00:00:00)
 Spark context Web UI available at None 
 Spark context available as 'sc' (master = local[*], app id = local-1740719582296).
 SparkSession available as 'spark'.
>>> import sys 
>>> "/home/hadoop/workspace/extra_python_path" in sys.path 
 True 

Python パッケージの pip によるインストール

PyPI (または他のアーティファクトリポジトリ) からパッケージを pip でインストールするには、次のアプローチを使用できます。

docker run -it --rm \ 
    -v ~/.aws:/home/hadoop/.aws \ 
    -v $WORKSPACE_LOCATION:/home/hadoop/workspace/ \ 
    --workdir /home/hadoop/workspace \ 
    -e AWS_PROFILE=$PROFILE_NAME \ 
    -e SCRIPT_FILE_NAME=$SCRIPT_FILE_NAME \ 
    --name glue5_pylib \ 
    public.ecr.aws/glue/aws-glue-libs:5 \ 
    -c 'pip3 install snowflake==1.0.5 ; spark-submit /home/hadoop/workspace/src/$SCRIPT_FILE_NAME'

本記事は、2025 年 3 月 12 日に公開された Develop and test AWS Glue 5.0 jobs locally using a Docker container を翻訳したものです。翻訳はソリューションアーキテクトの高橋が担当しました。