web-dev-qa-db-ja.com

Lambdaでpsycopg2を使用してRedshiftを更新する(Python)

Pythonを使用してLambda関数からRedshiftを更新しようとしています。これを行うには、2つのコードフラグメントを結合しようとしています。個別に実行すると、両方のフラグメントが機能します。

  1. PyDev for EclipseからRedshiftを更新する

    import psycopg2
    
    conn_string = "dbname='name' port='0000' user='name' password='pwd' Host='url'"
    conn = psycopg2.connect(conn_string)
    
    cursor = conn.cursor()
    
    cursor.execute("UPDATE table SET attribute='new'")
    conn.commit()
    cursor.close()
    
  2. S3バケットにアップロードされたコンテンツの受信(Lambdaで利用可能な事前構築テンプレート)

    from __future__ import print_function
    
    import json
    import urllib
    import boto3
    
    print('Loading function')
    
    s3 = boto3.client('s3')
    
    
    def lambda_handler(event, context):
        #print("Received event: " + json.dumps(event, indent=2))
    
        # Get the object from the event and show its content type
        bucket = event['Records'][0]['s3']['bucket']['name']
        key = urllib.unquote_plus(event['Records'][0]['s3']['object']['key']).decode('utf8')
    
        try:
            response = s3.get_object(Bucket=bucket, Key=key)
            print("CONTENT TYPE: " + response['ContentType'])
            return response['ContentType']
    
        except Exception as e:
            print(e)
            print('Error getting object {} from bucket {}. Make sure they exist and your bucket is in the same region as this function.'.format(key, bucket))
            raise e
    

これらのセグメントは両方とも機能したので、s3へのファイルのアップロード時にRedshiftを更新できるように、それらを組み合わせようとしました。

from __future__ import print_function

import json
import urllib
import boto3
import psycopg2

print('Loading function')

s3 = boto3.client('s3')


def lambda_handler(event, context):
    #print("Received event: " + json.dumps(event, indent=2))

    # Get the object from the event and show its content type
    bucket = event['Records'][0]['s3']['bucket']['name']
    key = urllib.unquote_plus(event['Records'][0]['s3']['object']['key']).decode('utf8')

    conn_string = "dbname='name' port='0000' user='name' password='pwd' Host='url'"

    conn = psycopg2.connect(conn_string)

    cursor = conn.cursor()

    cursor.execute("UPDATE table SET attribute='new'")
    conn.commit()
    cursor.close()

    try:
        response = s3.get_object(Bucket=bucket, Key=key)
        print("CONTENT TYPE: " + response['Body'].read())
        return response['Body'].read()
    except Exception as e:
        print(e)
        print('Error getting object {} from bucket {}. Make sure they exist and your bucket is in the same region as this function.'.format(key, bucket))
        raise e

外部ライブラリを使用しているため、展開パッケージを作成する必要があります。新しいフォルダー(lambda_function1)を作成し、.pyファイル(lambda_function1.py)をそのフォルダーに移動しました。次のコマンドを実行して、psycopg2をそのフォルダーにインストールします。

pip install psycopg2 -t \lambda_function1

次のフィードバックを受け取ります。

Collecting psycopg2
  Using cached psycopg2-2.6.1-cp34-none-win_AMD64.whl
Installing collected packages: psycopg2
Successfully installed psycopg2-2.6.1 

次に、ディレクトリの内容を圧縮しました。そして、そのZipをラムダ関数にアップロードしました。関数が監視するバケットにドキュメントをアップロードすると、cloudwatchログに次のエラーが表示されます。

Unable to import module 'lambda_function1': No module named _psycopg 

ライブラリを見ると、「_ psycopg」という名前の唯一のものは「_psycopg.pyd」です。

この問題の原因は何ですか? LambdaがPython 2.7を使用するときに3.4を使用することは重要ですか?Windowsマシンでファイルの内容を圧縮したことは重要ですか?誰もがlambdaからRedshiftに正常に接続できましたか?

12
awsQuestion

これを機能させるには、psycopg2静的リンクlibpq.so 図書館。このリポジトリをチェックしてください https://github.com/jkehler/awslambda-psycopg2 。それはすでにpsycopg2パッケージをビルドし、それを自分でビルドする方法を示しています。

あなたの質問に戻る:

この問題の原因は何ですか?

psycopg2は、Linux用の静的にリンクされたライブラリでコンパイルされたビルドを作成する必要があります。

LambdaがPython 2.7を使用するときに3.4を使用することは重要ですか?

