AWS Lambda関数をlambrollとGitHub Actionsでデプロイしてみた ~ fujiwara-ware OSS ~

AWS Lambda関数をlambrollとGitHub Actionsでデプロイしてみた ~ fujiwara-ware OSS ~

クラスメソッドによる2024年OSS支援対象の @fujiwara さん作の Lambda デプロイツール「lambroll」を紹介してみる
Clock Icon2024.08.19

クラスメソッドは2024年に5つのOSSに対して支援を実施しました。

https://dev.classmethod.jp/articles/oss-sponser-2024/

当方が推薦して選定された @fujiwara さん作による Amazon ECSのデプロイツールであるecspressoについては、先日紹介記事をかきました。

https://dev.classmethod.jp/articles/ecspresso-ecs-deployment-tool/

本記事では、 ecspresso の姉妹プロダクトとも言える、AWS Lambdaのデプロイツール lamboll について、基本的な使い方とGitHub Actionsからデプロイする方法について紹介します。

lambrollはミニマリストのためのAWS Lambdaデプロイツール

GitHubのプロジェクトページから lambroll の概要を引用します

lambroll is a minimal deployment tool for AWS Lambda.

lambroll はLambda関数のデプロイに必要な最小限の機能しか提供しません。やっていることといえば、ソースコードをZipアップロードしたり、Lambda関数の設定を更新するだけです。高機能でカスタマイズ性の高いServerless FrameworkやAWS SAMやAWS CDKのようなフレームワークを渡り歩いた後にたどり着く、 禅のようなフレームワーク です。

Lambda関数が実行時に利用するIAMやVPCといったインフラストラクチャのリソースは参照するだけであり、まさに ECSデプロイツール「ecspresso」のAWS Lambda関数版 です。

lambrollを導入してデプロイするまでの流れ

既存のLambda関数を lambroll でデプロイするまでの流れを紹介します。

lambrollをダウンロード

まずはlambrollをダウンロードします

macOSならbrewからインストールできます

$ brew install fujiwara/tap/lambroll

様々なアーキテクチャー向けにバイナリが用意されています。

https://github.com/fujiwara/lambroll/releases/

既存のLambda関数を取り込む

lambroll init コマンドを利用すると、既存Lambda関数を取り込めます。

関数名を指定し、取り込みましょう。

$ mkdir hello
$ cd hello
$ lambroll init --function-name hello --download
2024/08/17 03:30:23 [info] lambroll v1.0.6
2024/08/17 03:30:23 [info] function hello found
2024/08/17 03:30:23 [info] downloading function.zip
2024/08/17 03:30:23 [info] creating .lambdaignore
2024/08/17 03:30:23 [info] creating function.json

$ unzip function.zip
Archive:  function.zip
replace function.json? [y]es, [n]o, [A]ll, [N]one, [r]ename: A
  inflating: function.json           
  inflating: function.zip            
  inflating: lambda_function.py     

$ ls -1
function.json
function.zip
lambda_function.py

$ cat function.json
{
  "Architectures": [
    "x86_64"
  ],
  "EphemeralStorage": {
    "Size": 512
  },
  "FunctionName": "hello",
  "Handler": "lambda_function.lambda_handler",
  "LoggingConfig": {
    "LogFormat": "Text",
    "LogGroup": "/aws/lambda/hello"
  },
  "MemorySize": 128,
  "Role": "arn:aws:iam::123456789012:role/test_lambda_basic_execution_role",
  "Runtime": "python3.12",
  "SnapStart": {
    "ApplyOn": "None"
  },
  "Timeout": 3,
  "TracingConfig": {
    "Mode": "PassThrough"
  }
}

function.json は関数定義ファイル、function.zip はソースコードです。

Terraformと連携する

lambrollの嬉しい機能の一つは、Terafformとシームレスに連携できることです。

具体的には、Terraformのリソース状態をStateファイル(tfstate)で管理していると、AWSリソースIDをTerraformの論理名に置き換えられます。

Lambda関数の定義ファイル(function.json)内のLambda関数実行ロールをTerraform管理されているリソースを Terraformの論理名で置き換えます。

{
  ...
  "MemorySize": 128,
  "Role": "{{ tfstate `aws_iam_role.lambda_role.arn` }}",
  ...
}

正しく設定されていることを確認しましょう。

$ lambroll render --tfstate=s3://YOUR-BUCKET/path/to/terraform.tfstate
{
  ...
  "MemorySize": 128,
  "Role": "Role": "arn:aws:iam::123456789012:role/test_lambda_basic_execution_role",
  ...
}

Terraformで管理されているリソース一覧は $ terraform state list で確認できます。

Lambda関数の設定変更とコード変更を実施

Lambda関数の設定を変更し、Lambda関数を修正します。

$ lambroll diff --tfstate=s3://YOUR-BUCCKET/path/to/terraform.tfstate
2024/08/17 03:48:41 [info] lambroll v1.0.6
--- arn:aws:lambda:ap-northeast-1:123456789012:function:hello:$LATEST
+++
@@ -17,7 +17,7 @@
   "SnapStart": {
     "ApplyOn": "None"
   },
-  "Timeout": 3,
+  "Timeout": 30,
   "TracingConfig": {
     "Mode": "PassThrough"
   }

$ cat lambda_function.py
def lambda_handler(event, context):
    return("hello world from lambroll!")

デプロイする

最後に $ lambroll deploy を実行し、Lambda関数が更新されればデプロイ完了です。

