はじめに
コマンドラインツールをインストールして Lambda で実行するため、ECR のコンテナイメージで動作する AWS Lambda を実装し、GitHub Actions からデプロイする機会がありましたので、その手順を記載します。
GitHub Actions から AWS SAM を実行して、AWS Lambda のデプロイを行います。
やること
AWS Lambda へデプロイするプログラムをローカルでテストする環境を構築
準備
準備するファイルとフォルダ構成
VSCode Dev Container を使ってローカルでテストする環境を作成します。
|--.devcontainer | |--devcontainer.json |--.vscode | |--extensions.json | |--launch.json | |--settings.json |--Dockerfile |--lambda | |--app.py | |--requirements.txt
.devcontainer/devcontainer.json
コンテナ内で Python のデバッグができる様に VSCode の拡張機能をインストールする指定を入れています。
Lambda 実行プログラムの配置先である「/var/task」をカウントしています。
{
"name": "lambda_ecr",
"build": {
"dockerfile": "${localWorkspaceFolder}/Dockerfile",
"args": {}
},
"runArgs": [
"--name=lambda_ecr",
"--volume=${localWorkspaceFolder}/lambda:/var/task",
"--volume=${localWorkspaceFolder}/.vscode:/var/task/.vscode"
],
"workspaceFolder": "/var/task",
"customizations": {
"vscode": {
"extensions": [
"ms-python.autopep8",
"ms-python.python",
"ms-python.vscode-pylance",
]
}
}
}
.vscode/extensions.json
コンテナ外で使用する VSCode の拡張機能を定義しています。
{
"recommendations": [
"ms-python.autopep8",
"ms-python.python",
"ms-python.vscode-pylance",
"ms-vscode-remote.remote-containers"
]
}
.vscode/launch.json
Docker 内でデバッグ起動する際に使用します。
{
"version": "0.2.0",
"configurations": [
{
"name": "Python: Lambda",
"type": "debugpy",
"request": "launch",
"program": "${workspaceFolder}/app.py",
"console": "integratedTerminal",
"args": []
}
]
}
.vscode/settings.json
フォーマット定義
{
"editor.tabSize": 4,
"editor.renderWhitespace": "all",
"terminal.integrated.scrollback": 10000,
"extensions.ignoreRecommendations": false,
"editor.formatOnSave": true,
"editor.formatOnPaste": true,
"[python]": {
"editor.defaultFormatter": "ms-python.autopep8",
"editor.formatOnSave": true
},
}
lambda/app.py
Lambdaメイン処理
「python app.py」で実行できる様に、if __name__ == "__main__":を定義しています。
import json
def lambda_handler(event, context):
"""
Lambdaメイン処理
"""
print(json.dumps(event, ensure_ascii=False))
return {
'statusCode': 200,
'body': 'Hello World!',
}
if __name__ == "__main__":
event = {}
context = {}
print(lambda_handler(event, context))
lambda/requirements.txt
ライブラリインポート用
空のファイルを準備します。
Dockerfile
tar と gzip は、コンテナ内で VSCode の拡張機能をインストールするために必要です。
FROM public.ecr.aws/lambda/python:3.12
RUN set -ex \
&& dnf -y update \
&& dnf install -y tar gzip
COPY lambda/ ${LAMBDA_TASK_ROOT}
RUN pip3 install -r requirements.txt
ENV \
TZ='Asia/Tokyo'
CMD [ "app.lambda_handler" ]
Dev Container起動
左下「><」アイコンをクリックして、「コンテナを再度開く」を選択します。

左メニューの拡張機能アイコンをクリック、「@recommended 」を入力して推奨される拡張機能の一覧を表示して、「ワークスペースのおすすめの拡張機能をインストール」を実行してインストールします。

デバッグ起動
左メニューのデバッグアイコンをクリック、ブレークポイントを設定してデバッグ起動するとブレークポイントで止まることを確認します。

Github Actions からデプロイする設定
GitHub Actions から AWS へアクセスするため GitHub ID プロバイダ作成
GitHub Actions で IAM ロールを利用して AWS へアクセスするために、ID プロバイダを登録します。一時的なクレデンシャルを利用して GitHub Actions から AWS へアクセスするためよりセキュアに接続することができます。
IAM から、アクセス管理 – プロバイダを追加を実行します。
プロバイダの URL:OpneID Connect
プロバイダーの URL: https://token.actions.githubusercontent.com
対象者: sts.amazonaws.com

