DMMデータインフラ部に所属しているyuuaです
terraformで作成しlambdaをデプロイする際にterraformにlambda関数を含めるとchangeがでたり、扱いづらく
悩むときがあるのでその際の手順的な備忘録です
今回のlambdaはlambda containerではありません
初回の手順
1.terraformで基本的なlambdaの事前の情報を作成する(配置先など)
2.lambda関数をzip化しs3バケットに配置する
継続的なデプロイの手順
基本的にgithub actionsなどのCI/CDを使います
1.github actionsでlambda function / lambda layerをバケットに配置
2.github actionsでupdate functionの実行
下準備
lambdaを配置するようのs3 keyなどをterraformで作成します
// bucket作成
resource "aws_s3_bucket" "lambda_bucket" {
bucket = "lambda-bucket"
}
// lambda関数配置するようのkeyを作成
resource "aws_s3_bucket_object" "lambda_function" {
key = "functions/nodejs/"
bucket = aws_s3_bucket.lambda_bucket.id
}
// layerを使う場合はlayer用も
resource "aws_s3_bucket_object" "lambda_layer" {
key = "layers/nodejs/hoge/"
bucket = aws_s3_bucket.lambda_bucket.id
}
これで一旦 terraform apply
を実施する
lambda functionを配置
default のnode.js lambda
exports.handler = async (event) => {
// TODO implement
const response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
return response;
};
上記を zip
化し先ほど作成したs3のkeyに配置します。
配置自体はcliでもconsoleでもciでも配置できれば何でも良いです
lambdaのリソース定義
関数をs3に配置したらterraformでlambda関数を定義します
data "aws_iam_policy_document" "role" {
statement {
actions = ["sts:AssumeRole"]
effect = "Allow"
principals {
identifiers = ["lambda.amazonaws.com"]
type = "Service"
}
}
}
resource "aws_iam_role" "role" {
name = "${var.function_name}-lambda"
assume_role_policy = data.aws_iam_policy_document.role.json
}
// logginなど必要であれば、適宜roleにattachなどしてください
// 関数定義
resource "aws_lambda_function" "function" {
function_name = var.function_name
handler = var.handler
role = aws_iam_role.role.arn
runtime = var.runtime
s3_bucket = bucketを指定
s3_key = 配置したkeyを指定
layers = [layerを使うのであれば指定]
}
terraform apply
を実施する
上記でlambda関数の作成自体は完了です
publishなどのoptionは適宜
継続的なデプロイをするために
基本的に一度作ったら終わりということはあまりないと思うので継続的なdeployをするために定義を作成します
ここではgithub actionsを定義して、Pull Requestから各branchにPR close/mergeされたタイミングでdeployできるようにします
外部からdeployする際は iam
で 必要な権限を付与したuserを作成し、そのユーザのsecretを使います。
ざっと必要になりそうな権限
s3:PutObject
s3:GetObject
s3:DeleteObject
s3:ListBucket
lambda:GetFunction
lambda:UpdateFunctionCode
lambda:UpdateFunctionConfiguration
// layerがいるなら
lambda:GetLayerVersion
lambda:PublishLayerVersion
lambda:ListLayerVersions
lambda:AddLayerVersionPermission
github actions定義
lambda function
下記はセルフホストランナーでの定義ですが通常通りgihtub hosting/セルフホスティングどちらでも問題ないです
name: deploy-function
on:
pull_request:
branches:
- ブランチ名
types: [closed]
jobs:
update-functions:
name: lambda deploy
runs-on: [self-hosted, linux]
if: github.event.pull_request.merged == true // mergeされたら処理継続
steps:
- name: Checkout
uses: actions/checkout@v2
- name: code build
uses: actions/setup-node@v2
with:
node-version: "14"
cache: "npm"
- run: npm install // 必要であれば
- run: npx webpack // buildなどあれば
// aws credentialを設定
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: リージョン
// zipファイルを作成
- name: compression
working-directory: ./dist
run: zip function.zip main.js
- name: lambda update function codes
working-directory: ./dist
run: |
aws lambda update-function-code --function-name function名 --zip-file fileb://function.zip
// 必要であればpublish
コードをzip化し aws cli
の update-function-code
を実行しています
これでPR Close/merge時にdeployが実行されます
lambda layer
layerはnodeの場合 nodejs/node_modules
をzip化する必要があります
ここではlambda functionとは別にlayer用のディレクトリを定義しそこにpackage.jsonをおいています
name: lambda-layer-deploy
on:
pull_request:
branches:
- develop
types: [closed]
paths:
- "layerのpath/**"
jobs:
update-functions:
name: lambda layer deploy
runs-on: [self-hosted, linux]
if: github.event.pull_request.merged == true
steps:
- name: Checkout
uses: actions/checkout@v2
- name: code build
uses: actions/setup-node@v2
with:
node-version: "14"
cache: "npm"
- name: lambda layer
working-directory: ./layer
run: |
mkdir nodejs
cp package*.json nodejs/
npm install --prefix ./nodejs --production
zip -r package.zip nodejs/node_modules
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: リージョン
- name: lambda layer deploy
working-directory: ./layer
run: aws lambda publish-layer-version --layer-name layer名 --zip-file fileb://package.zip --compatible-runtimes nodejs14.x
// 現在のlatestを取得
- name: lambda layer latest version
id: step1
run: |
layer=$(aws lambda list-layer-versions --layer-name layer名 --query 'LayerVersions[0].LayerVersionArn')
echo "::set-output name=layer_ver::$layer"
- name: lambda update configure
run: |
aws lambda update-function-configuration --function-name function名 --layers ${{ steps.step1.outputs.layer_ver }} //複数layerがある場合は ${{ hogehoge }} ${{ foobar }} このような形で続けてかけます
まとめ
terraformでlambdaのリソースを作成しつつ継続的なdeployはCI/CDで行う環境を備忘録的な形でまとめました。
IaCとlambda関数のcodeが分離され、意識することもすくないのでlambda containerを使わない場合は
今のところ一番使いやすいかなと思っています。
データインフラ部では、AWSでのビッグデータ基盤関連の運用を行っており、
様々リソースを活用したプロダクト開発を行っています。
中途採用などもおこなっておりますので、興味のある方は、一度弊社HPなどから
カジュアル面談など、是非ご応募ください。