AWS Lambda関数をlambrollとGitHub Actionsでデプロイしてみた ~ fujiwara-ware OSS ~
クラスメソッドは2024年に5つのOSSに対して支援を実施しました。
当方が推薦して選定された @fujiwara さん作による Amazon ECSのデプロイツールであるecspressoについては、先日紹介記事をかきました。
本記事では、 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
様々なアーキテクチャー向けにバイナリが用意されています。
既存の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と認証します。
この際に、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とGitHub Actionsを連携した本格的な導入例としては、次のクラウドワークスさんの事例が参考になります。
最後に
Amazon ECSをデプロイする ecspresso の AWS Lambda版とも言える、AWS Lambdaをデプロイする lambroll を紹介しました。
設計思想は ecspresso と同じで、AWSのインフラリソースのプロビジョニングは行わず、AWS Lambdaのデプロイに必要な設定変更だけを行う、非常にミニマリスティックなツールです。特に、Amazon API Gateway を単一のLambda関数でルーティングしているようなケースや、TerraformでAWSインフラをIaC管理しているケースや、Lambdaをフレームワークに振り回されずにシンプルに運用したいケースでマッチすると思います。
lambroll の設計思想は、作者本人による次の記事が参考になります。
それでは。