AWS CDK (Go) で Lambda (Go) をデプロイする
今回の成果物
背景
- AWS CDK が v2 から Go を正式サポートしたのでせっかくなら Go で書きたい
- Lambda も Go で書けるので Go で書きたい
⇒ 全部 Go で書きたい
という感じで Go でゴリゴリ書いていたのですが、皆さんご存じのとおり Go 製 Function を Lambda にデプロイするにはあらかじめ linux/amd64
向けにビルドしておく必要があります。これを CDK で実現するにはどうすればよいのか分からなかったので、色々と調べながら何とか動くものを作れたのでまとめます。
Function のビルドはローカルで実行される
cdk deploy
すると初めにローカルで Lambda Function のビルドが実行され、その後成果物のバイナリを用いて Stack をデプロイという流れになるようです。したがって、事前にローカルで Go 製 Function をビルドするための設定を CDK 上で規定する必要があります。
このビルドですが、純粋なローカル環境を用いたビルド( GOOS=linux GOARCH=amd64 go build
)と Docker コンテナを用いたビルドの二種類が用意されています。詳しくは公式ドキュメントを読んでください。
各ビルド方法での設定は次のように指定することができます。 Bundling
内で指定している Command
が Docker を用いたビルド、 Local
がローカル環境でのビルドに対応します(LocalBundling
の詳細は後述します)。両方設定した場合は Local
が優先されます。
fn := awslambda.NewFunction(stack, jsii.String("Lambda"), &awslambda.FunctionProps{
Runtime: awslambda.Runtime_GO_1_X(),
Code: awslambda.AssetCode_FromAsset(jsii.String("lambda"), &awss3assets.AssetOptions{
Bundling: &awscdk.BundlingOptions{
Image: awslambda.Runtime_GO_1_X().BundlingImage(),
Command: jsii.Strings("bash", "-c", "GOOS=linux GOARCH=amd64 go build -o handler"),
Local: &LocalBundling{},
},
}),
Handler: jsii.String("handler"),
Timeout: awscdk.Duration_Seconds(jsii.Number(30)),
})
Local ビルド
上記の実装について Command
の方は特に説明することはないと思うので、 Local
について解説していきます。内部実装を読むと、 Local
には ILocalBundling というインターフェス型の変数を渡すことになっています(BundlingOptions)。
.....が、この ILocalBundling
が何者なのかよくわからず、調べてみてもびっくりするぐらい情報が出てきません。ネットの海を彷徨ったり、公式ドキュメントと睨めっこしたりしているうちに、どうやら
func TryBundle(outputDir *string, options *awscdk.BundlingOptions) *bool
という関数が実装された何らかのオブジェクトを渡せば良いっぽいことが分かりました。
そこで、下記のような LocalBundling
型を実装しました。TryBundle の引数の outputDir
にはバイナリの吐き出し先(通常は cdk.out/<id>/
)が渡されてくるので、素直にそこに向けてビルドします。
type LocalBundling struct{}
func (*LocalBundling) TryBundle(outputDir *string, options *awscdk.BundlingOptions) *bool {
path := filepath.Join(*outputDir, "handler")
var err error
if runtime.GOOS == "windows" {
err = exec.Command("cmd", "/c", fmt.Sprintf("set GOOS=linux&set GOARCH=amd64&cd lambda&go build -o %s", path)).Run()
} else {
err = exec.Command("bash", "-c", fmt.Sprintf("GOOS=linux GOARCH=amd64 cd lambda && go build -o %s", path)).Run()
}
return jsii.Bool(err == nil)
}
これで cdk synth
や cdk deploy
を実行すると、無事ローカル環境でビルドしたバイナリをデプロイすることができました。
Discussion