[Lambda] go1.xからprovided.al2へのマイグレーション

先日、LambdaのRuntimeに関する通知がありましたね。
現在関わっているプロジェクトでは、SAMやServerlessFrameworkを活用しています。
年末の提供終了に合わせてRuntimeを変更していきます。

https://aws.amazon.com/jp/blogs/compute/migrating-aws-lambda-functions-from-the-go1-x-runtime-to-the-custom-runtime-on-amazon-linux-2/

## 何が起こる？
届いたメールによると...

- 2023年12月31日
    - AmazonLinuxAMIのメンテナンスサポート終了
    - Lambdaでの Go 1.x ランタイムのサポート終了
        - provided.al2 ランタイムを使用してGo言語をサポート
- provided.al2 ランタイムを使用すると、AWS Graviton2 プロセッサのサポート
- より小さなデプロイパッケージとより高速な関数呼び出しパスによる効率的な実装

## 対応
基本的には、ドキュメント通りに移行していくだけなので簡単ですね。

### SAM
APIとして使っています。
`template.yml`と`Makefile`を変更します。

```yaml:template.yml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  nice handsome

Resources:
  ApiFunctions:
    Type: AWS::Serverless::Function
    Metadata:
      BuildMethod: makefile　
    Properties:
      CodeUri: .
      # Handler: main.go
      # Runtime: go1.x
      Handler: bootstrap
      Runtime: provided.al2
      MemorySize: 4096
      Tracing: Active
      Events:
        CatchAll:
          Type: Api
          Properties:
            Path: /{proxy+}
            Method: ANY
            RestApiId: !Ref TestApiGateway
      Role: !GetAtt TestApiFunctionsRole.Arn
```

```makefile:Makefile
.PHONY: build-ApiFunctions
build-ApiFunctions:
	# GOARCH=amd64 GOOS=linux CGO_ENABLED=0 go build -o ${ARTIFACTS_DIR}/main.go main.go
	GOARCH=amd64 GOOS=linux CGO_ENABLED=0 go build -o ${ARTIFACTS_DIR}/bootstrap main.go
```

#### Handler名の変更について
`Handler`が`bootstrap`以外でも動くか試してみました。
デプロイは可能ですが動かないので注意してください....

> While the go1.x runtime allows you to use any executable name, the provided.al2 runtime requires you to use bootstrap as the executable name. On macOS and Linux, here’s the simplest form of the build command
https://aws.amazon.com/jp/blogs/compute/migrating-aws-lambda-functions-from-the-go1-x-runtime-to-the-custom-runtime-on-amazon-linux-2/


```:CloudWatchログ
2023-08-27T14:35:31.539+09:00
RequestId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx Error: Couldn't find valid bootstrap(s): [/var/task/bootstrap /opt/bootstrap]
Runtime.InvalidEntrypoint
```


### ServerlessFramework
主にスケジューラなどの処理に使っています。
基本的には、`provided.al2`に変更するだけです。
`serverless.yml`を変更します。

```yaml:serverless.yml
service: test-functions
frameworkVersion: '3'

provider:
  name: aws
  region: ap-northeast-1
  timeout: 180
  # runtime: go1.x
  runtime: provided.al2
  lambdaHashingVersion: 20201221
  stage: ${opt:stage, "stg"}
  environment:
    ENV: ${opt:stage, "stg"}
    TZ: "Asia/Tokyo"
    # ↓追加
    CONFIG_SECRET: ${opt:stage, "stg"}/test-functions
  iamRoleStatements:
    - Effect: "Allow"
      Action:
        # 省略
        # ↓追加
        - "secretsmanager:GetSecretValue"

custom:
  go:
    cmd: GOARCH=amd64 GOOS=linux go build -ldflags="-s -w"
    # supportedRuntimes: ["go1.x"]
    supportedRuntimes: ["provided.al2"]
    buildProvidedRuntimeAsBootstrap: true

package:
  individually: true
  exclude:
    - "./**"
  # NOTE: Runtimeが変わったことによりファイルパスが変わったため
  # include:
  # - "./bin/**"
  # - "./src/config/stg/env.yml"
  # - "./src/config/prod/env.yml"

functions:
  create-message:
    # handler: bin/create-message
    handler: src/create-message/main.go src/create-message/sub_message.go
    events:
      - schedule: rate(15 minutes)
    maximumEventAge: 3600
    maximumRetryAttempts: 0

plugins:
  - serverless-go-plugin
```

#### ハマった点
`go1.x`と違って、includeしているファイルがコード上で読み込めなかったです。
provided.al2のディレクトリがどうなっているかは確認できていません。

```:CloudWatchログ
INIT_START Runtime Version: provided:al2.v21	Runtime Version ARN: arn:aws:lambda:ap-northeast-1::runtime:hogehoge

2023/08/27 16:43:25 load config error: open src/config/stg/env.yml: no such file or directory
```

元々の用途としては、環境差分のある値が入っているだけなのでsecrets managerに値を移行し取得するように変更しました。

#### [余談] `serverless-go-plugin`について
GithubActions上で対象の関数の`go build`を書き忘れるので`serverless-go-plugin`を導入しました。
今回の移行のついでにやったことにより、デプロイ忘れがなくなって素敵になりました。

きっかけは、SAMのHandler命名に関するエラーを調査していたときに見つけた感じです。

https://github.com/serverless/serverless/discussions/11667#discussioncomment-4976759

おかげでworkflowがスッキリしました。

```yml:deploy-stg.yml
name: deploy-stg
on:
  push:
    branches:
      - "main"

jobs:
  deploy-stg:
    name: deploy-stg
    runs-on: ubuntu-latest
    steps:
      - name: checkout
        uses: actions/checkout@v3

#       - name: setup go
#         uses: actions/setup-go@v4
#         with:
#           go-version-file: 'go.mod'
#           cache: true

      - name: setup node
        uses: actions/setup-node@v3
        with:
          node-version: 16

#       - name: clean up
#         run: rm -rf ./bin

#       - name: build
#         run: |
#             env GOARCH=amd64 GOOS=linux go build -ldflags="-s -w" -o bin/create-message/bootstrap src/create-message/main.go

      - name: install serverless
#       run: npm i -g serverless
        run: npm i -g serverless serverless-go-plugin

      - name: deploy
        run: sls deploy --verbose --stage stg
```

## 参考
https://aws.amazon.com/jp/blogs/compute/migrating-aws-lambda-functions-from-the-go1-x-runtime-to-the-custom-runtime-on-amazon-linux-2/

https://github.com/mthenw/serverless-go-plugin