LocalStackでLambdaファンクションをローカルで動かす

MMMバックエンドエンジニアの柳沼です。
文鳥が換羽期なので部屋中に羽が舞ってます。

今回はAtlassianが開発しているLocalStackを使って、Lambdaファンクションをローカルに閉じて動かしてみます。

LocalStackチュートリアル

まずは、LocalStackを使ってみます。
pipでインストールすることもできるのですが、
dockerイメージが公開されているため、そちらを使っていきます。
今回は公式のdocker-compose.ymlを使って、以下のように実行しました。

1
2
$ wget https://raw.githubusercontent.com/localstack/localstack/master/docker-compose.yml
$ docker-compose up -d

しばらくするとこのように、LocalStackのコンテナが上がってきます。

1
2
3
$ docker ps  
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ca98225f6bba localstack/localstack "/usr/bin/supervisor…" 13 minutes ago Up 13 minutes 0.0.0.0:4567-4583->4567-4583/tcp, 0.0.0.0:8080->8080/tcp sam_localstack_1

ポートが空くのを確認しましょう。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$ netstat -an
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp6 0 0 :::8080 :::* LISTEN
tcp6 0 0 :::4567 :::* LISTEN
tcp6 0 0 :::4568 :::* LISTEN
tcp6 0 0 :::4569 :::* LISTEN
tcp6 0 0 :::4570 :::* LISTEN
tcp6 0 0 :::4571 :::* LISTEN
tcp6 0 0 :::4572 :::* LISTEN
tcp6 0 0 :::4573 :::* LISTEN
tcp6 0 0 :::4574 :::* LISTEN
tcp6 0 0 :::4575 :::* LISTEN
tcp6 0 0 :::4576 :::* LISTEN
tcp6 0 0 :::4577 :::* LISTEN
tcp6 0 0 :::4578 :::* LISTEN
tcp6 0 0 :::4579 :::* LISTEN
tcp6 0 0 :::4580 :::* LISTEN
tcp6 0 0 :::4581 :::* LISTEN
tcp6 0 0 :::4582 :::* LISTEN
tcp6 0 0 :::4583 :::* LISTEN

(以下略)

8080番及び4567~4583が空くと思います。
この状態で localhost:8080 にアクセスしてみましょう。

このようにコンソールにアクセスできます。

8080番以外のポートはなにかというと、AWSの各サービスを示しています。
READMEに説明があります。

例えば、S3を利用してみましょう。
READMEによればS3のポートは4572なので、以下のようにバケットとオブジェクトを作ってみます。

1
2
3
$ aws --endpoint-url=http://localhost:4572 s3api create-bucket --bucket sam_test
$ echo "Hello world" > s3.txt
$ aws --endpoint-url=http://localhost:4572 s3 cp ./s3.txt s3://sam_test

これで先程のコンソールをリロードしてみると、バケットができています!!

これだけでも、ローカルでS3バケットをモックできるため、開発中に実際のS3バケットを見に行く必要がなくなります。便利。

今回は、LocalStack上のLambdaのエンドポイントに関数を作成し、実行します。

Lambdaファンクション作成

それでは、Lambdaファンクションを作ります。
aws clilambda create-function すればいいのですが、普通に作っただけではLocalStackのエンドポイントに作れないので、以下のような作り方をします。
まずはスクリプトを作成。

1
2
3
4
5
$ vi lambda.py

def lambda_handler(event, context):
print(event)
return 'LocalStack TEST'

zip化します。

1
$ zip lambda.zip lambda.py

そして、create-functionします。

1
$ aws --endpoint-url=http://localhost:4574 --region us-east-1 --profile localstack lambda create-function --function-name=f1 --runtime=python2.7 --role=r1 --handler=lambda.lambda_handler --zip-file fileb://lambda.zip

最大のポイントは --endpoint-url=http://localhost:4574 です。これでLocalStackに作ってくれます。
うまくできれば、以下のように返ってきます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"TracingConfig": {},
"FunctionName": "f1",
"VpcConfig": {
"SubnetIds": [
null
],
"SecurityGroupIds": [
null
]
},
"FunctionArn": "arn:aws:lambda:us-east-1:000000000000:function:f1",
"Environment": {
"Variables": {},
"Error": {}
},
"Handler": "lambda.lambda_handler",
"Role": "r1",
"Runtime": "python2.7"
}

コンソールをリロードすれば、ファンクションができていると思います。

ちなみに、右の Show code からコードを見ることもできます。便利。

実行は以下のようにします。

1
2
3
4
$ aws lambda --endpoint-url=http://localhost:4574 invoke --function-name f1 --payload '{"key1":"value1"}' result.log
{
"StatusCode": 200
}

200が返ると思います。
ログを見てみます。

1
2
$ cat result.log
LocalStack TEST

バッチリですね!!

まとめ

Lambdaファンクション作成 → 実行をローカルで完結させることができ、テストコードも書きやすくなるかと思います。インターネットに出る必要もなく、AWSリソースとしてのコストも考慮しなくていいので、開発時には非常に有用かと思います。
今回は書いていませんが、aws-sam-localと組み合わせることでより実際の環境に近づけることも可能です。
サーバーレスシステム開発のお問い合わせはこちらからお待ちしています。

このエントリーをはてなブックマークに追加