将 Python 库与 Amazon Glue 结合使用 - Amazon Glue
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

将 Python 库与 Amazon Glue 结合使用

您可以安装其他 Python 模块和库,以便与 Amazon Glue ETL 一起使用。对于 Amazon Glue 2.0 及更高版本,Amazon Glue 使用 Python Package Installer(pip3)安装 Amazon Glue ETL 使用的其他模块。AmazonGlue 提供了多种选项,来将其他 Python 模块引入 Amazon Glue 作业环境。您可以通过“—addition-python-modules”参数,从而使用 Python wheel 文件、需求文件(requirement.txt,Amazon Glue 5.0 及更高版本)或逗号分隔的 Python 模块列表引入模块。

根据 Amazon 责任共担模式,您负责管理您在 Amazon Glue ETL 作业中使用的其他 Python 模块、库及其依赖项。这包括应用更新和安全补丁。

Amazon Glue 不支持在作业环境中编译原生代码。但是,Amazon Glue 作业会在 Amazon 托管的 Linux 环境中运行。您可通过 Python wheel 文件,以编译后的形式提供原生依赖项。有关 Amazon Glue 版本兼容性的详细信息,请参阅上表。

如果您的 Python 依赖项以传递方式依赖于原生编译代码,则可能会遇到以下限制:Amazon Glue 不支持在作业环境中编译原生代码。但是,Amazon Glue 作业会在 Amazon 托管的 Linux 环境中运行。您可通过 Wheel 分发,以编译后的形式提供原生依赖项。有关 Amazon Glue 版本兼容性的详细信息,请参阅上表。

重要

使用不兼容的依赖项可能会导致运行时问题,尤其是对于具有原生扩展的库,因为这些库必须与目标环境的架构和系统库相匹配。每个 Amazon Glue 版本都在特定的 Python 版本上运行,其中包含预装的库和系统配置。

使用 pip 在 Amazon Glue 2.0 或更高版本中安装其他 Python 模块

Amazon Glue 使用 Python Package Installer(pip3)安装 Amazon Glue ETL 使用的其他模块。您可以将 --additional-python-modules 参数与逗号分隔的 Python 模块列表结合使用,以添加新模块或更改现有模块的版本。通过将分发上传到 Amazon S3,然后在模块列表中包含到 Amazon S3 对象的路径,您可以安装库的自定义分发。

您可以使用 --python-modules-installer-option 参数将其他选项传递给 pip3。例如,您可以传递 "--upgrade" 以升级 "--additional-python-modules" 指定的包。有关更多示例,请参阅使用 Amazon Glue 2.0 从 Spark ETL 工作负载仪表盘构建 Python 模块

Amazon Glue 支持使用存储在 Amazon S3 中的 wheel (.whl) 文件安装自定义 Python 包。要在 Amazon Glue 作业中包含 wheel 文件,请在 --additional-python-modules 作业参数中提供以逗号分隔的 wheel 文件(存储在 s3 中)列表。例如:

--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 Amazon Glue 2.0

您可以在 Amazon Glue 控制台的“作业参数”字段中指定 --additional-python-modules,也可以通过在 Amazon SDK 中更改作业参数指定它。有关设置作业参数的更多信息,请参阅在 Amazon Glue 作业中使用作业参数

在 Amazon Glue 5.0 中,您可以提供事实标准 requirements.txt 来管理 Python 库依赖项。为此,请提供下面的两个作业参数:

  • 键:--python-modules-installer-option

    值:-r

  • 键:--additional-python-modules

    值:s3://path_to_requirements.txt

Amazon 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 中使用未固定的库版本,以确保作业具有可靠且确定的 Amazon Glue 环境。

将 wheel 用于直接依赖项时,如果库版本未正确固定,则可能会引入不兼容版本的传递依赖项。作为最佳实践,应固定所有库版本以保持 Amazon Glue 作业的一致性。AmazonGlue 建议将您的 python 环境打包到 wheel 文件中,从而确保生产工作负载的一致性和可靠性。

Amazon Glue 允许通过传递 --additional-python-modules 参数,将以逗号分隔的 Python 模块列表作为值,从而更新或添加新的 Python 模块。例如,可使用以下键/值来更新/添加 scikit-learn 模块:"--additional-python-modules", "scikit-learn==0.21.3"。您可以通过两种方式直接配置 python 模块。

  • 已固定的 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 模块时,Amazon Glue 建议使用固定的库版本来确保 Amazon Glue 作业环境的一致性。如果使用未固定的库版本,则会拉取最新版本的 python 模块,但这可能会引入重大更改或不兼容的 python 模块,导致在 Amazon Glue 作业环境中安装 python 失败,并进而导致作业失败。我们建议客户不要将未固定的库版本用于生产工作负载。作为一项最佳实践,Amazon Glue 建议将您的 python 环境打包到 wheel 文件中,从而确保生产工作负载的一致性和可靠性。

