AWS Lambda の arm64 アーキテクチャで Go を実行するためのカスタムランタイムを使った SAMテンプレートの紹介

もう ARM のチップしか愛せないので Amazon Linux 2 で動かすしかありませんでした。
2022.02.02

Go で書いたコードを Zip形式の Lambda で実行するついでに「せっかくだから Graviton2(Arm) で動かしたいな」と思い設定方法を調べてみると Go の Lambda は arm64 をサポートしていませんでした。

代りにカスタムランタイムを用いて実行する方法がありました。試行錯誤した結果、動かすことができたので実際の設定をSAMテンプレートベースで紹介します。

Zip形式と、コンテナイメージ形式の違いは以下を参照ください。

なぜ

Go 1.x のランタイムの OS は Amazon Linux の提供しかないため、arm64 が使えませんでした。

Lambda ではプログラミング言語ごとにランタイムが用意されています。Python 3.9 や、Node.js 14 などなどありますが、各言語のバージョンと OS が組になって提供されています。 たとえば Python 3.7 であれば、Amazon Linux で、Python 3.9 は Amazon Linux 2 と言ったようにです。

現在、arm64 に対応している OS は Amazon Linux 2 のみです。Go 1.x のランタイムは Amazon Linux しかありませんでした。

Go 1.x などの Amazon Linux オペレーティングシステムを使用するランタイムは、arm64 アーキテクチャをサポートしません。

検証環境

以下のリンクを参考にして SAM を使って arm64 のLambda をデプロイしてみます。Amazon Linux 2 を使ったカスタムランタイムで実行してくださいといった内容です。

検証に利用したコードは以下に置いてあります。

Product Version
SAM CLI 1.37.0
Go 1.17.6
macOS 11.6.3

やってみた

arm64 対応で必要だったポイントを説明します。

重要なのは Lambda の設定を記述したtemplate.yamlと、ビルドの設定を記述したMakefileの2箇所だけです。

ディレクトリ構成

.
├── README.md
├── hello-world
│   ├── Makefile
│   ├── go.mod
│   ├── go.sum
│   ├── main.go
│   └── main_test.go
├── samconfig.toml
└── template.yaml

SAMテンプレート

Go のランタイムを使うわけではないので Lambda の設定には一切 Go の文字はないです。

  • Runtime で Amazon Linux 2 のイメージを指定
  • Architectures でリスト形式で arm64 を指定
  • Metadata の BuildMethod で後述する maikefile と指定
    • Makefile 自体は大文字の M から始まるファイル名なので注意

template.yaml

AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Description: >
  go-al2

  Sample SAM Template for go-al2
Globals:
  Function:
    Timeout: 5

Resources:
  HelloWorldFunction: # Makefile 内でここの名前を指定する必要がある
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: hello-world/
      Handler: bootstrap
      Runtime: provided.al2 # Amazon Linux 2 ベース
      Architectures: [arm64] # arm64(Graviton2) 指定
      Events:
        CatchAll:
          Type: Api
          Properties:
            Path: /hello
            Method: GET
    Metadata:
      BuildMethod: makefile # go build の設定ファイル

Outputs:
  HelloWorldAPI:
    Description: "API Gateway endpoint URL for Prod environment for First Function"
    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
  HelloWorldFunction:
    Description: "First Lambda Function ARN"
    Value: !GetAtt HelloWorldFunction.Arn
  HelloWorldFunctionIamRole:
    Description: "Implicit IAM Role created for Hello World function"
    Value: !GetAtt HelloWorldFunctionRole.Arn

Makefile

Makefileのファイル名は大文字のMからはじまる必要があります。テンプレートの指定では小文字はじまりのmakefileなので気をつけてください。

  • build- + 関数名の形式でビルド対象を指定(わかりづらいので下のMakefileをご確認ください)
  • クロスコンパイルするためにGOOS=linux GOARCH=arm64を指定

カスタムランタイムの構築 - AWS Serverless Application Model

hello-world/Makefile

build-HelloWorldFunction:
	GOOS=linux GOARCH=arm64 go build -o bootstrap
	cp ./bootstrap $(ARTIFACTS_DIR)/.

sam build & deploy

sam build実行するとMakefileを参照してgo buildが走ります。

$ sam build
Building codeuri: /Users/hoge/github/bigmuramra/sam-sample-arm64-go/hello-world runtime: provided.al2 metadata: {'BuildMethod': 'makefile'} architecture: arm64 functions: ['HelloWorldFunction']
Running CustomMakeBuilder:CopySource
Running CustomMakeBuilder:MakeBuild
Current Artifacts Directory : /Users/hoge/github/bigmuramra/sam-sample-arm64-go/.aws-sam/build/HelloWorldFunction

Build Succeeded

初回のデプロイであれば--guidedを付けて対話式に設定を入力してデプロイしてください。

$ sam deploy --guided

実行確認

デプロイ結果から API Gateway の URL が表示されますので、curl で GET リクエストを送ります。

-----------------------------------------------------------------------------------------------------------------------------
Outputs
-----------------------------------------------------------------------------------------------------------------------------
...snip...

Key                 HelloWorldAPI
Description         API Gateway endpoint URL for Prod environment for First Function
Value               https://hogehoge.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/

...snip...

以下の様にアクセス元のグローバルIPアドレスが返ってきたら成功です。

$ curl https://hogehoge.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/
Hello, [Global IP Address]

マネジメントコンソールからデプロイされた Lambda関数を確認すると arm64 となっています。

以上、SAM を利用した arm64 対応の Go Lambda の設定方法でした。

おわりに

Lambda の Go 1.x が Amazon Linux で動いていることを知ったので試してみました。Amazon Linux はメンテナンスサポート期間(2023年8月まで)に入っているので、Lambda で Go を実行するなら arm64 で動かすかどうかは別として Amazon Linux 2 のカスタムランタイムで実行した方がよいのではないかといった感想です。カスタムランタイムの設定も一度わかってしまえば簡単でした。Lambda でなにか動かす機会があれば試してみようと思います。

Amazon Linux のサポート期限

ちなみにカスタムランタイムを使うと Rust でもなんでもやりようによって実行できます。

参考