AWS Glue での Python ライブラリの使用
AWS Glue ETL で使用する追加の Python モジュールとライブラリをインストールできます。AWS Glue 2.0 以上の場合、AWS Glue は Python パッケージインストーラ (pip3) を使用して、AWS Glue ETL で使用する追加モジュールをインストールします。AWSGlue には、追加の Python モジュールを AWS Glue ジョブ環境に持ち込むための複数のオプションが用意されています。Python wheel ファイル、Requirements ファイル (requirement.txt、AWS Glue 5.0 以降)、またはカンマ区切りの Python モジュールのリストを使用してモジュールを取り込むため、「—additional-python-modules」パラメータを使用できます。
トピック
Glue バージョン | Python バージョン | 基本のイメージ | glibc バージョン | サポートされているインストール方法 |
---|---|---|---|---|
5.0 | 3.11 | Amazon Linux 2023 (AL2023) |
2.34 | |
4.0 | 3.10 | Amazon Linux 2 (AL2) |
2.26 | |
3.0 | 37 | Amazon Linux 2 (AL2) |
2.26 | |
2.0 | 37 | Amazon Linux AMI (AL1) |
2.17 | |
1.0 | 3.6 | Amazon Linux AMI (AL1) |
2.17 | |
0.9 | 2.7 | Amazon Linux AMI (AL1) |
2.17 |
AWS 責任共有モデル
AWS Glue は、ジョブ環境でのネイティブコードのコンパイルをサポートしていません。ただし、AWS Glue のジョブは、Amazon マネージド Linux 環境内での実行が可能です。Python Wheel ファイルを通じて、ネイティブの依存関係をコンパイルされた形式で提供できる場合があります。AWS Glue のバージョンの互換性の詳細については、上記の表を参照してください。
Python の依存関係が、ネイティブのコンパイル済みコードに過渡的に依存している場合、AWS Glue がジョブ環境でのネイティブコードのコンパイルをサポートしていない、という制限による影響を受ける場合があります。ただし、AWS Glue のジョブは、Amazon マネージド Linux 環境内での実行が可能です。Wheel ディストリビューションを通じて、ネイティブの依存関係をコンパイルされた形式で提供できる場合があります。AWS Glue のバージョンの互換性の詳細については、上記の表を参照してください。
重要
互換性のない依存関係を使用すると、ターゲット環境のアーキテクチャとシステムライブラリと一致する必要があるネイティブ拡張機能を持つライブラリの場合は特に、ランタイムの問題が発生する可能性があります。各 AWS Glue バージョンは、ライブラリとシステム設定がプリインストールされた特定の Python バージョンで実行します。
pip を使用して追加の Python モジュールを AWS Glue 2.0 以降にインストールする
AWS Glue は Python パッケージインストーラー (pip3) を使用して、AWS Glue の ETL で使用する追加モジュールをインストールします。--additional-python-modules
パラメータでコンマ区切りの Python モジュールのリストを指定することで、新しいモジュールを追加したり、既存のモジュールのバージョンを変更したりできます。Amazon S3 にディストリビューションをアップロードすることでライブラリのカスタムディストリビューションをインストールできます。その後で、モジュールのリストに Amazon S3 オブジェクトへのパスを含めます。
--python-modules-installer-option
パラメータを使用すると、pip3 に追加オプションを渡すことができます。例えば "--upgrade"
を渡すことで、"--additional-python-modules"
で指定されたパッケージをアップグレードできます。その他の例については、「AWS Glue 2.0 を使用して Spark ETL ワークロード用のホイールから Python モジュールを構築する
AWS Glue では、Amazon S3 に保存されている wheel (.whl) ファイルを使用したカスタム Python パッケージのインストールをサポートしています。AWS Glue ジョブに wheel ファイルを含めるには、s3 に保存されている wheel ファイルのカンマ区切りリストを --additional-python-modules
ジョブパラメータに渡します。例:
--additional-python-modules s3://amzn-s3-demo-bucket/path/to/package-1.0.0-py3-none-any.whl,s3://your-bucket/path/to/another-package-2.1.0-cp311-cp311-linux_x86_64.whl
このアプローチでは、カスタムディストリビューションが必要な場合や、適切なオペレーティングシステム用にプリコンパイルされたネイティブの依存関係を持つパッケージが必要な場合でもサポートされます。その他の例については、「Building Python modules from a wheel for Spark ETL workloads using AWS Glue 2.0
--additional-python-modules
は、AWS Glue コンソールの [ジョブパラメータ] フィールドを使用して指定するか、AWS SDK でジョブの引数を変更して指定します。ジョブパラメータの設定の詳細については、「AWS Glue ジョブでジョブパラメータを使用する」を参照してください。
AWS Glue 5.0 では、Python ライブラリの依存関係を管理するための業界標準である requirements.txt
を指定できます。そのためにはまず、次の 2 つのジョブパラメータを指定します。
-
キー:
--python-modules-installer-option
値:
-r
-
キー:
--additional-python-modules
値:
s3://path_to_requirements.txt
AWS Glue 5.0 ノードは、requirements.txt
で指定された Python ライブラリを最初にロードします。
次に requirements.txt の例を示します。
awswrangler==3.9.1 elasticsearch==8.15.1 PyAthena==3.9.0 PyMySQL==1.1.1 PyYAML==6.0.2 pyodbc==5.2.0 pyorc==0.9.0 redshift-connector==2.1.3 scipy==1.14.1 scikit-learn==1.5.2 SQLAlchemy==2.0.36
重要
requirements.txt では、固定されていないライブラリバージョンは避けて、ジョブに対して信頼性が高く確定的な AWS Glue 環境を確保してください。
直接的な依存関係に wheel を使用すると、一時的な依存関係が正しく固定されていない場合、互換性のないバージョンを取り込む可能性があります。ベストプラクティスとして、AWS Glue ジョブの一貫性を保つために、すべてのライブラリバージョンを固定する必要があります。AWSGlue では、本番環境のワークロードの一貫性と信頼性を確保するために、Python 環境を wheel ファイルにパッケージ化することをお勧めします。
新しい Python モジュール AWS Glue を更新または追加するには、カンマ区切りの Python モジュールのリストを値として --additional-python-modules
パラメータを渡すことができます。例えば、更新や新しい scikit-learn モジュールの追加には、"--additional-python-modules",
"scikit-learn==0.21.3"
のキー/値を使用します。Python モジュールを直接設定するには 2 つのオプションがあります。
-
固定された Python モジュール (推奨)
"--additional-python-modules", "scikit-learn==0.21.3,ephem==4.1.6"
-
固定されていない Python モジュール: (本番稼働用ワークロードには推奨されません)
"--additional-python-modules", "scikit-learn>==0.20.0,ephem>=4.0.0"
または
"--additional-python-modules", "scikit-learn,ephem"
重要
--additional-python-modules
で python モジュールを直接設定する場合、AWS Glue ジョブ環境の一貫性を確保するために、AWS Glue では固定ライブラリバージョンを使用することをお勧めしています。固定されていないライブラリバージョンを使用すると、最新バージョンの python モジュールがプルされますが、これにより重大な変更が発生したり、互換性のない python モジュールが AWS Glue ジョブ環境での python インストールの失敗によるジョブの失敗につながる可能性があります。本番ワークロードには、固定されていないライブラリバージョンを使用しないことをお勧めします。ベストプラクティスとして、AWS Glue では本番環境のワークロードの一貫性と信頼性を確保するために、Python 環境を wheel ファイルにパッケージ化することをお勧めしています。
AWS Glue に追加の Python ライブラリをインストールするためのベストプラクティス
(推奨) Python 環境を 1 つの wheel ファイルにパッケージ化する
安全で一貫性のある環境を実現するために、AWS Glue では、Python 環境のスナップショットを作成し、ホイールファイルにパッケージ化することをお勧めします。この利点は、参照 Python モジュール用の Python 環境とその推移的な依存関係がロックされることです。これにより、PyPI や依存関係などのアップストリームリポジトリが互換性のない更新を導入しても、AWS Glue ジョブが影響を受けなくなります。
このファイルは、--additional-python-modules
フラグを使用して AWS Glue ジョブで使用できます。
重要
次のスクリプトは、実行中の AWS Glue バージョンと同様の環境で実行する必要があります。Glue 環境の詳細表を参照して、同じベース OS イメージと Python バージョンを使用していることを確認してください。
#!/bin/bash set -e REQUIREMENTS_FILE="requirements.txt" FINAL_WHEEL_OUTPUT_DIRECTORY="." PACKAGE_NAME=$(basename "$(pwd)") PACKAGE_VERSION="0.1.0" # Help message show_help() { echo "Usage: $0 [options]" echo "" echo "Options:" echo " -r, --requirements FILE Path to requirements.txt file (default: requirements.txt)" echo " -o, --wheel-output DIR Output directory for final wheel (default: current directory)" echo " -n, --name NAME Package name (default: current directory name)" echo " -v, --version VERSION Package version (default: 0.1.0)" echo " -h, --help Show this help message" echo " -g, --glue-version Glue version (required)" echo "" echo "Example:" echo " $0 -r custom-requirements.txt -o dist -n my_package -v 1.2.3 -g 4.0" } # Parse command line arguments while [[ $# -gt 0 ]]; do key="$1" case $key in -r | --requirements) REQUIREMENTS_FILE="$2" shift 2 ;; -o | --wheel-output) FINAL_WHEEL_OUTPUT_DIRECTORY="$2" shift 2 ;; -n | --name) PACKAGE_NAME="$2" shift 2 ;; -v | --version) PACKAGE_VERSION="$2" shift 2 ;; -g | --glue-version) GLUE_VERSION="$2" shift 2 ;; -h | --help) show_help exit 0 ;; *) echo "Unknown option: $1" show_help exit 1 ;; esac done # If package name has dashes, convert to underscores and notify user. We need to check this since we cant import a package with dashes. if [[ "$PACKAGE_NAME" =~ "-" ]]; then echo "Warning: Package name '$PACKAGE_NAME' contains dashes. Converting to underscores." PACKAGE_NAME=$(echo "$PACKAGE_NAME" | tr '-' '_') fi UBER_WHEEL_NAME="${PACKAGE_NAME}-${PACKAGE_VERSION}-py3-none-any.whl" # Check if glue version is provided if [ -z "$GLUE_VERSION" ]; then echo "Error: Glue version is required." exit 1 fi # Validate version format (basic check) if [[ ! "$PACKAGE_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && [[ ! "$PACKAGE_VERSION" =~ ^[0-9]+\.[0-9]+$ ]]; then echo "Warning: Version '$PACKAGE_VERSION' doesn't follow semantic versioning (x.y.z or x.y)" fi # Check if requirements file exists if [ ! -f "$REQUIREMENTS_FILE" ]; then echo "Error: Requirements file '$REQUIREMENTS_FILE' not found." exit 1 fi # Get relevant platform tags/python versions based on glue version if [[ "$GLUE_VERSION" == "5.0" ]]; then PYTHON_VERSION="3.11" GLIBC_VERSION="2.34" elif [[ "$GLUE_VERSION" == "4.0" ]]; then PYTHON_VERSION="3.10" GLIBC_VERSION="2.26" elif [[ "$GLUE_VERSION" == "3.0" ]]; then PYTHON_VERSION="3.7" GLIBC_VERSION="2.26" elif [[ "$GLUE_VERSION" == "2.0" ]]; then PYTHON_VERSION="3.7" GLIBC_VERSION="2.17" elif [[ "$GLUE_VERSION" == "1.0" ]]; then PYTHON_VERSION="3.6" GLIBC_VERSION="2.17" elif [[ "$GLUE_VERSION" == "0.9" ]]; then PYTHON_VERSION="2.7" GLIBC_VERSION="2.17" else echo "Error: Unsupported glue version '$GLUE_VERSION'." exit 1 fi echo "Using Glue version $GLUE_VERSION" echo "Using Glue python version $PYTHON_VERSION" echo "Using Glue glibc version $GLIBC_VERSION" PIP_PLATFORM_FLAG="" is_glibc_compatible() { # assumes glibc version in the form of major.minor (ex: 2.17) # glue glibc must be >= platform glibc local glue_glibc_version="$GLIBC_VERSION" local platform_glibc_version="$1" # 2.27 (platform) can run on 2.27 (glue) if [[ "$platform_glibc_version" == "$glue_glibc_version" ]]; then return 0 fi local glue_glibc_major="${glue_glibc_version%%.*}" local glue_glibc_minor="${glue_glibc_version#*.}" local platform_glibc_major="${platform_glibc_version%%.*}" local platform_glibc_minor="${platform_glibc_version#*.}" # 3.27 (platform) cannot run on 2.27 (glue) if [[ "$platform_glibc_major" -gt "$glue_glibc_major" ]]; then return 1 fi # 2.34 (platform) cannot run on 2.27 (glue) if [[ "$platform_glibc_major" -eq "$glue_glibc_major" ]] && [[ "$platform_glibc_minor" -gt "$glue_glibc_minor" ]]; then return 1 fi # 2.17 (platform) can run on 2.27 (glue) return 0 } PIP_PLATFORM_FLAG="" if is_glibc_compatible "2.17"; then PIP_PLATFORM_FLAG="${PIP_PLATFORM_FLAG} --platform manylinux2014_x86_64" fi if is_glibc_compatible "2.28"; then PIP_PLATFORM_FLAG="${PIP_PLATFORM_FLAG} --platform manylinux_2_28_x86_64" fi if is_glibc_compatible "2.34"; then PIP_PLATFORM_FLAG="${PIP_PLATFORM_FLAG} --platform manylinux_2_34_x86_64" fi if is_glibc_compatible "2.39"; then PIP_PLATFORM_FLAG="${PIP_PLATFORM_FLAG} --platform manylinux_2_39_x86_64" fi echo "Using pip platform flags: $PIP_PLATFORM_FLAG" # Convert to absolute paths REQUIREMENTS_FILE=$(realpath "$REQUIREMENTS_FILE") FINAL_WHEEL_OUTPUT_DIRECTORY=$(realpath "$FINAL_WHEEL_OUTPUT_DIRECTORY") TEMP_WORKING_DIR=$(mktemp -d) VENV_DIR="${TEMP_WORKING_DIR}/.build_venv" WHEEL_OUTPUT_DIRECTORY="${TEMP_WORKING_DIR}/wheelhouse" # Cleanup function cleanup() { echo "Cleaning up temporary files..." rm -rf "$TEMP_WORKING_DIR" } trap cleanup EXIT echo "=========================================" echo "Building wheel for $PACKAGE_NAME with all dependencies from $REQUIREMENTS_FILE" echo "=========================================" # Determine Python executable to use consistently PYTHON_EXEC=$(which python3 2>/dev/null || which python 2>/dev/null) if [ -z "$PYTHON_EXEC" ]; then echo "Error: No Python executable found" exit 1 fi echo "Using Python: $PYTHON_EXEC" echo "" # Install build requirements echo "Step 1/5: Installing build tools..." echo "----------------------------------------" "$PYTHON_EXEC" -m pip install --upgrade pip build wheel setuptools echo "✓ Build tools installed successfully" echo "" # Create a virtual environment for building echo "Step 2/5: Creating build environment..." echo "----------------------------------------" "$PYTHON_EXEC" -m venv "$VENV_DIR" # Check if virtual environment was created successfully if [ ! -f "$VENV_DIR/bin/activate" ]; then echo "Error: Failed to create virtual environment" exit 1 fi source "$VENV_DIR/bin/activate" # Install pip-tools for dependency resolution "$VENV_DIR/bin/pip" install pip-tools echo "✓ Build environment created successfully" echo "" # Compile requirements to get all transitive dependencies GLUE_PIP_ARGS="$PIP_PLATFORM_FLAG --python-version $PYTHON_VERSION --only-binary=:all:" echo "Step 3/5: Resolving all dependencies..." echo "----------------------------------------" if ! "$VENV_DIR/bin/pip-compile" --pip-args "$GLUE_PIP_ARGS" --no-emit-index-url --output-file "$TEMP_WORKING_DIR/.compiled_requirements.txt" "$REQUIREMENTS_FILE"; then echo "Error: Failed to resolve dependencies. Check for conflicts in $REQUIREMENTS_FILE" exit 1 fi echo "✓ Dependencies resolved successfully" echo "" # Download all wheels for dependencies echo "Step 4/5: Downloading all dependency wheels..." echo "----------------------------------------" "$VENV_DIR/bin/pip" download -r "$TEMP_WORKING_DIR/.compiled_requirements.txt" -d "$WHEEL_OUTPUT_DIRECTORY" $GLUE_PIP_ARGS # Check if any wheels were downloaded if [ ! "$(ls -A "$WHEEL_OUTPUT_DIRECTORY")" ]; then echo "Error: No wheels were downloaded. Check your requirements file." exit 1 fi # Count downloaded wheels (using find instead of ls for better handling) WHEEL_COUNT=$(find "$WHEEL_OUTPUT_DIRECTORY" -name "*.whl" -type f | wc -l | tr -d ' ') echo "✓ Downloaded $WHEEL_COUNT dependency wheels successfully" echo "" # Create a single uber wheel with all dependencies echo "Step 5/5: Creating uber wheel with all dependencies included..." echo "----------------------------------------" # Create a temporary directory for the uber wheel UBER_WHEEL_DIR="$TEMP_WORKING_DIR/uber" mkdir -p "$UBER_WHEEL_DIR" # Create the setup.py file with custom install command cat >"$UBER_WHEEL_DIR/setup.py" <<EOF from setuptools import setup, find_packages import setuptools.command.install import os import glob import subprocess import sys setup( name='${PACKAGE_NAME}', version='${PACKAGE_VERSION}', description='Bundle containing dependencies for ${PACKAGE_NAME}', author='Package Builder', author_email='builder@example.com', packages=['${PACKAGE_NAME}'], # Include the package directory to hold wheels include_package_data=True, package_data={ '${PACKAGE_NAME}': ['wheels/*.whl'], # Include wheels in the package directory } ) EOF # Create a MANIFEST.in file to include all wheels cat >"$UBER_WHEEL_DIR/MANIFEST.in" <<EOF recursive-include ${PACKAGE_NAME}/wheels *.whl EOF # Create an __init__.py file that imports all the bundled wheel files (no auto-install logic) mkdir -p "$UBER_WHEEL_DIR/${PACKAGE_NAME}" cat >"$UBER_WHEEL_DIR/${PACKAGE_NAME}/__init__.py" <<EOF """ ${PACKAGE_NAME} - dependencies can be installed at runtime using the $(load_wheels) function """ from pathlib import Path import logging import subprocess import sys __version__ = "${PACKAGE_VERSION}" def load_wheels(log_level=logging.INFO): logger = logging.getLogger(__name__) handler = logging.StreamHandler(sys.stdout) formatter = logging.Formatter("[Glue Python Wheel Installer] %(asctime)s - %(name)s - %(levelname)s - %(message)s") handler.setFormatter(formatter) logger.addHandler(handler) logger.setLevel(log_level) logger.info("Starting wheel installation process") package_dir = Path(__file__).parent.absolute() wheels_dir = package_dir / "wheels" logger.debug(f"Package directory: {package_dir}") logger.debug(f"Looking for wheels in: {wheels_dir}") if not wheels_dir.exists(): logger.error(f"Wheels directory not found: {wheels_dir}") return False wheel_files = list(wheels_dir.glob("*.whl")) if not wheel_files: logger.warning(f"No wheels found in: {wheels_dir}") return False logger.info(f"Found {len(wheel_files)} wheels") wheel_file_paths = [str(wheel_file) for wheel_file in wheel_files] logger.info(f"Installing {wheel_file_paths}...") try: result = subprocess.run( [sys.executable, "-m", "pip", "install", *wheel_file_paths], check=True, capture_output=True, text=True ) logger.info(f"✓ Successfully installed wheel files") logger.debug(f"pip output: {result.stdout}") except subprocess.CalledProcessError as e: error_msg = f"Failed to install wheel files" logger.error(f"✗ {error_msg}: {e}") if e.stderr: logger.error(f"Error details: {e.stderr}") return False logger.info("All wheels installed successfully") return True EOF cat >"$UBER_WHEEL_DIR/${PACKAGE_NAME}/auto.py" <<EOF """ ${PACKAGE_NAME} - utility module that allows users to automatically install modules by adding $(import ${PACKAGE_NAME}.auto) to the top of their script """ from ${PACKAGE_NAME} import load_wheels load_wheels() EOF # Copy all wheels to the uber wheel directory mkdir -p "$UBER_WHEEL_DIR/${PACKAGE_NAME}/wheels" cp "$WHEEL_OUTPUT_DIRECTORY"/*.whl "$UBER_WHEEL_DIR/${PACKAGE_NAME}/wheels/" # Build the uber wheel echo "Building uber wheel package..." # Install build tools in the current environment "$VENV_DIR/bin/pip" install build if ! (cd "$UBER_WHEEL_DIR" && "$VENV_DIR/bin/python" -m build --skip-dependency-check --wheel --outdir .); then echo "Error: Failed to build uber wheel" exit 1 fi # Ensure output directory exists mkdir -p "$FINAL_WHEEL_OUTPUT_DIRECTORY" # Copy the uber wheel to the output directory FINAL_WHEEL_OUTPUT_PATH="$FINAL_WHEEL_OUTPUT_DIRECTORY/$UBER_WHEEL_NAME" # Find the generated wheel (should be only one in the root directory) GENERATED_WHEEL=$(find "$UBER_WHEEL_DIR" -maxdepth 1 -name "*.whl" -type f | head -1) if [ -z "$GENERATED_WHEEL" ]; then echo "Error: No uber wheel was generated" exit 1 fi cp "$GENERATED_WHEEL" "$FINAL_WHEEL_OUTPUT_PATH" # Get final wheel size for user feedback WHEEL_SIZE=$(du -h "$FINAL_WHEEL_OUTPUT_PATH" | cut -f1) echo "✓ Uber wheel created successfully!" echo "" echo "=========================================" echo "BUILD COMPLETED SUCCESSFULLY!" echo "=========================================" echo "Final wheel: $FINAL_WHEEL_OUTPUT_PATH" echo "Wheel size: $WHEEL_SIZE" echo "Dependencies included: $WHEEL_COUNT packages" echo "" echo "To install the bundle, run:" echo " pip install $FINAL_WHEEL_OUTPUT_PATH" echo "" echo "After installation, you can verify that the bundle works by running:" echo " python -c \"import ${PACKAGE_NAME}; ${PACKAGE_NAME}.load_wheels()\"" echo " or " echo " python -c \"import ${PACKAGE_NAME}.auto\"" echo "========================================="
./wheel_packager.sh -r <path to requirements.txt> -g <glue version> -o <wheel output directory> -n <package name> -v <wheel version>
--additional-python-modules s3://your-bucket/path/to/package_with_dependencies-1.0.0-py3-none-any.whl
# Option 1: automatic installation via import import package_with_dependencies.auto # Option 2: manual installation from package_with_dependencies import load_wheels load_wheels()
PySpark のネイティブ機能を使用して Python ファイルを含める
AWS Glue では、PySpark を使用して、AWS Glue ETL ジョブに Python ファイルを含めます。可能な場合には、依存関係を管理するために、--additional-python-modules
を使用することが必要になります。Python ファイルをインクルードするには、--extra-py-files
ジョブパラメータを使用します。依存関係は Amazon S3 でホストされている必要があり、引数の値は、スペースを含まない Amazon S3 パスのカンマ区切りリストである必要があります。この機能は、Spark で使用する Python の依存関係管理のように動作します。Spark での Python の依存関係管理の詳細については、Apache Spark ドキュメントの「Using PySpark Native Features--extra-py-files
が便利です。依存関係ツールをメンテナンス可能にするには、送信する前に依存関係をバンドルする必要があります。
ビジュアル変換を使用するプログラミングスクリプト
AWS Glue Studio のビジュアルインターフェイスを使用して AWS Glue ジョブを作成するとき、マネージドデータトランスフォームノードおよびカスタムビジュアル変換を使用してデータを変換できます。マネージドデータ変換ノードの詳細については、「AWS Glue マネージド変換によるデータの変換」を参照してください。カスタムビジュアル変換の詳細については、「 カスタムビジュアル変換によるデータの変換 」を参照してください。ビジュアル変換を使用するスクリプトは、ジョブの [言語] が Python を使用するように設定されている場合にのみ生成できます。
ビジュアル変換を使用して AWS Glue ジョブを生成する場合、AWS Glue Studio はジョブ設定の --extra-py-files
パラメータを使用し、これらの変換をランタイム環境に組み込みます。ジョブパラメータについては、「AWS Glue ジョブでジョブパラメータを使用する」を参照してください。生成されたスクリプトまたはランタイム環境を変更するとき、スクリプトを正常に実行するためにこのジョブ設定を保存する必要があります。
取り込みのためのライブラリの圧縮
ライブラリは、単一の .py
ファイルに含まれていない限り、.zip
アーカイブにパッケージ化される必要があります。パッケージディレクトリは、アーカイブのルートにあって、パッケージの __init__.py
ファイルを含んでいる必要があります。そうすると、Python は通常の方法でパッケージをインポートできるようになります。
ライブラリが 1 つの .py
ファイルにある単一の Python モジュールでのみ構成されている場合、.zip
ファイルに入れる必要はありません。
Glue Studio ノートブックでの Python AWS ライブラリのロード
Glue Studio ノートブックで Python AWS ライブラリを指定するには、「追加 Python モジュールのインストール」を参照してください。
AWS Glue 0.9/1.0 の開発エンドポイントへの Python ライブラリのロード
異なる ETL スクリプトに異なるライブラリセットを使用している場合、各セットに別々の開発エンドポイントをセットアップするか、スクリプトを切り替えるたびに開発エンドポイントがロードするライブラリ .zip
ファイルを上書きすることができます。
コンソールを使用して、作成時に開発エンドポイントに 1 つまたは複数のライブラリ .zip ファイルを指定できます。名前と IAM ロールを割り当てた後、[Script Libraries and job parameters (optional)] (スクリプトライブラリおよびジョブパラメータ (任意)) をクリックし、[Python library path] (Python ライブラリパス) ボックスに、ライブラリ .zip
ファイルへの完全な Amazon S3 パスを入力します。例:
s3://bucket
/prefix/
site-packages.zip
必要に応じてファイルへの複数のフルパスを指定できますが、以下のように、スペースなしでカンマで区切ります。
s3://bucket/prefix/lib_A.zip,s3://bucket_B/prefix/lib_X.zip
これらの .zip
ファイルを後で更新する場合は、コンソールを使用して開発エンドポイントにそのファイルを再インポートできます。該当する開発エンドポイントに移動し、横にあるチェックボックスをオンにして、[Action] (アクション) メニューから [Update ETL libraries] (ETL ライブラリの更新) を選択します。
同様の方法で、AWS Glue API を使用してライブラリファイルを指定できます。CreateDevEndpoint アクション (Python: create_dev_endpoint) を呼び出して開発エンドポイントを作成する場合、ExtraPythonLibsS3Path
パラメータでライブラリへの 1 つ以上のフルパスを指定できます。以下のような呼び出しになります。
dep = glue.create_dev_endpoint(
EndpointName="testDevEndpoint
",
RoleArn="arn:aws:iam::123456789012
",
SecurityGroupIds="sg-7f5ad1ff
",
SubnetId="subnet-c12fdba4
",
PublicKey="ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCtp04H/y...
",
NumberOfNodes=3
,
ExtraPythonLibsS3Path="s3://bucket/prefix/lib_A.zip,s3://bucket_B/prefix/lib_X.zip
")
開発エンドポイントを更新するときに、DevEndpointCustomLibraries オブジェクトを使用し UpdateDevEndpoint (update_dev_endpoint) の呼び出し時に UpdateEtlLibraries
パラメータを True
に設定して、ロードするライブラリも更新できます。
ジョブまたは JobRun での Python ライブラリの使用
コンソールで新しいジョブを作成する際、[Script Libraries and job parameters (optional)] (スクリプトライブラリおよびジョブパラメータ (任意)) をクリックし、開発エンドポイント作成時と同じ方法で Amazon S3 ライブラリの完全なパスを入力することで、1 つ以上のライブラリ .zip ファイルを指定できます。
s3://bucket/prefix/lib_A.zip,s3://bucket_B/prefix/lib_X.zip
CreateJob (create_job) を呼び出している場合は、以下のようにデフォルトの --extra-py-files
パラメータを使用してデフォルトのライブラリへの 1 つ以上のフルパスを指定できます。
job = glue.create_job(Name='sampleJob
',
Role='Glue_DefaultRole
',
Command={'Name': 'glueetl',
'ScriptLocation': 's3://my_script_bucket/scripts/my_etl_script.py
'},
DefaultArguments={'--extra-py-files': 's3://bucket/prefix/lib_A.zip,s3://bucket_B/prefix/lib_X.zip
'})
その後 JobRun を開始するときに、デフォルトのライブラリ設定を別のもので上書きできます。
runId = glue.start_job_run(JobName='sampleJob
',
Arguments={'--extra-py-files': 's3://bucket/prefix/lib_B.zip
'})
Python の依存関係をプロアクティブに分析する
AWS Glue にデプロイする前に潜在的な依存関係の問題をプロアクティブに特定するには、依存関係分析ツールを使用して、ターゲット AWS Glue 環境に対して Python パッケージを検証できます。
AWS は、AWS Glue 環境専用に設計されたオープンソースの Python 依存関係アナライザーツールを提供します。このツールは AWS Glue サンプルリポジトリで入手でき、デプロイ前にローカルで使用して依存関係を検証できます。
この分析は、一貫した本番稼働用デプロイのためにすべてのライブラリバージョンを固定するという推奨プラクティスを依存関係が確実に遵守するのに役立ちます。詳細については、ツールの README
AWS Glue Python Dependency Analyzer は、ターゲット AWS Glue 環境に一致するプラットフォーム固有の制約で pip のインストールをシミュレートすることで、固定されていない依存関係とバージョン競合を特定するのに役立ちます。
# Analyze a single Glue job python glue_dependency_analyzer.py -j my-glue-job # Analyze multiple jobs with specific AWS configuration python glue_dependency_analyzer.py -j job1 -j job2 --aws-profile production --aws-region us-west-2
このツールでは、次のフラグが付けられます。
-
ジョブ実行間で異なるバージョンをインストールできる固定されていない依存関係
-
パッケージ間のバージョン競合
-
ターゲット AWS Glue 環境で使用できない依存関係
Amazon Q Developer は、生成人工知能 (AI) を活用した会話型アシスタントであり、AWS アプリケーションの理解、構築、拡張、運用を支援します。Amazon Q の入門ガイドの手順に従ってダウンロードできます。
Amazon Q Developer を使用して、Python の依存関係によるジョブの失敗を分析および修正できます。ジョブ <Job-Name> プレースホルダーを Glue ジョブの名前に置き換えて、次のプロンプトを使用することをお勧めします。
I have an AWS Glue job named <Job-Name> that has failed due to Python module installation conflicts. Please assist in diagnosing and resolving this issue using the following systematic approach. Proceed once sufficient information is available. Objective: Implement a fix that addresses the root cause module while minimizing disruption to the existing working environment. Step 1: Root Cause Analysis • Retrieve the most recent failed job run ID for the specified Glue job • Extract error logs from CloudWatch Logs using the job run ID as a log stream prefix • Analyze the logs to identify: • The recently added or modified Python module that triggered the dependency conflict • The specific dependency chain causing the installation failure • Version compatibility conflicts between required and existing modules Step 2: Baseline Configuration Identification • Locate the last successful job run ID prior to the dependency failure • Document the Python module versions that were functioning correctly in that baseline run • Establish the compatible version constraints for conflicting dependencies Step 3: Targeted Resolution Implementation • Apply pinning by updating the job's additional_python_modules parameter • Pin only the root cause module and its directly conflicting dependencies to compatible versions, and do not remove python modules unless necessary • Preserve flexibility for non-conflicting modules by avoiding unnecessary version constraints • Deploy the configuration changes with minimal changes to the existing configuration and execute a validation test run. Do not change the Glue versions. Implementation Example: Scenario: Recently added pandas==2.0.0 to additional_python_modules Error: numpy version conflict (pandas 2.0.0 requires numpy>=1.21, but existing job code requires numpy<1.20) Resolution: Update additional_python_modules to "pandas==1.5.3,numpy==1.19.5" Rationale: Use pandas 1.5.3 (compatible with numpy 1.19.5) and pin numpy to last known working version Expected Outcome: Restore job functionality with minimal configuration changes while maintaining system stability.
プロンプトは Q に次のように指示します。
-
最後に失敗したジョブ実行 ID を取得する
-
関連するログと詳細を検索する
-
変更された Python パッケージを検出するため、正常なジョブ実行を検索する
-
設定を修正し、別のテストランをトリガーする
AWS Glue で提供済みの Python モジュール
これらの提供済みモジュールのバージョンを変更するには、--additional-python-modules
ジョブパラメータにより新しいバージョンを指定します。