GitHub Actions 用の IAM ポリシー、IAM ロール作成
IAM で、GitHub Actions 用のIAMポリシーを作成します。下記権限のポリシーをポリシー名「lambda-ecr-deploy-policy」で作成します。
- CloudFormation テンプレートファイルを S3 へ格納するため S3 の権限が必要
- CloudFormation を実行する権限が必要
- Lambda に対する権限が必要
- ECR プッシュする権限が必要
- (この例では必要なかったが)CloudFormation テンプレートファイルで IAM に関する定義がある場合は権限が必要
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "0",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject"
],
"Resource": "arn:aws:s3:::lambda-ecr-deploy-{AWSアカウントID}/*"
},
{
"Sid": "1",
"Effect": "Allow",
"Action": "cloudformation:*",
"Resource": [
"arn:aws:cloudformation:ap-northeast-1:{AWSアカウントID}:stack/lambda-ecr-deploy-stack/*",
"arn:aws:cloudformation:ap-northeast-1:aws:transform/Serverless-2016-10-31"
]
},
{
"Sid": "2",
"Effect": "Allow",
"Action": "lambda:*",
"Resource": [
"arn:aws:lambda:ap-northeast-1:{AWSアカウントID}:function:lambda-ecr-deploy"
]
},
{
"Sid": "3",
"Effect": "Allow",
"Action": [
"ecr:GetAuthorizationToken",
"ecr:BatchCheckLayerAvailability",
"ecr:GetDownloadUrlForLayer",
"ecr:GetRepositoryPolicy",
"ecr:DescribeRepositories",
"ecr:ListImages",
"ecr:DescribeImages",
"ecr:BatchGetImage",
"ecr:GetLifecyclePolicy",
"ecr:GetLifecyclePolicyPreview",
"ecr:ListTagsForResource",
"ecr:DescribeImageScanFindings"
],
"Resource": [
"*"
]
},
{
"Sid": "4",
"Effect": "Allow",
"Action": [
"ecr:BatchCheckLayerAvailability",
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload",
"ecr:PutImage"
],
"Resource": [
"arn:aws:ecr:ap-northeast-1:{AWSアカウントID}:repository/lambda-ecr-deploy-ecr"
]
},
{
"Sid": "5",
"Effect": "Allow",
"Action": [
"iam:CreateRole",
"iam:DetachRolePolicy",
"iam:AttachRolePolicy",
"iam:GetRole",
"iam:DeleteRole",
"iam:PassRole"
],
"Resource": [
"*"
]
}
]
}
IAM で、GitHub Actions 用の IAM ロールを作成します。下記権限のポリシーをポリシー名「lambda-ecr-deploy-role」で作成します。
信頼されたエンティティタイプ:カスタム信頼ポリシー
カスタム信頼ポリシー
- IDプロバイダーを使用すること宣言
- 接続するGitHubリポジトリを定義
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::{AWSアカウントID}:oidc-provider/token.actions.githubusercontent.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
},
"StringLike": {
"token.actions.githubusercontent.com:sub": "repo:{GitHubリポジトリ}:*"
}
}
}
]
}
Lambda 用のIAMポリシー、IAMロール作成
IAM で、Lambda 用のIAMポリシーを作成します。下記権限のポリシーをポリシー名「lambda-ecr-deploy-run-policy」で作成します。
- LambdaからCloudWatchへログ出力するのに必要な権限のみ定義
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "0",
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "*"
}
]
}
IAM で、Lambda 用の IAM ロールを作成します。下記権限のポリシーをポリシー名「lambda-ecr-deploy-run-role」で作成します。
信頼されたエンティティタイプ:AWS のサービス
サービスまたはユースケース:Lambda