$ lambroll deploy --tfstate=s3://YOUR-BUCCKET/path/to/terraform.tfstate
2024/08/17 03:49:05 [info] lambroll v1.0.6
2024/08/17 03:49:05 [info] starting deploy function hello
2024/08/17 03:49:05 [info] creating zip archive from .
...
2024/08/17 03:49:14 [info] deployed version 2
2024/08/17 03:49:14 [info] updating alias set current to version 2
2024/08/17 03:49:14 [info] alias updated

$ lambroll versions --tfstate=s3://YOUR-BUCCKET/path/to/terraform.tfstate
2024/08/17 03:50:17 [info] lambroll v1.0.6
+---------+----------------------+---------+------------+
| VERSION |    LAST MODIFIED     | ALIASES |  RUNTIME   |
+---------+----------------------+---------+------------+
|       1 | 2024-08-14T03:43:01Z |         | python3.12 |
|       2 | 2024-08-17T03:49:07Z | current | python3.12 |
| $LATEST | 2024-08-17T03:49:07Z |         | python3.12 |
+---------+----------------------+---------+------------+

新しい関数を実行します。

$ lambroll invoke --payload='{}' --tfstate=s3://YOUR-BUCCKET/path/to/terraform.tfstate
2024/08/17 03:52:46 [info] lambroll v1.0.6
"hello world from lambroll!"
2024/08/17 03:52:46 [info] StatusCode:200
2024/08/17 03:52:46 [info] ExecutionVersion:$LATEST

新しい関数が実行されました。

GitHub Actionsと連携

次に、.zipファイルアーカイブ版のLambda関数をGitHub Actionsのワークフローでデプロイします。

ポイントは以下です

  • GitHubからAWSへはOpenID Connectで認証
  • GitHub ActionsがassumeするIAMロールを用意し、デプロイに必要なアクションを許可
  • IAMロールのARNはGitHubのシークレットで管理

ソースツリー

以下の様なソースコードツリーを用意します。

.github
└── workflows
    └── deploy.yaml
└── lambda
    └── hello
        ├── function.json
        └── lambda_function.py

GitHub ActionsがassumeするIAMロールを作成

GitHubからはOpenID ConnectでAWSと認証します。

https://docs.github.com/en/actions/security-for-github-actions/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services

この際に、GitHub ActionsがデプロイのためにassumeするAWS IAMロールを作成し、IAMロールのARNを GitHubのシークレットで管理します。

信頼関係

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringLike": {
                    "token.actions.githubusercontent.com:sub": "repo:Your-Account/Your-Repository:*"
                }
            }
        }
    ]
}

Condition にあるように、レポジトリで制限をかけています。

許可ポリシー

デプロイに必要なアクションを許可します。

Lambda関数がVPC LambdaやコンテナイメージLambdaの場合、許可するアクションの種類も増えます。

取っ掛かりとしては、マネージドポリシーのAWSLambda_FullAccess を許可するとよいでしょう。

IAMロール作成用のCloudFormationテンプレート

このようなIAMロールを作成するCloudFormationテンプレートは次の通りです。

AWSTemplateFormatVersion: '2010-09-09'
Parameters:
  GitHubRepoName:
    Description: "GitHub repository (format: owner/repo)"
    Type: String
    Default: "owner/repo"
Resources:
  LambdaDeployRole:
    Type: "AWS::IAM::Role"
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal:
              Federated: !Sub 'arn:aws:iam::${AWS::AccountId}:oidc-provider/token.actions.githubusercontent.com'
            Action: "sts:AssumeRoleWithWebIdentity"
            Condition:
              StringLike:
                token.actions.githubusercontent.com:sub: !Sub 'repo:${GitHubRepoName}:*'
      ManagedPolicyArns:
        - "arn:aws:iam::aws:policy/AWSLambda_FullAccess"
Outputs:
  RoleArn:
    Description: "The ARN of the IAM role"
    Value: !GetAtt LambdaDeployRole.Arn

デプロイ用ワークフローを作成

以下の様な .github/workflows/deploy.yaml を用意します。

name: deploy lambda

on:
  workflow_dispatch:

permissions:
  id-token: write
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: fujiwara/lambroll@v1
        with:
          version: v1.0.6
      - name: Git clone the repository
        uses: actions/checkout@v4
      - name: configure aws credentials
        uses: aws-actions/configure-aws-credentials@v3
        with:
          aws-region: ap-northeast-1
          role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
      - run: lambroll deploy
        working-directory: lambda/hello/

先ほどシークレット管理したAWS IAMロールは、 role-to-assume: ${{ secrets.AWS_ROLE_ARN }} というように参照しています。

Actionsからデプロイ

最後に、ActionsからLambdaをデプロイするワークフローを実行します。

lambroll-run-workflow

デプロイの実行ログです

lambroll-run-workflow-log

実践例

lambrollとGitHub Actionsを連携した本格的な導入例としては、次のクラウドワークスさんの事例が参考になります。

https://engineer.crowdworks.jp/entry/2023/03/27/100000

最後に

Amazon ECSをデプロイする ecspresso の AWS Lambda版とも言える、AWS Lambdaをデプロイする lambroll を紹介しました。
設計思想は ecspresso と同じで、AWSのインフラリソースのプロビジョニングは行わず、AWS Lambdaのデプロイに必要な設定変更だけを行う、非常にミニマリスティックなツールです。特に、Amazon API Gateway を単一のLambda関数でルーティングしているようなケースや、TerraformでAWSインフラをIaC管理しているケースや、Lambdaをフレームワークに振り回されずにシンプルに運用したいケースでマッチすると思います。

lambroll の設計思想は、作者本人による次の記事が参考になります。

https://sfujiwara.hatenablog.com/entry/lambroll

それでは。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.