在 Amazon Glue 中安装其他 Python 库的最佳实践

(推荐)将 Python 环境打包为单个 wheel 文件

为确保环境的安全性和一致性,Amazon Glue 建议为您的 python 环境拍摄快照并打包到 wheel 文件中。此操作的优势在于,参考 python 模块的 python 环境及其传递依赖项将被锁定。这样就可以确保在上游存储库(例如 PyPI)或依赖项引入不兼容的更新时,您的 Amazon Glue 作业不会受到影响。

然后就可以使用 --additional-python-modules 标志在 Amazon Glue 作业中使用该文件。

重要

您必须在与正在运行的 Amazon Glue 版本相似的环境中运行以下脚本。请参阅 Glue 环境详细信息表,并确保您使用的基本操作系统映像和 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 文件

Amazon Glue 使用 PySpark 在 Amazon Glue ETL 作业中包含 Python 文件。如果可用,您希望使用 --additional-python-modules 管理依赖项。您可以使用 --extra-py-files 作业参数以包含 Python 文件。依赖关系必须托管在 Amazon S3 中,参数值应为逗号分隔的 Amazon S3 路径列表,且不含空格。此功能的行为类似于您将在 Spark 中使用的 Python 依赖项管理。有关 Spark 中 Python 依赖项管理的更多信息,请参阅 Apache Spark 文档中的 Using PySpark Native Features(使用 PySpark 原生功能)页面。如果其他代码未打包,或您使用现有工具链迁移 Spark 程序以管理依赖项时,--extra-py-files 非常有用。为使依赖项工具可维护,您必须在提交之前捆绑依赖项。

使用视觉对象转换的编程脚本

使用 Amazon Glue Studio 可视化界面创建 Amazon Glue 作业时,您可以使用托管式的数据转换节点和自定义视觉对象转换来转换数据。有关托管式数据转换节点的更多信息,请参阅 使用 Amazon Glue 托管转换转换数据。有关自定义视觉对象转换的更多信息,请参阅 使用自定义视觉转换来转换数据 。只有当作业的语言设置为使用 Python 时,才能生成使用视觉对象转换的脚本。

生成使用视觉对象转换的 Amazon Glue 作业时,Amazon Glue Studio 将使用作业配置中的 --extra-py-files 参数将这些转换包含在运行时环境中。有关任务参数的更多信息,请参阅 在 Amazon Glue 作业中使用作业参数。对生成的脚本或运行时环境进行更改时,需要保留此作业配置以确保脚本的成功运行。

压缩库以用于包含

除非库包含在单个 .py 文件中,否则它应打包到 .zip 存档中。包目录应该位于存档文件的根部,并且必须包含一个针对该包的 __init__.py 文件。然后,Python 将能够以正常方式导入包。

如果您的库仅在一个 .py 文件中包含单个 Python 模块,您无需将其放入 .zip 文件。

加载 Amazon Glue Studio 笔记本中的 Python 库

要在 Amazon Glue Studio Notebook 中指定 Python 库,请参阅安装其他 Python 模块

通过 Amazon Glue 0.9/1.0 在开发端点中加载 Python 库

如果对不同的 ETL 脚本使用不同的库集,则可以为每个集设置单独的开发终端节点,也可以覆盖每次您切换脚本时开发终端节点加载的库 .zip 文件。

在创建开发终端节点时,您可以使用控制台为其指定一个或多个库 .zip 文件。在分配名称和 IAM 角色后,请选择 Script Libraries and job parameters (optional) (脚本库和任务参数(可选)),然后在 Python library path (脚本库路径) 框中输入库 .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

类似地,您可以使用 Amazon Glue API 指定库文件。当您通过调用 CreateDevEndpoint 操作(Python:create_dev_endpoint) 创建开发终端节点时,可以通过如下所示的调用在 ExtraPythonLibsS3Path 参数中指定库的一个或多个完整路径:

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")

当您更新一个开发终端节点时,还可以通过在调用 UpdateDevEndpoint (update_dev_endpoint) 时使用 DevEndpointCustomLibraries 对象并将 UpdateEtlLibraries 参数设置为 True 来更新它所加载的库。

在作业或作业运行中使用 Python 库

当您在控制台上创建新任务时,可以通过选择 Script Libraries and job parameters (optional) (脚本库和任务参数 (可选)) 并输入完整的 Amazon S3 库路径来指定一个或多个库 .zip 格式文件(方法与创建开发终端节点时相同):

s3://bucket/prefix/lib_A.zip,s3://bucket_B/prefix/lib_X.zip

如果您正在调用 CreateJob (create_job),则可以使用 --extra-py-files 默认参数指定默认库的一个或多个完整路径,如下所示:

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'})

