概要
GitHubActionsを使って、terraformで構築したLambdaをデプロイする方法を紹介します。
まずは、terraformでLambdaを構築します。
次のような流れで構築することを想定します。
- Lambdaのソースコード(ダミー)をzipにアーカイブする
- アーカイブしたzipファイルを使用してLambda関数を作成する
ダミーのZipファイルを作成するdata sourceを作成します。
main.tf
| data "archive_file" "improv_archive_file" {
type = var.type
source_dir = var.source_dir
output_path = var.output_path
}
|
outputs.tf
| output "file_hash" {
description = "The SHA256 hash of the archive file"
value = data.archive_file.improv_archive_file.output_base64sha256
}
output "output_path" {
description = "The path to the archive file"
value = data.archive_file.improv_archive_file.output_path
}
|
variables.tf
1
2
3
4
5
6
7
8
9
10
11
12
13
14 | variable "type" {
description = "The type of archive to create"
type = string
}
variable "source_dir" {
description = "The directory containing the Lambda function source code"
type = string
}
variable "output_path" {
description = "The path to the output archive"
type = string
}
|
Lambda関数を定義します。
main.tf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 | resource "aws_lambda_function" "this" {
function_name = var.function_name
handler = var.handler
runtime = "python${var.python_version}"
role = var.role_arn
environment {
variables = var.enable_environment_variables ? var.environment_variables : {}
}
layers = var.enable_layers ? var.layers : []
filename = var.zip_file
timeout = var.timeout
memory_size = var.memory_size
}
|
variables.tf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48 | variable "function_name" {
description = "The name of the Lambda function"
type = string
}
variable "handler" {
description = "The entry point of the Lambda function"
type = string
}
variable "python_version" {
description = "The Python version to use"
type = string
}
variable "role_arn" {
description = "The ARN of the IAM role to use"
type = string
}
variable "zip_file" {
description = "The path to the archive file"
type = string
}
variable "timeout" {
description = "The amount of time your Lambda function has to run in seconds"
type = number
}
variable "memory_size" {
description = "The amount of memory your Lambda function has access to in MB"
type = number
}
variable "enable_environment_variables" {
description = "Whether to enable environment variables"
type = bool
default = false
}
variable "environment_variables" {
description = "A map that defines environment variables for the Lambda function"
type = map(string)
default = {}
}
variable "enable_layers" {
description = "Whether to enable layers"
type = bool
default = false
}
variable "layers" {
description = "A list of ARNs of Lambda layers to add to the function's execution environment"
type = list(string)
default = []
}
|
outputs.tf
| output "function" {
description = "The ARN and name of the lambda function"
value = {
arn = aws_lambda_function.this.arn
name = aws_lambda_function.this.function_name
}
}
|
| terraform init
terraform apply
|
マネジメントコンソールより、ダミーソースコードでLambdaが作成されたことを確認します。
GitHubActionsでLambdaをデプロイする
GitHubActionsを使って、Lambdaをデプロイします。
Slackへ通知を行うLambdaをデプロイする例を示します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130 | name: Deploy common SampleLambda
on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
aws_environment:
description: 'AWS Environment(dev2 or prod)'
required: true
default: 'prod'
aws_region:
description: 'AWS region'
required: true
default: 'ap-northeast-1'
actions_role_name:
description: 'IAM Role name (excluding environment names)'
required: true
default: 'improvement-role-github-actions-deployment'
function_name:
description: 'Lambda function name'
required: true
default: 'SampleLambda'
function_dir:
description: 'Current directory'
required: true
default: 'lambda/SampleLambda'
s3_bucket:
description: 'Dependencies S3 bucket (excluding environment names)'
required: true
default: 'improvement-input-file'
lambda_function_zip_name:
description: 'Lambda function zip name'
required: true
default: 'SampleLambda.zip'
jobs:
build:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.11'
- name: Set default environment variables
run: |
echo "AWS_ENVIRONMENT=${{ github.event.inputs.aws_environment || 'prod' }}" >> $GITHUB_ENV
echo "AWS_REGION=${{ github.event.inputs.aws_region || 'ap-northeast-1' }}" >> $GITHUB_ENV
echo "ACTIONS_ROLE_NAME=${{ github.event.inputs.actions_role_name || 'improvement-role-github-actions-deployment' }}" >> $GITHUB_ENV
echo "FUNCTION_NAME=${{ github.event.inputs.function_name || 'SampleLambda' }}" >> $GITHUB_ENV
echo "FUNCTION_DIR=${{ github.event.inputs.function_dir || 'lambda/SampleLambda' }}" >> $GITHUB_ENV
echo "S3_BUCKET=${{ github.event.inputs.s3_bucket || 'improvement-input-file' }}" >> $GITHUB_ENV
echo "LAMBDA_FUNCTION_ZIP_NAME=${{ github.event.inputs.lambda_function_zip_name || 'SampleLambda.zip' }}" >> $GITHUB_ENV
- name: Set AWS account ID
id: set-aws-account-id
run: |
if [ "${{ env.AWS_ENVIRONMENT }}" = "prod" ]; then
echo "AWS_ACCOUNT_ID=${{ secrets.AWS_ACCOUNT_ID_PROD }}" >> $GITHUB_ENV
elif [ "${{ env.AWS_ENVIRONMENT }}" = "dev2" ]; then
echo "AWS_ACCOUNT_ID=${{ secrets.AWS_ACCOUNT_ID_DEV2 }}" >> $GITHUB_ENV
else
echo "AWS_ACCOUNT_ID=${{ secrets.AWS_ACCOUNT_ID_STG2 }}" >> $GITHUB_ENV
fi
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::${{ env.AWS_ACCOUNT_ID }}:role/${{ env.ACTIONS_ROLE_NAME }}-${{ env.AWS_ENVIRONMENT }}
role-session-name: GithubActions
aws-region: ${{ env.AWS_REGION }}
- name: Get Caller Identity is Allowed to Run on Role.
run: aws sts get-caller-identity
- name: Archive Lambda function script
run: |
cd ${{ env.FUNCTION_DIR }}
find . -type d -name 'tests' -prune -o -type f -name '*.py' -print > py_files_list.txt
zip -@ ${{ env.LAMBDA_FUNCTION_ZIP_NAME }} < py_files_list.txt
rm py_files_list.txt
- name: Upload Lambda function to S3
run: |
aws s3 cp ${{ env.FUNCTION_DIR }}/${{ env.LAMBDA_FUNCTION_ZIP_NAME }} s3://${{ env.S3_BUCKET }}-${{ env.AWS_ENVIRONMENT }}/
- name: Get current environment variables
id: get-env-vars
run: |
aws lambda get-function-configuration \
--function-name ${{ env.FUNCTION_NAME }} \
--region ${{ env.AWS_REGION }} \
--query 'Environment.Variables' > current_env_vars.json
cat current_env_vars.json
- name: Merge new environment variables
id: merge-env-vars
run: |
jq -n \
--argjson current "$(cat current_env_vars.json)" \
--argjson new '{"SLACK_WEBHOOK":"${{ secrets.SLACK_WEBHOOK }}"}' \
'$current + $new' > merged_env_vars.json
cat merged_env_vars.json
- name: Update Lambda function configuration
run: |
env_vars=$(cat merged_env_vars.json | jq -r '. | to_entries | map("\(.key)=\(.value | tostring)") | join(",")')
aws lambda update-function-configuration \
--function-name ${{ env.FUNCTION_NAME }} \
--environment "Variables={$env_vars}" \
--region ${{ env.AWS_REGION }}
aws lambda wait function-updated \
--function-name ${{ env.FUNCTION_NAME }} \
--region ${{ env.AWS_REGION }}
- name: Update Lambda function code
run: |
aws lambda update-function-code \
--function-name ${{ env.FUNCTION_NAME }} \
--s3-bucket ${{ env.S3_BUCKET }}-${{ env.AWS_ENVIRONMENT }} \
--s3-key ${{ env.LAMBDA_FUNCTION_ZIP_NAME }} \
--region ${{ env.AWS_REGION }}
|
このGitHubActionsの設定ファイルでは、以下の処理を行っています。
- AWS環境へIAM認証を行う
- Lambda関数のソースコードをzipにアーカイブする
- アーカイブしたzipファイルをS3にアップロードする
- Lambda関数の環境変数を取得する
- Lambda関数の環境変数を追加設定する
- Lambda関数の設定を更新する
- Lambda関数のソースコードを更新する
GitHubActionsを実行する
GitHubActionsのGUIから設定値を入力しワークフローを手動実行します。
本番環境へのデプロイは、v*タグをpushすることで自動デプロイされるように設定する例となっています。