Lambda で Go のめっちゃ基礎 の続きです。
S3 イベントでファイル取得して、別 S3 に出力してみます。
GitHub
この README のサンプルを参考に実装。
開発環境
$ sw_vers ProductName: Mac OS X ProductVersion: 10.15.7 BuildVersion: 19H1419 $ go version go version go1.17 darwin/amd64
Lambda にトリガーを追加
Lambda 関数の「関数の概要」で S3 イベント駆動で動かすためにトリガーを追加。
トリガー元のバケットを指定して保存。
トリガー元バケットに Lambda からの参照を許可
トリガー元のバケットの「アクセス許可」から
バケットポリシーを設定。
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::AWSアカウントID:role/service-role/Lambdaの実行ロール" }, "Action": [ "s3:GetObject", "s3:GetObjectAcl" ], "Resource": "arn:aws:s3:::インプットバケット名/*" } ] }
Lambda の実行ロールは、Lambda 関数の「設定」から参照できるので、この ARN を設定する。
出力先バケットに Lambda からの保存を許可
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam::AWSアカウントID:role/service-role/Lambdaの実行ロール" }, "Action": [ "s3:PutObject", "s3:PutObjectAcl" ], "Resource": "arn:aws:s3:::アウトプットバケット名/*" } ] }
これで、AWS 側の準備は整いました。
Lambda の実装
エラー処理などは考えずに、取りあえず動くだけの実装。
// main.go package main import ( "bytes" "context" "io/ioutil" "log" "github.com/aws/aws-lambda-go/events" "github.com/aws/aws-lambda-go/lambda" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/s3" ) // 出力バケット const S3Output = "出力バケット名" // https://github.com/aws/aws-lambda-go/blob/main/events/README_S3.md を参考 func handler(ctx context.Context, s3Event events.S3Event) { // セッション獲得 sess := session.Must(session.NewSession()) // S3 clientを作成 svc := s3.New(sess) for _, record := range s3Event.Records { s3rec := record.S3 log.Printf("[%s - %s] Bucket = %s, Key = %s \n", record.EventSource, record.EventTime, s3rec.Bucket.Name, s3rec.Object.Key) // オブジェクト取得 obj, err := svc.GetObject(&s3.GetObjectInput{ Bucket: aws.String(s3rec.Bucket.Name), Key: aws.String(s3rec.Object.Key), }) if err != nil { log.Fatal(err) } // オブジェクト読み込み rc := obj.Body defer rc.Close() content, err := ioutil.ReadAll(rc) if err != nil { log.Fatal(err) } // オブジェクト書き込み _, err = svc.PutObject(&s3.PutObjectInput{ Body: bytes.NewReader(content), Bucket: aws.String(S3Output), // バケットは適宜変更 Key: aws.String(s3rec.Object.Key), }) if err != nil { log.Fatal(err) } } } func main() { // Make the handler available for Remote Procedure Call by AWS Lambda lambda.Start(handler) }
試す
ビルドして Lambda にアップロードして、
$ go mod init sample $ go get $ GOOS=linux GOARCH=amd64 go build -o main main.go $ zip main.zip main
インプット側の S3 に何かファイルを置けば、コピーがアウトプット側のS3 に出力されるはず。
ソース
さいごに
Lambda で Go は、後から追加されたランタイムなので、Python や Node.js と比べてサンプルが少ないですね。
サクッとコピペで試そうとしたけど、断片的にしか見つけられなかったので、自分の試したかったことだけをまとめました。
参考にしたサイト
s3 - Amazon Web Services - Go SDK
s3manager package - github.com/aws/aws-sdk-go/service/s3/s3manager - pkg.go.dev
session package - github.com/aws/aws-sdk-go/aws/session - pkg.go.dev
Go言語(golang)でS3へファイルをアップロードする | DevelopersIO
Go言語(golang)でS3からファイルを取得する | DevelopersIO
3分で作る、S3イベントで実行するLambda | DevelopersIO
クレデンシャルの適切な扱い方 ー AWS SDK for Goの場合 | DevelopersIO
【Golang】AWSLambdaからS3にアップロードする - 怠慢プログラマーの備忘録
【Go】AWS SDK GoのGetObjectの返り値が16進数になった...!