web-dev-qa-db-ja.com

AWSLambdaがLXMLをインポートしない

AWS Lambda内でLXMLモジュールを使用しようとしていますが、うまくいきません。次のコマンドを使用してLXMLをダウンロードしました。

pip install lxml -t folder

ラムダ関数デプロイメントパッケージにダウンロードします。他のすべてのラムダ関数と同じようにラムダ関数のコンテンツを圧縮し、AWSLambdaにアップロードしました。

ただし、何を試しても、関数を実行すると次のエラーが発生します。

Unable to import module 'handler': /var/task/lxml/etree.so: undefined symbol: PyFPE_jbuf

ローカルで実行しても問題はありません。この問題が発生するのは、Lambdaで実行したときだけです。

11
user3024827

私は同じ問題に直面しました。

RaphaëlBraud によって投稿されたリンクは役に立ちました。これも役に立ちました: https://nervous.io/python/aws/lambda/2016/02/17/scipy-pandas-lambda /

2つのリンクを使用して、lxmlおよびその他の必要なパッケージを正常にインポートできました。これが私が従ったステップです:

  • Amazon LinuxAMIでec2マシンを起動します
  • 次のスクリプトを実行して、依存関係を蓄積します。

    set -e -o pipefail
    Sudo yum -y upgrade
    Sudo yum -y install gcc python-devel libxml2-devel libxslt-devel
    
    virtualenv ~/env && cd ~/env && source bin/activate
    pip install lxml
    for dir in lib64/python2.7/site-packages \
         lib/python2.7/site-packages
    do
    if [ -d $dir ] ; then
       pushd $dir; Zip -r ~/deps.Zip .; popd
    fi
    done  
    mkdir -p local/lib
    cp /usr/lib64/ #list of required .so files
    local/lib/
    Zip -r ~/deps.Zip local/lib
    
  • link で指定されているようにハンドラーファイルとワーカーファイルを作成します。サンプルファイルの内容:

handler.py

import os
import subprocess


libdir = os.path.join(os.getcwd(), 'local', 'lib')

def handler(event, context):
    command = 'LD_LIBRARY_PATH={} python worker.py '.format(libdir)
    output = subprocess.check_output(command, Shell=True)

    print output

    return

worker.py:

import lxml

def sample_function( input_string = None):
    return "lxml import successful!"

if __name__ == "__main__":
    result = sample_function()
    print result
  • ハンドラーとワーカーをZipファイルに追加します。

上記の手順の後、Zipファイルの構造は次のようになります。

deps 
├── handler.py
├── worker.py 
├── local
│   └── lib
│       ├── libanl.so
│       ├── libBrokenLocale.so
|       ....
├── lxml
│   ├── builder.py
│   ├── builder.pyc
|       ....
├── <other python packages>
  • ラムダ関数を作成するときは、必ず正しいハンドラー名を指定してください。上記の例では、「handler.handler」になります。

お役に立てれば!

8
Mask

これらの答えを拡張すると、次のことがうまく機能することがわかりました。

ここでのオチは、静的ライブラリを使用してlxmlをpythonコンパイルし、サイトパッケージではなく現在のディレクトリにインストールすることです。

また、個別のworker.pyを必要とせず、LD_LIBRARY_PATHをいじることなく、通常どおりpythonコードを記述できることも意味します。

Sudo yum groupinstall 'Development Tools'
Sudo yum -y install python36-devel python36-pip
Sudo ln -s /usr/bin/pip-3.6 /usr/bin/pip3
mkdir lambda && cd lambda
STATIC_DEPS=true pip3 install -t . lxml
Zip -r ~/deps.Zip *

それを次のレベルに引き上げるには、サーバーレスとDockerを使用してすべてを処理します。これを示すブログ投稿は次のとおりです: https://serverless.com/blog/serverless-python-packaging/

4
Foofy

マスクの答えを少し拡張します。特にlxmlをインストールする場合、libxsltおよびlibxml2ライブラリはAWSラムダを実行するAMIにすでにインストールされています。したがって、サブプロセスを開始する必要はありません。その回答のように異なるLD_LIBRARY_PATHただし、AMIイメージでpip install lxmlを実行する必要があります(クロスコンパイルも可能かもしれませんが、方法がわかりません)。

Launch an ec2 machine with Amazon Linux AMI
Run the following script to accumulate dependencies:
set -e -o pipefail
Sudo yum -y upgrade
Sudo yum -y install gcc python-devel libxml2-devel libxslt-devel

virtualenv ~/env && cd ~/env && source bin/activate
pip install lxml
for dir in lib64/python2.7/site-packages \
    lib/python2.7/site-packages
do
    if [ -d $dir ] ; then
        pushd $dir; Zip -r ~/deps.Zip .; popd
    fi
done 

マークスの回答の最後のステップは省略されていることに注意してください。 lxmlは、ハンドラーメソッドを含むpythonファイルから直接使用できます。

2

AWS LambdaはLinuxの特別なバージョンを使用しています(私が見る限り)。

「pipinstalla_package -t folder」を使用すると、Lambdaに送信されるアーカイブ内に依存関係をパッケージ化するのに役立つため、通常は適切ですが、ライブラリ、特にバイナリライブラリはバージョンと互換性がある必要がありますOSとラムダのPython。

Python: https://docs.python.org/2/library/xml.etree.elementtree.html に含まれているxmlモジュールを使用できます

本当にlxmlが必要な場合、このリンクはLambdaの共有ライブラリをコンパイルする方法に関するいくつかのトリックを提供します: http://www.perrygeo.com/running-python-with-compiled-code-on-aws-lambda。 html

2
Raphaël Braud

serverless フレームワークとその組み込みのDocker機能を使用してこれを解決しました。

要件:.awsフォルダーにアクセス可能なAWSプロファイルがあります。

まず、説明されているようにサーバーレスフレームワークをインストールします ここ 。次に、コマンドserverless create --template aws-python3 --name my-lambdaを使用して構成ファイルを作成できます。単純な「hello」関数を使用してserverless.ymlファイルとhandler.pyを作成します。それがsls deployで機能するかどうかを確認できます。それが機能する場合は、サーバーレスを使用する準備ができています。

次に、バンドルPython要件。sls plugin install --name serverless-python-requirementsからインストールできます。 "serverless-python-requirements" という名前の追加のプラグインが必要です。

このプラグインは、不足しているlxmlパッケージを解決するために必要なすべての魔法が発生する場所です。 custom-> pythonRequirementsセクションで、dockerizePip: non-linuxプロパティを追加するだけです。 serverless.ymlファイルは次のようになります。

service: producthunt-crawler

provider:
  name: aws
  runtime: python3.8

functions:
  hello:
    # some handler that imports lxml
    handler: handler.hello

plugins:
  - serverless-python-requirements

custom:
  pythonRequirements:
    fileName: requirements.txt
    dockerizePip: non-linux

    # Omits tests, __pycache__, *.pyc etc from dependencies
    slim: true

これにより、事前設定されたDockerコンテナ内でpython要件のバンドルが実行されます。その後、sls deployを実行して魔法が発生することを確認し、次にsls invoke -f my_functionを実行して確認できます。それが機能すること。

サーバーレスを使用して後でdockerizePip: non-linuxオプションをデプロイおよび追加した場合は、すでに構築されている要件をsls requirements cleanでクリーンアップしてください。それ以外の場合は、すでに構築されているものを使用します。

1
akohout