然后,当您启动作业运行时,可以使用其他设置覆盖默认库设置:

runId = glue.start_job_run(JobName='sampleJob', Arguments={'--extra-py-files': 's3://bucket/prefix/lib_B.zip'})

主动分析 Python 依赖项

要在部署到 Amazon Glue 之前主动识别潜在的依赖项问题,您可以使用依赖项分析工具,根据目标 Amazon Glue 环境验证您的 Python 包。

Amazon 提供了专为 Amazon Glue 环境设计的开源 Python 依赖项分析器工具。该工具可从 Amazon Glue 示例存储库中获取并在本地使用,从而在部署之前验证依赖项。

此分析有助于确保依赖项遵循推荐的做法,即固定所有库版本以确保生产部署的一致性。有关更多详细信息,请参阅该工具的 README 文件。

Amazon Glue Python 依赖项分析器通过使用与目标 Amazon 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

该工具将标记以下问题:

  • 未固定的依赖项,这可能会导致在作业运行中安装不同的版本

  • 软件包之间的版本冲突

  • 不支持目标 Amazon Glue 环境的依赖项

Amazon Q 开发者版是一款由生成式人工智能(AI)提供支持的对话式助手,可为您理解、构建、扩展和操作 Amazon 应用程序提供帮助。您可以按照 Amazon Q 入门指南中的说明进行下载该工具。

Amazon Q 开发者版可用于分析和修复因 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 执行以下操作:

  1. 获取最新的失败作业运行 ID

  2. 查找关联的日志和详细信息

  3. 查找成功的作业运行以检测任何发生更改的 Python 软件包

  4. 执行配置修复并启动新的测试运行

Amazon Glue 中已提供的 Python 模块

要更改这些已提供模块的版本,请使用 --additional-python-modules 作业参数提供新版本。

Amazon Glue version 5.0

Amazon Glue 5.0 版包括以下开箱即用的 Python 模块:

  • aiobotocore==2.13.1

  • aiohappyeyeballs==2.3.5

  • aiohttp==3.10.1

  • aioitertools==0.11.0

  • aiosignal==1.3.1

  • appdirs==1.4.4

  • attrs==24.2.0

  • boto3==1.34.131

  • botocore==1.34.131

  • certifi==2024.7.4

  • charset-normalizer==3.3.2

  • contourpy==1.2.1

  • cycler==0.12.1

  • fonttools==4.53.1

  • frozenlist==1.4.1

  • fsspec==2024.6.1

  • idna==2.10

  • jmespath==0.10.0

  • kaleido==0.2.1

  • kiwisolver==1.4.5

  • matplotlib==3.9.0

  • multidict==6.0.5

  • numpy==1.26.4

  • packaging==24.1

  • pandas==2.2.2

  • pillow==10.4.0

  • pip==23.0.1

  • plotly==5.23.0

  • pyarrow==17.0.0

  • pyparsing==3.1.2

  • python-dateutil==2.9.0.post0

  • pytz==2024.1

  • requests==2.32.2

  • s3fs==2024.6.1

  • s3transfer==0.10.2

  • seaborn==0.13.2

  • setuptools==59.6.0

  • six==1.16.0

  • tenacity==9.0.0

  • tzdata==2024.1

  • urllib3==1.25.10

  • virtualenv==20.4.0

  • wrapt==1.16.0

  • yarl==1.9.4

Amazon Glue version 4.0

Amazon Glue 4.0 版包括以下开箱即用的 Python 模块:

  • aiobotocore==2.4.1

  • aiohttp==3.8.3

  • aioitertools==0.11.0

  • aiosignal==1.3.1

  • async-timeout==4.0.2

  • asynctest==0.13.0

  • attrs==22.2.0

  • avro-python3==1.10.2

  • boto3==1.24.70

  • botocore==1.27.59

  • certifi==2021.5.30

  • chardet==3.0.4

  • charset-normalizer==2.1.1

  • click==8.1.3

  • cycler==0.10.0

  • Cython==0.29.32

  • fsspec==2021.8.1

  • idna==2.10

  • importlib-metadata==5.0.0

  • jmespath==0.10.0

  • joblib==1.0.1

  • kaleido==0.2.1

  • kiwisolver==1.4.4

  • matplotlib==3.4.3

  • mpmath==1.2.1

  • multidict==6.0.4

  • nltk==3.7

  • numpy==1.23.5

  • packaging==23.0

  • pandas==1.5.1

  • patsy==0.5.1

  • pillow==9.4.0

  • pip==23.0.1

  • plotly==5.16.0

  • pmdarima==2.0.1

  • ptvsd==4.3.2

  • pyarrow==10.0.0

  • pydevd==2.5.0

  • pyhocon==0.3.58

  • pymysql==1.0.2

  • pyparsing==2.4.7

  • python-dateutil==2.8.2

  • pytz==2021.1

  • PyYAML==6.0.1

  • regex==2022.10.31

  • requests==2.23.0

  • s3fs==2022.11.0

  • s3transfer==0.6.0

  • scikit-learn==1.1.3

  • scipy==1.9.3

  • setuptools==49.1.3

  • six==1.16.0

  • statsmodels==0.13.5

  • subprocess32==3.5.4

  • sympy==1.8

  • tbats==1.1.0

  • threadpoolctl==3.1.0

  • tqdm==4.64.1

  • typing_extensions==4.4.0

  • urllib3==1.25.11

  • wheel==0.37.0

  • wrapt==1.14.1

  • yarl==1.8.2

  • zipp==3.10.0

