AWS Day3: Lambda × Go
こんにちは。
AWS入門第三弾です。今回は投稿が遅くならないように着実に進めていく所存です・・・
今回の内容は以下です。
AWS Lambda の基本
そもそも Lambda って何ぞや、という話からさっとまとめていきます。
AWS Lambda とは
- サーバ管理なくコードを実行できる
- コードを準備すれば、高可用性・スケーリングなどはLambdaが担ってくれる
- 課金が時間・呼び出し回数単位
- AWSの他サービスをトリガにするようにも、他アプリ・Webなどから呼び出すようにもできる
いわゆるサーバレス!ワクワクしますね。
Lambdaが動くまで
- コードを書きアップロード or コードエディタを使って書く
- コードの呼び出し元を設定
- 呼び出された時に必要なだけのリソースを確保し実行
ほぅ・・・便利そうですが 3. の動きが気になります。その「呼び出し」に遅延は感じないのだろうか。今回はそこまでのコードを実行しないので確かめようがないけれど。
ユースケース
公式サイト(https://aws.amazon.com/jp/lambda/)に載ってます。
主にデータの加工・抽出などを行う処理やバックエンド処理をサーバレスで実行するものなどが挙げられています。
AWS CLI で Lambda 関数を作成
以下の手順を進めていきます。参考:https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/gettingstarted-awscli.html
まずはチュートリアル通りに、コーディング部分はサンプルを使って流れを理解していきます。
- 実行ロールの作成
- 関数を作成
- 関数によって出力されたものを確認
- 作成した関数のリストを取得
- Lambda関数を取得
AWS CLI が使用できるターミナルがあることとして進めていきます。
1. 実行ロールの作成
実行ロール
AWSのリソースにアクセスするためのアクセス権。これを関数に付与します。
①trust-policy.json を作成
ロールの作成には、信頼ポリシー
を定義するJSONファイルが必要になります。
※インラインで信頼ポリシーを指定することも可能ですが、ここでは「何を指定するか」を理解するためにファイルにします
・trust-policy.json
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }
- lamnda.amazonaws.com へのアクセス許可
- サービスプリンシパルに AssumeRole アクションを呼び出させるため
②実行ロールを作成
以下のコマンドで①のポリシーファイルを読み込み、実行ロールを作成します。
❯ aws iam create-role --role-name lambda-ex --assume-role-policy-document file://trust-policy.json { "Role": { "Path": "/", "RoleName": "lambda-ex", "RoleId": "AROAYHSN4WF**********", "Arn": "arn:aws:iam::566025302349:role/lambda-ex", "CreateDate": "2020-06-13T09:47:43+00:00", "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } } }
実行ロールが作成できました。
③アクセス許可を上記のロールに追加
②で作成したロールに対して、アクセス許可設定を行います。
❯ aws iam attach-role-policy --role-name lambda-ex --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
attach-policy-to-role
コマンドで、ロールにアクセス許可を設定AWSLambdaBasicExecutionRole
を追加してる
ここまでで、Lambda関数がAWSリソースにアクセスする用ロールを作成しました。
2. 関数を作成
①関数を作成
Lambdaの主役となる関数を作成します。今回はサンプルコードで一旦進めます。
・index.js
exports.handler = async function(event, context) { console.log("ENVIRONMENT VARIABLES\n" + JSON.stringify(process.env, null, 2)) console.log("EVENT\n" + JSON.stringify(event, null, 2)) return context.logStreamName }
②デプロイパッケージを作成
zipに固めます。
❯ zip function.zip index.js
③Lambda関数を作成
以下のコマンドで、arn:aws:iam:: hogehoge 部分を先に出力された アカウントID に置き換えます。
❯ aws lambda create-function --function-name my-function \ --zip-file fileb://function.zip --handler index.handler --runtime nodejs12.x \ --role arn:aws:iam::123456789012:role/lambda-ex You must specify a region. You can also configure your region by running "aws configure".
create-function
でLambda関数を作成
・・・うげ。リージョン指定しろって怒られた。すみません。
❯ aws configure AWS Access Key ID [****************]: AWS Secret Access Key [****************]: Default region name [None]: ap-northeast-1 Default output format [None]: json
もう一度実行したら、以下の結果が返ってきました。
{ "FunctionName": "my-function", "FunctionArn": "arn:aws:lambda:ap-northeast-1:123456789012:function:my-function", "Runtime": "nodejs12.x", "Role": "arn:aws:iam::123456789012:role/lambda-ex", "Handler": "index.handler", "CodeSize": 322, "Description": "", "Timeout": 3, "MemorySize": 128, "LastModified": "2020-06-13T10:17:17.924+0000", "CodeSha256": "M0TsZslRTH6XjlyiputXgVNun2KTcWrno9TeqPZsOhI=", "Version": "$LATEST", "TracingConfig": { "Mode": "PassThrough" }, "RevisionId": "6a213101-7e86-4639-baf7-519a6ece909a", "State": "Active", "LastUpdateStatus": "Successful" }
④ 関数を呼び出し、そのログを取得
❯ aws lambda invoke --function-name my-function out --log-type Tail { "StatusCode": 200, "LogResult": "U1RBUlQgUmVxdWVzdElkOiBkZTc3YzI0OS04ZTdkLTRkNTA...", "ExecutedVersion": "$LATEST" }
lambda invoke
で関数を呼び出す--log-type
オプションでログを取得する- Base64 なので意味は不明
ログをデコードしてみます。
❯ aws lambda invoke --function-name my-function out --log-type Tail \ --query 'LogResult' --output text | base64 -d START RequestId: a1b23675-cec8-4123-841c-275a3552526f Version: $LATEST 2020-06-13T10:27:47.541Z a1b23675-cec8-4123-841c-275a3552526f INFO ENVIRONMENT VARIABLES { "AWS_LAMBDA_FUNCTION_VERSION": "$LATEST", "AWS_SESSION_TOKEN": "IQoJb3J...", : "AWS_LAMBDA_FUNCTION_NAME": "my-function", "PATH": "/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin", "AWS_DEFAULT_REGION": "ap-northeast-1", "AWS_REGION": "ap-northeast-1", "_X_AMZN_TRACE_ID": "Root=1-5ee4aa23-bef1b3c06a9649a0dc2dd280;Parent=2360ae02038b73cc;Sampled=0" } 2020-06-13T10:27:47.541Z a1b23675-cec8-4123-841c-275a3552526f INFO EVENT {} END RequestId: a1b23675-cec8-4123-841c-275a3552526f REPORT RequestId: a1b23675-cec8-4123-841c-275a3552526f Duration: 49.00 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 65 MB
base64
ユーティリティでデコード- 関数の出力にログストリーム名を設定できる
いろいろ見れました。
3. 作成したLambda関数をリストアップ
❯ aws lambda list-functions --max-items 10 { "Functions": [ { "FunctionName": "my-function", "FunctionArn": "arn:aws:lambda:ap-northeast-1:123456789012:function:my-function", "Runtime": "nodejs12.x", "Role": "arn:aws:iam::123456789012:role/lambda-ex", "Handler": "index.handler", "CodeSize": 322, "Description": "", "Timeout": 3, "MemorySize": 128, "LastModified": "2020-06-13T10:17:17.924+0000", "CodeSha256": "M0TsZslRTH6XjlyiputXgVNun2KTcWrno9TeqPZsOhI=", "Version": "$LATEST", "TracingConfig": { "Mode": "PassThrough" }, "RevisionId": "6a213101-7e86-4639-baf7-519a6ece909a" } ] }
list-functions
コマンドでリスト--max-items
で表示件数を指定
当たり前ですが、先ほど登録した関数の情報が表示されました。
4. Lambda関数を取得
❯ aws lambda get-function --function-name my-function { "Configuration": { "FunctionName": "my-function", "FunctionArn": "arn:aws:lambda:ap-northeast-1:123456789012:function:my-function", "Runtime": "nodejs12.x", "Role": "arn:aws:iam::123456789012:role/lambda-ex", "Handler": "index.handler", "CodeSize": 322, "Description": "", "Timeout": 3, "MemorySize": 128, "LastModified": "2020-06-13T10:17:17.924+0000", "CodeSha256": "M0TsZslRTH6XjlyiputXgVNun2KTcWrno9TeqPZsOhI=", "Version": "$LATEST", "TracingConfig": { "Mode": "PassThrough" }, "RevisionId": "6a213101-7e86-4639-baf7-519a6ece909a", "State": "Active", "LastUpdateStatus": "Successful" }, "Code": { "RepositoryType": "S3", "Location": "https://awslambda-ap-ne-1-tasks.s3.ap-northeast-1.amazonaws.com/snapshots/566025302349/my-function-a6bee001-..." } }
get-function
コマンドでLambda関数メタデータ・署名付きURLを取得(有効期間10分)- 関数のデプロイパッケージをDLする時に使用する情報
5. 関数を削除
❯ aws lambda delete-function --function-name my-function
delete-function
コマンドでLambda関数を削除
いとも簡単に消え去りました。
Go でやってみる
はい、恒例の Go タイムです(ここまででちょっと疲れてる・・・)元気出してくぞ!
基本的には上記の手順と変わらないですが、以下の観点が追加で必要になります。
- Lambda関数デプロイパッケージとの依存関係が成立しているGo実行ファイル(.zip)
①Go のプログラムを作成
今回はGo自体のプログラムの内容というよりかは、LambdaでGo実行するには何が必要か?だけを確かめていきます。
・main.go
package main import ( "fmt" "context" "github.com/aws/aws-lambda-go/lambda" ) type MyEvent struct { Name string `json:"name"` } // Lambdaハンドラ署名と実際に実行されるコード func HandleRequest(ctx context.Context, name MyEvent) (string, error) { return fmt.Sprintf("Hello %s!", name.Name ), nil } // 実処理のエントリポイント func main() { lambda.Start(HandleRequest) }
github.com/aws/aws-lambda-go/lambda
ライブラリをインポート
参考:https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/golang-handler.html
②GoのLambdaライブラリを取得し、コンパイル
❯ go get github.com/aws/aws-lambda-go/lambda
go get
でGoのライブラリをDL
GOOS=linux go build main.go
GOOS
をLinuxに設定することで、non-Linux環境下でのコンパイルでも Goランタイムとの互換性を確保できる https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-runtimes.html
③パッケージ化
zip function.zip main
④Lambda関数を作成
❯ aws lambda create-function --function-name my-function \ --zip-file fileb://function.zip --handler main --runtime go1.x \ --role arn:aws:iam::123456789012:role/lambda-ex { "FunctionName": "my-function", "FunctionArn": "arn:aws:lambda:ap-northeast-1:123456789012:function:my-function", "Runtime": "go1.x", "Role": "arn:aws:iam::566025302349:role/lambda-ex", "Handler": "main", "CodeSize": 10196815, "Description": "", "Timeout": 3, "MemorySize": 128, "LastModified": "2020-06-13T11:47:17.915+0000", "CodeSha256": "lDb5drLqJYm6y8/NKPOA2nBPowOgOln9Pt0cF87eiyY=", "Version": "$LATEST", "TracingConfig": { "Mode": "PassThrough" }, "RevisionId": "f76012d3-2ff2-4f30-9b94-650dd39cfa7b", "State": "Active", "LastUpdateStatus": "Successful" }
- ハンドラのパラメータ(ここでいうと main)は、ハンドラを含む実行可能ファイル名と一致する
- --role は適宜書き換える
⑤Hello ○○ してみる
# JSON形式のInputをbase64でエンコードしておく ❯ echo '{"name":"don"}' | base64 eyJuYW1lIjoiZG9uIn0K ❯ aws lambda invoke --function-name my-function out --payload eyJuYW1lIjoiZG9uIn0K { "StatusCode": 200, "ExecutedVersion": "$LATEST" } ❯ cat out "Hello don!"
無事Hello donできました(自分に挨拶)。
終わりに
コードさえ用意できれば、気軽にサーバレスな処理を追加していけるLambdaの良さを味わうことができました。
今回は手動で関数を呼び出しましたが、次回以降はAWSの他リソースの処理をトリガにして呼び出すようなものに挑戦しようと思います。