はい、ラムダは2.7バージョンのみをサポートしています。仮想環境を作成し、そこに必要なすべてのパッケージをインストールするだけです。

Windowsマシンでファイルの内容を圧縮したことは重要ですか?

圧縮したすべてのライブラリをLinuxで実行できる限り、

誰かがラムダからRedshiftに正常に接続できましたか?

はい。

16
Vor

私はこの同じ問題に出くわしました。次のように問題を説明した他の回答で指摘された同じ githubプロジェクト に偶然出会いました:

AWS LambdaにAMIイメージに必要なPostgreSQLライブラリがないため、デフォルトの動的リンクの代わりにPostgreSQL libpq.soライブラリを静的にリンクしたlibpqライブラリを使用してpsycopg2をコンパイルする必要がありました。

これは前の回答で指摘されており、私は静的にリンクされたPostgreSQLライブラリを備えたpsycopg2のバージョンを自分で構築するための指示に従い始めました。しかし、はるかに簡単なオプションを見つけました。 psycopg2 github page で次のことに気付きました:

PyPI:からpsycopg2-binaryパッケージをインストールすることで、コンパイラや外部ライブラリを必要としないスタンドアロンパッケージを取得することもできます。

$ pip install psycopg2-binary

バイナリパッケージは、開発とテストの実用的な選択肢ですが、本番環境では、ソースからビルドされたパッケージを使用することをお勧めします。

Psycopg2-binaryパッケージをpipインストールして私のrequirements.txtファイルに含めたところ、ラムダ関数からpostgresqlデータベースに問題なく接続できました。私は chalice を使用していますが、これを強くお勧めします。 psycopg2は本番環境ではバイナリバージョンを使用しないことをお勧めしますが、バイナリバージョンを使用するか、自分でコンパイルして静的にリンクするかには大きな違いはありません。私がそれについて間違っているなら誰かが私を訂正してください。

7
jshammon

Awsラムダでpsycopg2を使用するには、import aws-psycopg2を使用します

Awsはpsycopg2をサポートしますが、aws自体にpsycopg2のコンパイル済みライブラリがあるため、psycopg2をインポートする方法は少し異なります。したがって、インポートする必要があるのはaws-psycopg2を使用することです。

2
Sumit Chhabra

ラムダでpsycopg2を使用する別の方法(Windowsでプログラミングし、python 3.6を使用している場合)

  1. あなたのマシンでpythonというディレクトリを作成してください
  2. https://pypi.org/project/psycopg2-binary/ からlib psycopg2をダウンロードし、正しいパッケージを検索します(Amazon linuxは86_64):psycopg2_binary-2.8.4-cp36-cp36m-manylinux1_x86_64 .whl
  3. これを、作成したdirectorie python=に解凍します。whlには7-Zipを使用できます
  4. ディレクトリpythonを圧縮する
  5. 次にAWS lambdaパネルで、所有しているpython.Zipでレイヤーを作成します
  6. 最後に、レイヤーをラムダ関数に追加します
0

ああ少年!いくつかの答えは本当に素晴らしく、うまくいくかもしれません!ちょうどこれに出くわした https://pypi.org/project/aws-psycopg2/ そしてそれは私にとって魅力のように働いた。手順:

mkdir aws-psycopg2

cd aws-psycopg2

vi get_layer_packages.sh

export PKG_DIR="python"

rm -rf ${PKG_DIR} && mkdir -p ${PKG_DIR}

docker run --rm -v $(pwd):/foo -w /foo lambci/lambda:build-python3.6 \
    pip install -r requirements.txt --no-deps -t ${PKG_DIR}

vi requirements.txt

aws-psycopg2

次に行う:chmod + x get_layer_packages.sh

./get_layer_packages.sh

Zip -r aws-psycopg2.Zip。

このZipをAWS Lambdaレイヤーにアップロードしてください!

0
khanna

パッケージが正しいと仮定すると、no module named psycopg2エラーは通常、psycopg2デプロイメントのバイナリファイルがターゲットOSまたはPythonバージョンの場合)に正しくないことを示します。

ラムダの場合、 psycopg2バイナリ が機能することがわかりました(manylinux_x86_64を使用)。まだ報告されていませんが、競合する libssl binaries が存在するため、 segfault のリスクが報告されています。 (これは基本的に上記のjshammonの回答の+1です)

「適切な解決策」はおそらく jkehlers Lambdaがlib_pq.so、しかしそれは現在ssl + py3.7をサポートしておらず、私たちは自分たちでそれを再コンパイルするにはWindowsです。

0
David Stannard