AWS
DynamoDB
sam
lambda
local

AWSのLambdaとDynamoDBのローカル開発(SAM)


概要

AWSのコンソールで割と簡単にLambdaの処理とDynamoDBのテーブルを作成したり、編集したりすることができます。

ただ、チームでやるプロジェクトだと、バージョン管理とローカルのテストが重要になってきます。

SAMのCLIを使うと本物のコンソールを使わなくても、ローカルで動作確認もできますし、簡単にAWSにデプロイもできます。


環境の情報


  • Windows 10

  • Docker for Windows

  • Visual Studio Code

  • Python 3.7 (他のでも大丈夫だと思います)


プロジェクト作成


プロジェクトフォルダーを作成し、VSCodeで開きます。


Pythonの確認

VSCodeのターミナルは【Ctrl+@】で開けます。

sam-lambda-dynamodb> python -V

Python 3.7.2


pipの更新

sam-lambda-dynamodb> python -m pip install --upgrade pip


仮想環境の作成

仮想環境を作ることで、別の環境で構築する時に、Pythonのインストールされているライブラリーのバージョンを簡単に合わせることができるので、ライブラリーのバージョンの違いで問題になることはなくなります。

sam-lambda-dynamodb> python -m venv venv

sam-lambda-dynamodb> .\venv\Scripts\activate
(venv) sam-lambda-dynamodb>

仮想環境に入っていると、左側に(venv)が表示されます。

activateスクリプトを実行できない場合、管理者として以下のコマンドを実行します。

set-executionpolicy remotesigned


仮想環境の中のpipの更新

(venv) sam-lambda-dynamodb> python -m pip install --upgrade pip


VSCodeのWorkspaceの設定

仮想環境のための設定を入れます。

- VSCODEに「Python」というExtensionをインストールします。

- 「F1」を押し、>Preferences: Open Workspace Settings を書きます。

- 「Python: Python Path」の設定を探し、仮想環境のpython.exeのパスを入力します。

- 例:C:\\Users\\path\\to\\sam-lambda-dynamodb\\venv\\Scripts\\python.exe

- 「Python: Venv Path」の設定を探し、仮想環境のベースパスを入力します。

- 例:C:\\Users\\path\\to\\sam-lambda-dynamodb\\venv

- 設定終わると、ワークスペースフォルダーに.vscode/settings.jsonが自動的に作成されます。

- settings.jsonの中身は以下のようになります。


settings.json

{

"python.pythonPath": "C:\\Users\\path\\to\\sam-lambda-dynamodb\\venv\\Scripts\\python.exe",
"python.venvPath": "C:\\Users\\path\\to\\sam-lambda-dynamodb\\venv"
}


仮想環境に必要なライブラリーをインストール

(venv) sam-lambda-dynamodb> pip install aws-sam-cli

(venv) sam-lambda-dynamodb> sam --version
SAM CLI, version 0.11.0
(venv) sam-lambda-dynamodb> pip install awscli
(venv) sam-lambda-dynamodb> aws --version
aws-cli/1.16.101 Python/3.7.2 Windows/10 botocore/1.12.91

他の環境でも同じライブラリーのバージョンになるため、requirements.txtを作成します。

(venv) sam-lambda-dynamodb> pip freeze | Out-File -Encoding UTF8 .\requirements.txt

requirements.txtからインストールしたい時、このコマンドでできます。

pip install -r requirements.txt


SAMのinit処理を実行

(venv) sam-lambda-dynamodb> sam init --runtime python3.7

こちらのコマンドを実行すると、sam-appのフォルダーが作成されます。

hello_worldのデフォルトプロジェクトは設定されているので、試してみましょう。


awsの設定

ローカル用のテスト環境なので、内容はあまり重要ではないです。

(venv) sam-lambda-dynamodb> aws configure

AWS Access Key ID [None]: testid
AWS Secret Access Key [None]: testsecret
Default region name [None]: ap-northeast-1
Default output format [None]: json


hello_worldのテンプレートのテスト



  • sam_appに入り、ビルドを実行

(venv) sam-lambda-dynamodb> cd .\sam-app\

(venv) sam-lambda-dynamodb\sam-app> sam build


  • dockerは実行中か確認し、APIを実行

(venv) sam-lambda-dynamodb\sam-app> sam local start-api


  • hello_worldのapiを実行

ブラウザーで「localhost:3000/hello」にアクセスします。

画面に{"message": "hello world"}が表示されたら成功です。


ローカルのDynamoDBの設定

Ctrl+C」でhello_worldのlambdaを止めます。

DynamoDBをプルします。

(venv) sam-lambda-dynamodb\sam-app> docker pull amazon/dynamodb-local

