Github Actions | Terraform を活用して、AWS Lambda への自動デプロイを構築する
はじめに
最近、私自身Github上でソース管理することが増えてきました。
その上で、Github Actionsを積極的に活用することで、CI/CDを実現することが可能になります。
優秀な生成AIモデルも増えてきましたし、CI/CDを実現するためのハードルが徐々に低くなってきたと感じています。
そんな今だからこそ、今一度自分の中で整理してみようと思い立ち、記事を書くことにしました。
誰かの助けになるかどうかはわかりませんが、業務フロー等の見直しの良いキッカケになることを願います✋
全体構成図
構成図
今回作成していく構成図になります。

Githubへのpushをトリガーにし、Terraforom Applyを実行してAWS上にLambda関数を作成および更新をしていきます。
これによって、Github Actionsを使った自動デプロイを実行してみようといった感じです。
この構成を実現するメリットは以下のように考えます。
- 手動実行する手間がかからない
- Terraformを利用することで複数プラットフォームに対応できる
- トリガーの工夫次第でステージング、プロダクション環境等への適用が容易
- 障害発生時のリカバリーが容易かつ迅速
ディレクトリ構成
最終的に作るディレクトリ構成を先に出しておきます。

.github/workflows/deploy.ymlにはGituhub Actionsから実行するフローをステップごとに分け、それぞれで認証情報の取得、コマンド実行等を担います。
terraform下には、Lambda関数をデプロイするためのHCLがつらつらと書かれます。
TerraformでLambdaデプロイコードを記述
terraformディレクトリを作成し、main.tfとvariables.tfを作成し、Lambda関数を作成するためのコードを記述していきます。
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = var.aws_region
}
data "archive_file" "lambda_zip" {
type = "zip"
source_file = "${path.module}/../lambda_function.py"
output_path = "${path.module}/lambda_function.zip"
}
data "aws_iam_role" "lambda_role" {
name = "hello-lambda-role"
}
## 新規作成時のみ不要
# import {
# to = aws_lambda_function.hello_function
# id = "hello-function"
# }
resource "aws_lambda_function" "hello_function" {
filename = data.archive_file.lambda_zip.output_path
function_name = "hello-function"
role = data.aws_iam_role.lambda_role.arn
handler = "lambda_function.lambda_handler"
source_code_hash = data.archive_file.lambda_zip.output_base64sha256
runtime = "python3.11"
timeout = 30
tags = {
Name = "hello-lambda"
}
}
variable "aws_region" {
description = "AWS region"
type = string
default = "ap-northeast-1"
}
コードを読んで気がついた方がいらっしゃるかもですが、hello-lambda-roleというカスタムロールを使用していて、IAMにてこのロールをあらかじめ作っています。
hello-lambda-roleには、以下のようなポリシーが含まれていればOKです。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "*"
}
]
}
このIAMロールを使用した上で、Lambda関数の作成および更新を行います。
Github Actionsのセットアップ
IAMユーザーの作成
まずは、Github ActionsからTerraform Apply等のコマンドを実行するためのIAMユーザーを作成します。IAMユーザーの作成手順に従い、ユーザーを作成します。

IAM、Lambdaへのアクセスが必要になってくるので、ポリシーを設置しています。
IAMポリシーのベストプラクティスに則ってポリシーを定義すべきでしょうが、一旦はフルアクセスとしました。
アクセスキー、シークレットアクセスキーの発行
作成が終わったら、IAMユーザーのアクセスキー、シークレットアクセスキーを発行しておきます。
これは後にActionsのシークレット、変数に定義しておく必要があるためです。

Actionsシークレットに、アクセスキーを追加
GithubリポジトリのSettings>Secrets and variables>Actionsに移動し、
「New repository secret」ボタンから、追加していきます。
キーにはそれぞれ以下のように指定し、バリューには先ほど発行したアクセスキー、シークレットアクセスキーを追加します。
- AWS_ACCESS_KEY_ID:{アクセスキー}
- AWS_SECRET_ACCESS_KEY:{シークレットアクセスキー}

以下のようにセットされていればOKです。

ActionsのYAMLを作成する
最後に、Github ActionsからTerraformコマンド等を実行するための手順書をYAMLにて記述していきます。
name: Deploy Lambda Function
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
terraform:
name: 'Terraform'
runs-on: ubuntu-latest
environment: production
defaults:
run:
shell: bash
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: 1.5.0
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
- name: Terraform Init
run: terraform init
working-directory: terraform
- name: Terraform Format
run: terraform fmt -check
working-directory: terraform
- name: Terraform Plan
run: terraform plan -input=false
working-directory: terraform
- name: Terraform Apply
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: terraform apply -auto-approve -input=false
working-directory: terraform
今回は、ubuntu-latestのランナーを使用しています。
AWS認証情報の取得後、各種Terraformコマンドの実行をステップで分けています。
自動デプロイを実行してみる
ここまでできたら、冒頭に記載したディレクトリ構成になっているかと思います。
Lambdaは非常にシンプルなものでOKだと思いますので、以下のようなコードでいきます。
これをGithub上にプッシュしていくと・・
import json
def lambda_handler(event, context):
name = event.get('name', 'World')
message = f"Hello {name}さん"
return {
'statusCode': 200,
'body': json.dumps({
'message': message
}, ensure_ascii=False)
}
Actionsが回り始めました。

Actionsが回りきりました。これでTerraform Applyまで完了しています!

無事にLambda関数が作成ができるところまで完了しました!
継続デプロイ時はmain.tfのコメントアウトされている箇所を復活すれば問題なしです。
おわりに
今回はLambdaのみのデプロイでしたが、他にもプラットフォーム問わず色々なサービスをデプロイすることができます。
CI/CDを構築すると、素早いサービス展開、障害の防止、発生時のリカバリーが容易になると考えています。新しいサービスを作るとなった時のためにも、常に知見をアップデートしておきたいところですね。
では!
Discussion