ECR リポジトリ作成
ECR 名「lambda-ecr-deploy-ecr」、プライベートな ECR 定義を作成します。
S3 バケット作成
バケット名「lambda-ecr-deploy-{AWSアカウントID}」で作成します。
Lambda 用の CloudFormation テンプレート作成
ファイルを追加して、Lambda 用の CloudFormation テンプレートを作成します。
|--.devcontainer | |--devcontainer.json |--.vscode | |--extensions.json | |--launch.json | |--settings.json |--Dockerfile |--lambda | |--app.py | |--requirements.txt |--lambda-stack.yaml ← ★追加★
lambda-stack.yaml
Lambda 本体の定義のみで、作成済みの IAM ロールと ECR リポジトリを指定しています。ImageConfig\Command で実行する Lambda 関数を指定しています。
AWSTemplateFormatVersion: "2010-09-09"
Transform: AWS::Serverless-2016-10-31
Parameters:
Project:
Type: String
AccountId:
Type: String
Resources:
EcrFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: !Sub ${Project}
CodeUri: lambda/
Role: !Sub arn:aws:iam::${AWS::AccountId}:role/${Project}-run-role
PackageType: Image
ImageUri: !Sub ${AWS::AccountId}.dkr.ecr.ap-northeast-1.amazonaws.com/${Project}-ecr:latest
ImageConfig:
Command:
- "app.lambda_handler"
GitHub Actions 定義作成
ファイルを追加して、GitHub Actions 用のワークフローファイルを作成します。
|--.devcontainer | |--devcontainer.json |--.github | |--workflows | | |--lambda_deploy_dev.yaml ← ★追加★ |--.vscode | |--extensions.json | |--launch.json | |--settings.json |--Dockerfile |--lambda | |--app.py | |--requirements.txt |--lambda-stack.yaml
lambda_deploy_dev.yaml
処理の流れは
- GitHub 資源チェックアウト
- GitHub 用 IAM ロールのセッション受入
- ECR ログイン
- Docker ビルド
- ECR へDocker イメージプッシュ
- AWS SAM コマンドで Lambda デプロイ
- Lambda の新しいイメージをデプロイ実行(ECR へ Docker イメージプッシュしただけでは、Lambda の参照 ECR イメージは最新化されないため、最新化するコマンドを実行する)
name: Lambda Deploy Development
on:
workflow_dispatch:
env:
AWS_ACCOUNT_ID: {AWSアカウントID}
AWS_IAM_ROLE_ARN: arn:aws:iam::{AWSアカウントID}:role/lambda-ecr-deploy-role
AWS_DEFAULT_REGION: ap-northeast-1
PROJECT: lambda-ecr-deploy
SAM_CLI_TELEMETRY: 1
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ env.AWS_IAM_ROLE_ARN }}
role-session-name: github-actions-${{ github.run_id }}
aws-region: ${{ env.AWS_DEFAULT_REGION }}
- run: aws sts get-caller-identity
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: Build Docker
working-directory: ./
run: |
docker build -t ${{ env.PROJECT }}-ecr -f ./Dockerfile .
docker tag ${{ env.PROJECT }}-ecr:latest ${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/${{ env.PROJECT }}-ecr:latest
- name: Push Image to Amazon ECR
working-directory: ./
run: |
docker push ${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/${{ env.PROJECT }}-ecr:latest
- name: ECR Lambda Stack
env:
STACK_NAME: ${{ env.PROJECT }}-stack
TEMPLATE_NAME: lambda-stack.yaml
working-directory: ./
run: |
sam build --use-container \
--template-file ${TEMPLATE_NAME}
sam deploy --no-confirm-changeset \
--stack-name ${STACK_NAME} \
--template-file ${TEMPLATE_NAME} \
--s3-bucket ${{ env.PROJECT }}-${AWS_ACCOUNT_ID} \
--image-repository ${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/${{ env.PROJECT }}-ecr \
--parameter-overrides Project=${{ env.PROJECT }} AccountId=${AWS_ACCOUNT_ID} \
--capabilities CAPABILITY_IAM \
--no-fail-on-empty-changeset
- name: Lambda Renew Image
run: |
aws lambda update-function-code \
--function-name ${{ env.PROJECT }} \
--image-uri ${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/${{ env.PROJECT }}-ecr:latest
GitHub Actions 実行
GiHub Actions のリポジトリで、「Actions」タブ押下、左メニューのワークフロー名押下、「Run workflow」押下、該当の Branch を選択して、「Run workflow」押下して、GitHub Actions を実行し、
GiHub Actions が正常終了することを確認します。

Lambda テスト実行
GiHub Actions 正常終了後、Lambda「lambda-ecr-deploy」がデプロイされていることを確認した後に、
イベント名:任意の値
イベントJSON:{}(任意のJSON値)
を入力して「テスト」ボタン押下してテスト実行し、正常に下記が出力されていることを確認します。
{
"statusCode": 200,
"body": "Hello World!"
}
ECR のコンテナイメージで動作する AWS Lambda を GitHub Actions からデプロイし、テスト実行できるまでできました!

