はじめに
こんにちは。いかりがわです。
普段はニフティトップページの開発運用を行っています。
このプロダクトの裏側ではGoで記述されたLambda関数がいくつか動いています。
公式からLambda関数についてメールが届きました。どうやらLambda関数のGoランタイムサポートが2023/12/31にサポート終了するらしいです。
1 2 3 4 5 |
お客様の AWS アカウントに現在 Go 1.x ランタイムを使用する 1 つ以上の Lambda 関数があることを確認しましたので、ご連絡いたします。 Amazon Linux AMI のメンテナンスサポートが 2023 年 12 月 31 日に終了するのに合わせて、AWS Lambda での Go 1.x ランタイムのサポートを終了します [1]。 Lambda は、provided.al2 ランタイムを使用して Go プログラミング言語を引き続きサポートします。 provided.al2 ランタイムを使用すると、AWS Graviton2 プロセッサのサポートや、より小さなデプロイパッケージとより高速な関数呼び出しパスによる効率的な実装など、go1.x ランタイムに比べていくつかの利点があります。 詳細については、ブログ記事 [2] を参照してください。 |
Goのランタイムは Amazon Linux AMIに基づいています。Amazon Linux AMIのサポートが 2023/12/31に終了するに伴い、Goのランタイムもサポート終了となるようです。
Goのランタイムで動作しているLambda関数は、ランタイムをprovided.al2
(Amazon Linux 2 AMIベースのカスタムランタイム)に移行する必要があります。
何故Amazon Linux 2 AMIでGoのランタイムをサポートしてくれなかったんだ。。。。
AWS公式からの見解としては以下です。
Go は、他のマネージドランタイムとは異なる方法で実装されています。Go はネイティブコードにコンパイルされるため、Lambda は Go をカスタムランタイムとして扱います。
provided.al2
ランタイムを使用して Go 関数を Lambda にデプロイすることをお勧めします。
Go による Lambda 関数の構築 – AWS Lambda
つまり、「コンパイル後はネイティブコードになるんだからわざわざGoのランタイムとして用意する必要ないやろ」と言うことです。
なので今回は、サポート終了してしまうgo1.x
のランタイムからprovided.al2
のカスタムランタイムに変更していく手順をまとめていきます。
前提
Lambda関数をTerraformで構築するためのディレクトリ構成は以下のようになっています。
1 2 3 4 5 6 7 8 9 10 |
. ├── lambda │ ├── archive // 圧縮後のファイルを保存するディレクトリ │ ├── build // バイナリを保存するディレクトリ │ └── cmd // goのワーキングディレクトリ │ ├── go.mod │ ├── go.sum │ └── main.go └── main.tf |
また、Lambda関数の中で動いているコードは以下のようになっています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
package main import ( "context" "fmt" "github.com/aws/aws-lambda-go/lambda" ) type MyEvent struct { Name string `json:"name"` } func HandleRequest(ctx context.Context, name MyEvent) (string, error) { return fmt.Sprintf("Hello %s!", name.Name), nil } func main() { lambda.Start(HandleRequest) } |
変更してみる
aws_lambda_functionのruntime
ランタイムをgo1.xからprovided.al2に変更します。
前述の通り、コンパイル後はネイティブコードになるため、ランタイムはAmazon Linux 2 AMIベースのカスタムランタイムを指定します。
1 2 3 4 5 6 7 8 9 |
resource "aws_lambda_function" "lambda" { function_name = "go-lambda-sample" filename = "./lambda/archive/sample.zip" role = aws_iam_role.lambda_role.arn handler = "sample" - runtime = "go1.x" // 変更前 + runtime = "provided.al2" // 変更後 source_code_hash = data.archive_file.lambda.output_base64sha256 } |
ビルド後のファイル名
現状のビルド周りのコードは以下のようになっています。
おそらく、TerraformでGoのLambdaを構築する際の一般的な方法だと思います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
resource "null_resource" "default" { triggers = { always_run = timestamp() } provisioner "local-exec" { command = "cd ./lambda/cmd/ && GOOS=linux GOARCH=amd64 go build -o ../build/main main.go" } } data "archive_file" "lambda" { type = "zip" source_file = "./lambda/build/main" output_path = "./lambda/archive/sample.zip" depends_on = [null_resource.default] } |
今回は、go build
の部分を変更します。また、変更後に圧縮するため、圧縮元ファイルも変更します。
カスタムランタイムでは、実行ファイル名はbootstrap
である必要があります。なので、go build
は以下のようになります。
1 2 3 4 5 |
cd ./lambda/cmd/ && GOOS=linux GOARCH=amd64 go build -o ../build/main main.go ↓ cd ./lambda/cmd/ && GOOS=linux GOARCH=amd64 go build -o ../build/bootstrap main.go |
圧縮元ファイルもbootstrap
に変更します。
1 2 3 4 5 6 7 |
data "archive_file" "lambda" { type = "zip" source_file = "./lambda/build/bootstrap" output_path = "./lambda/archive/sample.zip" depends_on = [null_resource.default] } |
確認
実際にコンソールから確認してみます!
ランタイムがAmazon Linux 2 AMIベースのカスタムランタイムになっていることが確認できます!
テストでお試し実行してみても問題なく動作することが確認できます!
意外と簡単にGoランタイムからAmazon Linux 2 AMIベースのカスタムランタイムに移行できることがわかりました。
急いで移行する必要はないですが、簡単に移行できるので早めに移行することをお勧めします!
注意:コールドスタートにかかる時間も請求に含まれる
冒頭のメールに以下のような内容が記述されています。
1 2 3 |
Lambda の請求には、go1.x ランタイムと provided.al2 ランタイムとの間に違いがあります。 go1.x ランタイムでは、Lambda は関数の初期化 (コールドスタート) に費やされた時間を請求しませんが、provided.al2 ランタイムでは、Lambda は請求される関数実行時間に関数の初期化時間を含めます。 Go 関数は通常非常に迅速に初期化され、Lambda は複数の関数呼び出しに関数実行環境を再利用することで初期化の回数を減らすため、実際には Lambda 請求額の違いはごくわずかです。 |
カスタムランタイムに変更すると、コールドスタートにかかる時間も請求に含まれるため多少請求額に変化があるかもしれません。
GitHub
サンプルコードはこちらに公開しています。
https://github.com/k0825/go-lambda-al2-sample