lambrollでLambda関数をデプロイする
はじめに
最近、fujiwaraさん作のlambrollというAWS Lambda専用のGo製デプロイツールを使ってみたので備忘も兼ねて記事にまとめたいと思います(認識の間違い等あればツッコミいただければと)
lambroll is a minimal deployment tool for AWS Lambda.
これが非常に便利で、Lambdaの作成、削除、デプロイ等が非常に簡単にできます。上がったLambda関数をローカルから簡単に呼び出すこともできるため開発も非常にしやすく、git管理も可能です。素晴らしいことにCircleCIのOrbも用意されているのでCircleCIで簡単にlambrollを使うことができます。では、早速最低限の使い方を説明していきます(今回は「見て理解する」スタイルで文字少なめで説明していきます)
レポジトリ
CircleCI Orb
CircleCI | Orb | fujiwara/lambroll@0.0.8
使い方
準備
環境変数
# ~/.zshrc
export AWS_ACCOUNT_ID=*************
export AWS_ACCESS_KEY_ID=*************
export AWS_SECRET_ACCESS_KEY=*************
インストール
# macOS and Linux
$ brew install fujiwara/tap/lambroll
help
$ lambroll
usage: lambroll [<flags>] <command> [<args> ...]
Flags:
--help Show context-sensitive help (also try --help-long and --help-man).
--log-level=info log level (trace, debug, info, warn, error)
--function="function.json" Function file path
--profile="" AWS credential profile name
--region="" AWS region
--tfstate="" URL to terraform.tfstate
--endpoint="" AWS API Lambda Endpoint
--envfile=ENVFILE ... environment files
Commands:
help [<command>...]
Show help.
version
show version
init --function-name=FUNCTION-NAME [<flags>]
init function.json
list
list functions
deploy [<flags>]
deploy or create function
rollback [<flags>]
rollback function
delete [<flags>]
delete function
invoke [<flags>]
invoke function
archive [<flags>]
archive zip
logs [<flags>]
tail logs using `aws logs tail` (aws-cli v2 required)
diff
show display diff of function.json compared with latest function
initをhelpしたい場合
$ lambroll init --help
usage: lambroll init --function-name=FUNCTION-NAME [<flags>]
init function.json
Flags:
--help Show context-sensitive help (also try --help-long and --help-man).
--log-level=info log level (trace, debug, info, warn, error)
--function="function.json" Function file path
--profile="" AWS credential profile name
--region="" AWS region
--tfstate="" URL to terraform.tfstate
--endpoint="" AWS API Lambda Endpoint
--envfile=ENVFILE ... environment files
--function-name=FUNCTION-NAME Function name for initialize
--download Download function.zip
【Lambda関数未作成の場合】 空のlambda設定ファイルを作成
testFunctionという名前でLambda関数作成。
$ lambroll init --function-name=testFunction
2021/10/27 07:48:12 [info] lambroll v0.11.9
2021/10/27 07:48:13 [info] function testFunction is not found
2021/10/27 07:48:13 [info] creating .lambdaignore
2021/10/27 07:48:13 [info] creating function.json
2021/10/27 07:48:13 [info] completed
$ ls
function.json # 作成されたもの
$ cat function.json
{
"FunctionName": "testFunction",
"Handler": "index.handler",
"MemorySize": 128,
"Role": "arn:aws:iam::XXXXXXXXXX:role/YOUR_LAMBDA_ROLE_NAME",
"Runtime": "nodejs10.x",
"Timeout": 3
}
【既にLambdaを作成している場合】 既存の設定を取得
色々ステップを省くために今回はこちらの方法でやっていきます。
(「関数の作成」画面で以下のようにLambda関数をコンソール上から作成しておいてください)
Lambda関数の設定を取得します。
# --function-nameはコンソール上で作成した関数名に合わせてください
$ lambroll init --function-name=testFunction
2021/10/27 08:13:20 [info] lambroll v0.11.9
2021/10/27 08:13:21 [info] function testFunction found
2021/10/27 08:13:21 [info] creating .lambdaignore
2021/10/27 08:13:21 [info] creating function.json
2021/10/27 08:13:21 [info] completed
$ ls
function.json
$ cat function.json
{
"Architectures": [
"x86_64"
],
"Description": "",
"FunctionName": "testFunction",
"Handler": "lambda_function.lambda_handler",
"MemorySize": 128,
"Role": "arn:aws:iam::XXXXXXXXXX:role/service-role/testFunction-role-2joa85l4",
"Runtime": "python3.8",
"Tags": {},
"Timeout": 3,
"TracingConfig": {
"Mode": "PassThrough"
}
}
補足:既存のソースコードも取得したい場合は--download
オプションも付けてください。
デプロイするプログラムを用意
-
HelloWorld
を出力して、レスポンスとしてHello Response
を返すだけのプログラムを用意
$ cat hello_world.py
import json
def lambda_handler(event, context):
print("Hello World")
return {
'statusCode': 200,
'body': json.dumps("Hello Response")
}
# ローカル確認用
if __name__ == '__main__':
lambda_handler(None, None)
$ python3 hello_world.py
Hello World
Lambdaから実行する関数を指定するためにHandler修正
$ vim function.json
{
"Architectures": [
"x86_64"
],
"Description": "",
"FunctionName": "testFunction",
- "Handler": "lambda_function.lambda_function",
+ "Handler": "hello_world.lambda_handler", # <file_path>.<function_name>
"MemorySize": 128,
"Role": "arn:aws:iam::XXXXXXXXXXX:role/service-role/testFunction-role-2joa85l4",
"Runtime": "python3.8",
"Tags": {},
"Timeout": 3,
"TracingConfig": {
"Mode": "PassThrough"
}
}
補足:appディレクトリ配下にhello_world.py
を置いていた場合は以下のようになる。
{
...
- "Handler": "hello_world.lambda_handler"
+ "Handler": "app/hello_world.lambda_handler"
...
}
Lambda関数をデプロイ
デプロイ先を特定するためにLambdaの設定ファイルであるfunction.json
を指定し、src
でデプロイしたいソースを指定することでそのディレクトリを自動的にzipしてデプロイする。
$ lambroll deploy --function=function.json --src="."
2021/10/27 08:26:45 [info] lambroll v0.11.9
2021/10/27 08:26:45 [info] starting deploy function testFunction
2021/10/27 08:26:45 [info] creating zip archive from .
2021/10/27 08:26:45 [info] zip archive wrote 366 bytes
2021/10/27 08:26:45 [info] updating function configuration
2021/10/27 08:26:46 [info] updating function code
2021/10/27 08:26:46 [info] deployed version 18
2021/10/27 08:26:46 [info] updating alias set current to version 18
2021/10/27 08:26:46 [info] alias current is not found. creating alias
2021/10/27 08:26:46 [info] alias updated
2021/10/27 08:26:46 [info] completed
補足:--function
と--src
のデフォルト値はそれぞれfunction.json
と.
となっているため、実は設定する必要はないので以下のようなやり方でも問題はない。
$ lambroll deploy
反映されたか確認
コンソールを確認すると反映されていることが分かります。
Lambda実行し動作確認
Testボタンを押すと結果が画面に出力されます。
Hello Response
とHello World
が出力されているか確認。
Test Event Name
test
Response
{
"statusCode": 200,
"body": "\"Hello Response\"" <-------
}
Function Logs
START RequestId: fbbb422e-9197-4f98-9058-b77375d35b45 Version: $LATEST
Hello World <-------
END RequestId: fbbb422e-9197-4f98-9058-b77375d35b45
REPORT RequestId: fbbb422e-9197-4f98-9058-b77375d35b45 Duration: 1.69 ms Billed Duration: 2 ms Memory Size: 128 MB Max Memory Used: 38 MB Init Duration: 178.60 ms
Request ID
fbbb422e-9197-4f98-9058-b77375d35b45
ローカルからLambda関数を呼び出す
実際にLambda関数を実行してテストしたい時に便利です。
# --function=function.jsonはデフォルトなので抜いてます
echo '{"event":"test"}' | lambroll invoke
2021/10/27 09:42:33 [info] lambroll v0.11.9
{"statusCode": 200, "body": "\"Hello Response\""} <-------
2021/10/27 09:42:33 [info] StatusCode:200
2021/10/27 09:42:33 [info] ExecutionVersion:$LATEST
2021/10/27 09:42:33 [info] completed
レスポンスだけでなく、print
で標準出力させたログ(Hello World
)も確認したい場合は--log-tail
を付けてください。
$ echo '{"event":"test"}' | lambroll invoke --log-tail
2021/10/27 09:50:25 [info] lambroll v0.11.9
{"statusCode": 200, "body": "\"Hello Response\""}
2021/10/27 09:50:25 [info] StatusCode:200
2021/10/27 09:50:25 [info] ExecutionVersion:$LATEST
START RequestId: 57c914e9-56b9-43da-9a89-9a19a9b55a93 Version: $LATEST
Hello World <------------
END RequestId: 57c914e9-56b9-43da-9a89-9a19a9b55a93
REPORT RequestId: 57c914e9-56b9-43da-9a89-9a19a9b55a93 Duration: 0.85 ms Billed Duration: 1 ms Memory Size: 128 MB Max Memory Used: 39 MB
2021/10/27 09:50:25 [info] completed
存在しない関数名を指定してデプロイしたらどうなる
FunctionName
をnewTestFunction
に変更してみる。
{
"Architectures": [
"x86_64"
],
"Description": "",
- "FunctionName": "testFunction",
+ "FunctionName": "newTestFunction",
"Handler": "hello_world.lambda_handler",
"MemorySize": 128,
"Role": "arn:aws:iam::XXXXXXXXXX:role/service-role/testFunction-role-2joa85l4",
"Runtime": "python3.8",
"Tags": {},
"Timeout": 3,
"TracingConfig": {
"Mode": "PassThrough"
}
}
デプロイ
$ lambroll deploy
2021/10/27 21:19:57 [info] lambroll v0.11.9
2021/10/27 21:19:57 [info] starting deploy function testFunction
2021/10/27 21:19:57 [info] creating zip archive from .
2021/10/27 21:19:57 [info] zip archive wrote 366 bytes
2021/10/27 21:19:57 [info] updating function configuration
2021/10/27 21:19:58 [info] updating function code
2021/10/27 21:19:58 [info] deployed version 21
2021/10/27 21:19:58 [info] updating alias set current to version 21
2021/10/27 21:19:58 [info] alias updated
2021/10/27 21:19:58 [info] completed
関数を一覧表示
$ lambroll list
2021/10/27 21:20:55 [info] lambroll v0.11.9
{
"Architectures": [
"x86_64"
],
"Description": "",
"FunctionName": "newTestFunction",
"Handler": "hello_world.lambda_handler",
"MemorySize": 128,
"Role": "arn:aws:iam::XXXXXXXXXX:role/service-role/testFunction-role-2joa85l4",
"Runtime": "python3.8",
"Tags": {},
"Timeout": 3,
"TracingConfig": {
"Mode": "PassThrough"
}
}
{
"Architectures": [
"x86_64"
],
"Description": "",
"FunctionName": "testFunction",
"Handler": "hello_world.lambda_handler",
"MemorySize": 128,
"Role": "arn:aws:iam::XXXXXXXXXX:role/service-role/testFunction-role-2joa85l4",
"Runtime": "python3.8",
"Tags": {},
"Timeout": 3,
"TracingConfig": {
"Mode": "PassThrough"
}
}
newTestFunction
とtestFunction
の二つの関数が存在していることが確認できるかと思います。つまり、存在しない関数名をFunctionName
に設定してデプロイをすると新しく関数が作成されます。
作成したLambda関数を削除
作成したnewTestFunction
はもう必要がないので削除します。function.json
のFunctionName
に紐づいているので、関数名がnewTestFunction
になっていることを確認し、deleteを実行します。
$ lambroll delete
2021/10/27 21:26:13 [info] lambroll v0.11.9
2021/10/27 21:26:13 [info] deleting function newTestFunction
2021/10/27 21:26:13 [info] completed
newTestFunction
が存在しないことを確認。
$ lambroll list
2021/10/27 21:27:50 [info] lambroll v0.11.9
{
"Architectures": [
"x86_64"
],
"Description": "",
"FunctionName": "testFunction",
"Handler": "hello_world.lambda_handler",
"MemorySize": 128,
"Role": "arn:aws:iam::XXXXXXXXXX:role/service-role/testFunction-role-2joa85l4",
"Runtime": "python3.8",
"Tags": {},
"Timeout": 3,
"TracingConfig": {
"Mode": "PassThrough"
}
}
【Terraform】 Lambdaにデプロイするサイズが大きい場合の対処
AWS Lambdaの仕様上、ソースコードを圧縮して50MB以上あるとLambdaへ直接デプロイする時にエラーになるため、サイズが50MB以上となってしまった時の対策としてS3を使用してデプロイさせるようにします。
以下のようなTerraformのコードを用意
$ vim main.tf
provider "aws" {
version = "~> 3.0"
profile = "default"
region = "ap-northeast-1"
}
resource "aws_s3_bucket" "lambda_source" {
bucket = "lambda-source-xxxxxxx"
acl = "private"
}
terraform apply
実行してS3を作成。
$ terraform init
$ terraform apply
これでaws_s3_bucket.lambda_source
というリソースが使用可能になったので、function.json
にこれを組み込んでいきます。
function.json
に以下の行を追加。
# S3Bucket以外もtfstateから参照させておくべきではありますが、
# 今回はシンプルさを保つためS3Bucketのみにとどめています。
{
"Architectures": [
"x86_64"
],
"Description": "",
"FunctionName": "newTestFunction",
"Handler": "hello_world.lambda_handler",
"MemorySize": 128,
"Role": "arn:aws:iam::XXXXXXXXX:role/service-role/testFunction-role-2joa85l4",
"Runtime": "python3.8",
"Tags": {},
"Timeout": 3,
"TracingConfig": {
"Mode": "PassThrough"
},
+ "Code": {
+ "S3Bucket": "{{ tfstate `aws_s3_bucket.lambda_source.id` }}",
+ "S3Key": "lambda_source.zip"
+ }
}
S3経由でLambdaデプロイします。--tfstate
オプションでtfstateファイルを指定してください。
補足:Terraformを使わず直接ハードコードすることもできますが、環境毎にデプロイ先のバケットを分けることができなくなるためオススメはしません。
$ lambroll deploy --tfstate=terraform.tfstate
2021/10/27 23:31:10 [info] lambroll v0.11.9
2021/10/27 23:31:10 [info] starting deploy function newTestFunction
2021/10/27 23:31:11 [info] creating zip archive from .
2021/10/27 23:31:11 [info] zip archive wrote 911 bytes
2021/10/27 23:31:11 [info] uploading function 911 bytes to s3://lambda-source-xxxxxxx/lambda_source.zip
2021/10/27 23:31:11 [info] object created
2021/10/27 23:31:11 [info] creating function
2021/10/27 23:31:11 [info] deployed function version 2
2021/10/27 23:31:12 [info] creating alias set current to version 2
2021/10/27 23:31:12 [info] alias created
2021/10/27 23:31:12 [info] completed
このようにすれば50MB以上のzipファイルもデプロイすることができます。
ちゃんとS3にアップロードされていますね。
CircleCIからlambrollを使用する
lambrollのCircleCI Orbが用意されているのでこれを使えば簡単にCircleCI上からlambrollが使えるようになります。
version: 2.1
orbs:
lambroll: fujiwara/lambroll@0.0.8
jobs:
deloy:
docker:
- image: cimg/base
steps:
- checkout
- lambroll/install:
version: v0.10.0
- run:
command: |
lambroll deploy
参考: GitHub | fujiwara/lambroll
CircleCI Orb関連でエラーが出た場合
Third Party Orbを使用する場合、CircleCIでデプロイしようとすると以下のようなエラーが表示されます。
Orb fujiwara/lambroll@0.0.8 not loaded. To use this orb, an organization admin must opt-in to using third party orbs in Organization Security settings.
このように設定してからRerunをすれば通るようになります。
最後に
lambrollを一通り説明しましたが、これでもまだ必要最低限の機能しか説明していないため、もし細かい機能を知りたい場合はfujiwaraさんのGitHubレポジトリ「fujiwara/lambroll」に分かりやすく説明が書かれているため、こちらを参考にすると良いかと思います。それにしても、よくこれを開発したなと思うと同時に「やっぱりGoはやっておきたいな」と、lambrollのソースコードを読みながらつくづく思いました。今度時間が空いた時にでもやれたら良いですね。
それでは、lambrollの話でした。
皆も時間があれば使ってみると便利さに気づくかもしれません。
Discussion