LoginSignup
8
5

More than 3 years have passed since last update.

AWS Lambdaでpsycopg2を使う

Last updated at Posted at 2019-07-13

前書き

Redshiftにquery投げるバッチをlambda使って書いてデプロイするとこんなエラーになった
ローカルでは動くのに。

ModuleNotFoundError: No module named 'psycopg2._psycopg'

一応こういう方法で回避もできるがそうするとlocalで動かすのがめんどくさくなる。
https://github.com/jkehler/awslambda-psycopg2

解決策

これでOK!
https://github.com/Miserlou/lambda-packages
READEMEにも書いてある通りzappaと組み合わせて使うととても楽
zappaってflask使うケースしか見つからないけどlambdaをcronで動かすだけという使い方もできます。

完成品はこちら

pipenv

pythonの開発環境に関して深入りする気は無いですがここではpipenv使います
必要なライブラリのインストールしてPipenvシェルを有効化

$ pipenv install
$ pipenv install zappa
$ pipenv install psycopg2
$ pipenv install psycopg2-binary  // これがないとlambda上で動かなかった。
$ pipenv install --dev pytest
$ pipenv shell

zappa

zappaの設定に関してはいろいろ記事があるので説明は割愛しますがこんな感じ

$ zappa init

Your Zappa configuration can support multiple production stages, like 'dev', 'staging', and 'production'.
What do you want to call this environment (default 'dev'):

enter

AWS Lambda and API Gateway are only available in certain regions. Let's check to make sure you have a profile set up in one that will work.
We found the following profiles: default, mine. Which would you like us to use? (default 'default'):

お好みでどうぞ。
僕は自分のアカウントでmineというprofileを作っているのでそちらを使っています。
awsのアカウントってどうしてもいくつか必要になってしまうので何か指定しておいたほうが無難だと思います。

Your Zappa deployments will need to be uploaded to a private S3 bucket.
If you don't have a bucket yet, we'll create one for you too.
What do you want to call your bucket? (default 'zappa-xxxxx'):

zappaが使うs3 bucket。特別な理由がなければそのままenter

What's the modular path to your app's function?
This will likely be something like 'your_module.app'.
Where is your app's function?: 

今回はlambdaだけなので使わないです。
あとで消すので適当にtest.appとか入れておきます。

You can optionally deploy to all available regions in order to provide fast global service.
If you are using Zappa for the first time, you probably don't want to do this!
Would you like to deploy this application globally? (default 'n') [y/n/(p)rimary]:

いらないよ!って言ってくれているのでそのままenter

Okay, here's your zappa_settings.json:

{
    "dev": {
        "app_function": "test.app",
        "aws_region": "ap-northeast-1",
        "profile_name": "mine",  // 自分のawsのprofile
        "project_name": "zappa-psql",
        "runtime": "python3.7",
        "s3_bucket": "zappa-xxxx" // uniqなS3バケット名
    }
}

Does this look okay? (default 'y') [y/n]:

enterでzappa_settings.jsonができるので編集

{
    "dev": {
        "app_function": "test.app",  この行を削除する
        "aws_region": "ap-northeast-1",
        "profile_name": "mine",
        "project_name": "zappa-psql",
        "apigateway_enabled": false, これを追加
        "runtime": "python3.7",
        "s3_bucket": "zappa-xxxx"
    }
}

Redshiftに接続

DBに接続してprintするだけ

scripts/main.py
import os
import psycopg2


def lambda_handler(event, context):
    params = dict(
        user=os.getenv('DB_USER'),
        password=os.getenv('DB_PASSWORD'),
        host=os.getenv('DB_HOST'),
        port=os.getenv('DB_PORT'),
        database=os.getenv('DB_NAME')
    )

    with psycopg2.connect(**params) as connection:
        with connection.cursor() as cur:
            cur.execute("select * from users")
            for user in cur.fetchall():
                print(user)

動作確認

一応動作確認

tests/test_main.py
from unittest import TestCase

from scripts.main import lambda_handler

class SampleTestCase(TestCase):

    def test_lambda_handler(self):
        lambda_handler(None, None)

環境変数を準備。
localで用意したpsqlに接続。
Redshiftとかに直接繋いでもいいけど。

tests/.env
DB_USER=postgres
DB_PASSWORD=
DB_HOST=localhost
DB_PORT=5432
DB_NAME=sample

今更ですがsampleというDBがあってusersっていうテーブルがある前提です

$ psql -Upostgres sample

sample=# \d users;
                       Table "public.users"
 Column |          Type          | Collation | Nullable | Default
--------+------------------------+-----------+----------+---------
 id     | integer                |           | not null |
 name   | character varying(100) |           | not null |

テスト実行

PIPENV_DOTENV_LOCATION=tests/.env pipenv run pytest -v --capture=no

tests/test_main.py::SampleTestCase::test_lambda_handler (1, 'andy')
(2, 'bob')
PASSED

selectの結果が表示された

デプロイ

zappa_settingの追加

環境変数(environment_variables)の追加と、triger(events)の設定。
expressionはcronのフォーマットでもかけるけどさっさと動作確認したいので毎分実行

zappa_settings.json
{
    "dev": {
        "aws_region": "ap-northeast-1",
        "profile_name": "mine",
        "project_name": "zappa-psql",
        "apigateway_enabled": false,
        "runtime": "python3.7",
        "s3_bucket": "zappa-xxxx",
        "events": [{
            "function": "scripts.main.lambda_handler",
            "expression": "rate(1 minute)"
        }],
        "environment_variables": {
          "DB_USER": "your_value",
          "DB_PASSWORD": "your_value",
          "DB_PORT": "your_value",
          "DB_NAME": "your_value"
        }
    }
}

デプロイ実行

zappa deploy dev

aws consoleで作ったlambdaを確認

cloudwatchにselectの結果が表示されるのを待つ

後始末

zappa undeploy dev
Are you sure you want to undeploy? [y/n] y
8
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
5