lambdaとdynamodbは同じネットワークにあると楽なので、dockerのネットワークを作成します。

(venv) sam-lambda-dynamodb\sam-app> docker network create lambda-local

containerを作成し、runします。

(venv) sam-lambda-dynamodb\sam-app> docker run --network lambda-local --name dynamodb -p 8000:8000 amazon/dynamodb-local -jar DynamoDBLocal.jar -sharedDb

runの後は「Ctrl+C」を押します。

PS: 上のコマンドを1回目の時にしか使わないです。次の実行の時「docker start dynamodb」のコマンドを使います。


DynamoDBのテーブルを作成


  • プロジェクトフォルダのに「DynamoDB」のフォルダを作成し、AccessTable.jsonのファイルを作成します。


AccessTable.json

{

"TableName": "Access",
"KeySchema": [
{
"AttributeName": "Path",
"KeyType": "HASH"
},
{
"AttributeName": "Date",
"KeyType": "RANGE"
}
],
"AttributeDefinitions": [
{
"AttributeName": "Path",
"AttributeType": "S"
},
{
"AttributeName": "Date",
"AttributeType": "S"
}
],
"ProvisionedThroughput": {
"ReadCapacityUnits": 2,
"WriteCapacityUnits": 2
}
}


  • プロジェクトのルートフォルダーに戻り、テーブルの作成コマンドを実行します。

(venv) sam-lambda-dynamodb\sam-app> cd ..

(venv) sam-lambda-dynamodb> aws dynamodb create-table --cli-input-json file://.\DynamoDB\AccessTable.json --endpoint-url http://localhost:8000
(venv) sam-lambda-dynamodb> aws dynamodb list-tables --endpoint-url http://localhost:8000
{
"TableNames": [
"Access"
]
}

これでテーブルの作成ができました。


「hello_world」のapiを編集

まず、ローカルと本番の接続処理は違うので、ローカルだとわかるようにtemplate.yamlに環境のパラメーターを追加します。

実際にデプロイをする時パラメーターを上書きできます。


template.yaml

... 略

+Parameters:
+ Env:
+ Type: String
+ Default: local

Globals:
Function:
Timeout: 3
+ Environment:
+ Variables:
+ ENV: !Ref Env

... 略


「hello_world」のフォルダーの中にあるrequirements.txtboto3のライブラリーを追加します。


requirements.txt

requests

boto3

「hello_world」のフォルダーの中にあるapp.pyを編集します。

returnの前に以下のコードを追加します。


app.py

import json

import boto3
import os
import logging
from datetime import datetime

# ... 略

try:
logger = logging.getLogger()
logger.setLevel(logging.INFO)

session = boto3.session.Session()
awsRegion = session.region_name
paramList = event['queryStringParameters']

client = boto3.client('dynamodb')
# ローカルの場合
if os.environ['ENV'] == 'local':
dynamodb = boto3.resource('dynamodb', region_name = awsRegion, endpoint_url = "http://dynamodb:8000")
# ローカル以外の環境の場合
else:
dynamodb = boto3.resource('dynamodb', region_name = awsRegion)
# テーブルを取得
table = dynamodb.Table('Access')
# 日時の文字列
date = datetime.utcnow().isoformat()
# 登録するアイテムのベース
item = {'Path': event['path'], 'Date': date}

if paramList != None:
for key,value in paramList.items():
item[key] = value

table.put_item(
Item=item
)

except Exception as e:
# Lambdaログにエクセプションの情報を入れる
logger.exception(e)
return {
'statusCode': 500,
'body': json.dumps({
'error_message': str(e)
}),
}

# ... 略



APIを試す

もう一度「sam-app」に入り、ビルドを実行します。

(venv) sam-lambda-dynamodb> cd .\sam-app\

(venv) sam-lambda-dynamodb\sam-app> sam build

APIをlambda-localのネットワークで開始します。

(venv) sam-lambda-dynamodb\sam-app> sam local start-api --docker-network lambda-local

ブラウザーでGatewayにアクセスします。(http://localhost:3000/hello?param=test)

成功できたら、以下のコマンドでテーブルのアイテムが見れます。

(venv) sam-lambda-dynamodb> aws dynamodb scan --table-name Access --endpoint-url http://localhost:8000

{
"Items": [
{
"Path": {
"S": "/hello"
},
"param": {
"S": "test"
},
"Date": {
"S": "2019-02-11T03:48:44.017178"
}
}
],
"Count": 1,
"ScannedCount": 1,
"ConsumedCapacity": null
}

これでDynamoDBとLambdaをローカルで使えるようになりました。


その他の情報