前書き
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するだけ
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)
動作確認
一応動作確認
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とかに直接繋いでもいいけど。
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のフォーマットでもかけるけどさっさと動作確認したいので毎分実行
{
"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