Amazon Glue version 3.0

Amazon Glue 3.0 版包括以下开箱即用的 Python 模块:

  • aiobotocore==1.4.2

  • aiohttp==3.8.3

  • aioitertools==0.11.0

  • aiosignal==1.3.1

  • async-timeout==4.0.2

  • asynctest==0.13.0

  • attrs==22.2.0

  • avro-python3==1.10.2

  • boto3==1.18.50

  • botocore==1.21.50

  • certifi==2021.5.30

  • chardet==3.0.4

  • charset-normalizer==2.1.1

  • click==8.1.3

  • cycler==0.10.0

  • Cython==0.29.4

  • docutils==0.17.1

  • enum34==1.1.10

  • frozenlist==1.3.3

  • fsspec==2021.8.1

  • idna==2.10

  • importlib-metadata==6.0.0

  • jmespath==0.10.0

  • joblib==1.0.1

  • kiwisolver==1.3.2

  • matplotlib==3.4.3

  • mpmath==1.2.1

  • multidict==6.0.4

  • nltk==3.6.3

  • numpy==1.19.5

  • packaging==23.0

  • pandas==1.3.2

  • patsy==0.5.1

  • pillow==9.4.0

  • pip==23.0

  • pmdarima==1.8.2

  • ptvsd==4.3.2

  • pyarrow==5.0.0

  • pydevd==2.5.0

  • pyhocon==0.3.58

  • pymysql==1.0.2

  • pyparsing==2.4.7

  • python-dateutil==2.8.2

  • pytz==2021.1

  • PyYAML==5.4.1

  • regex==2022.10.31

  • requests==2.23.0

  • s3fs==2021.8.1

  • s3transfer==0.5.0

  • scikit-learn==0.24.2

  • scipy==1.7.1

  • six==1.16.0

  • spark==1.0

  • statsmodels==0.12.2

  • subprocess32==3.5.4

  • sympy==1.8

  • tbats==1.1.0

  • threadpoolctl==3.1.0

  • tqdm==4.64.1

  • typing_extensions==4.4.0

  • urllib3==1.25.11

  • wheel==0.37.0

  • wrapt==1.14.1

  • yarl==1.8.2

  • zipp==3.12.0

Amazon Glue version 2.0

Amazon Glue 2.0 版包括以下开箱即用的 Python 模块:

  • avro-python3==1.10.0

  • awscli==1.27.60

  • boto3==1.12.4

  • botocore==1.15.4

  • certifi==2019.11.28

  • chardet==3.0.4

  • click==8.1.3

  • colorama==0.4.4

  • cycler==0.10.0

  • Cython==0.29.15

  • docutils==0.15.2

  • enum34==1.1.9

  • fsspec==0.6.2

  • idna==2.9

  • importlib-metadata==6.0.0

  • jmespath==0.9.4

  • joblib==0.14.1

  • kiwisolver==1.1.0

  • matplotlib==3.1.3

  • mpmath==1.1.0

  • nltk==3.5

  • numpy==1.18.1

  • pandas==1.0.1

  • patsy==0.5.1

  • pmdarima==1.5.3

  • ptvsd==4.3.2

  • pyarrow==0.16.0

  • pyasn1==0.4.8

  • pydevd==1.9.0

  • pyhocon==0.3.54

  • PyMySQL==0.9.3

  • pyparsing==2.4.6

  • python-dateutil==2.8.1

  • pytz==2019.3

  • PyYAML==5.3.1

  • regex==2022.10.31

  • requests==2.23.0

  • rsa==4.7.2

  • s3fs==0.4.0

  • s3transfer==0.3.3

  • scikit-learn==0.22.1

  • scipy==1.4.1

  • setuptools==45.2.0

  • six==1.14.0

  • spark==1.0

  • statsmodels==0.11.1

  • subprocess32==3.5.4

  • sympy==1.5.1

  • tbats==1.0.9

  • tqdm==4.64.1

  • typing-extensions==4.4.0

  • urllib3==1.25.8

  • wheel==0.35.1

  • zipp==3.12.0