Terraformを使って.NETのLambda関数をAWSにデプロイする
2022-09-20
azblob://2022/11/11/eyecatch/2022-09-16-terraform-for-dotnet-lambda-000.jpg

こんにちは。二宮です。
伝説的名作フリーゲーム「Ruina 廃都の物語」のリメイク版がSteamで発売されるらしいです。楽しみですね!

さて、今回は、.NETで書いたLambda関数を1度のterraform applyだけでデプロイする方法を書いていきます。

事前準備

Terraformを使ってLambda関数をデプロイするためには、ローカルでzipファイルを作成するか、S3にアップロードする必要がありますが、今回はローカルでzipファイルを作成する方法でデプロイしていきます。
ソースのzipファイル化は、.NET ToolのAmazon.Lambda.Toolsを使用すると簡単です。
まずは、次のコマンドでAmazon.Lambda.Toolsをインストールします。

dotnet tool install -g Amazon.Lambda.Tools

Amazon.Lambda.Toolsがインストールできたら、次のコマンドでソースをzip化します。

dotnet lambda package

が、今回は一度のterraform applyでLambda関数をデプロイしたいので、このコマンドもTerraformから実行します。

Terraform作成

次のようなTerraformファイルを作成します。

provider "aws" {
  region     = "ap-northeast-1"
  access_key = <アクセスキー>
  secret_key = <シークレットキー>
}

resource "null_resource" "lambda_build" {
  triggers = {
    always_run = timestamp()
  }
  provisioner "local-exec" {
    command = "dotnet lambda package --project-location <Functionのフォルダのpath> --output-package <zipファイルの出力先/filename.zip>"
  }
}

resource "aws_lambda_function" "sample_function" {
  filename      = <zipファイルの出力先/filename.zip>
  function_name = <Lambda関数の名前>
  role          = aws_iam_role.lambda_role.arn
  handler       = "<関数名>::<関数名>.<関数ファイル名>::<ハンドラー名>"
  runtime       = "dotnetcore3.1"
  environment {
    variables = {
      Sample_Message = "Hello World"
    }
  }
  depends_on = [
    null_resource.lambda_build,
    aws_iam_role_policy_attachment.basic_policy_attachment
  ]
}

data "aws_iam_policy_document" "lambda_role_policy_document" {
  version = "2012-10-17"
  statement {
    actions = [
      "sts:AssumeRole"
    ]
    effect = "Allow"
    principals {
      type        = "Service"
      identifiers = ["lambda.amazonaws.com"]
    }
  }
}

resource "aws_iam_role" "function_role" {
  name               = "function_role"
  assume_role_policy = data.aws_iam_policy_document.lambda_role_policy_document.json
}

data "aws_iam_policy" "basic_role" {
  arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}

resource "aws_iam_role_policy_attachment" "basic_policy_attachment" {
  role       = aws_iam_role.function_role.name
  policy_arn = data.aws_iam_policy.basic_role.arn
}

providerブロックは、AWSのリージョン、アクセスキー、シークレットキーを入れることでTerraformとAWSを接続するブロックです。

provider "aws" {
  region     = "ap-northeast-1"
  access_key = <アクセスキー>
  secret_key = <シークレットキー>
}

null_resourceでは、コマンドを実行してLambda関数をビルド・zip化を行っています。

resource "null_resource" "lambda_build" {
  triggers = {
    always_run = timestamp()
  }
  provisioner "local-exec" {
    command = "dotnet lambda package --project-location <Functionのフォルダのpath> --output-package <zipファイルの出力先/filename.zip>"
  }
}

aws_lambda_functionでは、Lambdaリソースを定義しています。
depends_onでnull_resourceとaws_iam_policy_attachmentが完了を待っています。

resource "aws_lambda_function" "sample_function" {
  filename      = <zipファイルの出力先/filename.zip>
  function_name = <Lambda関数の名前>
  role          = aws_iam_role.lambda_role.arn
  handler       = "<関数名>::<関数名>.<関数ファイル名>::<ハンドラー名>"
  runtime       = "dotnetcore3.1"
  environment {
    variables = {
      Sample_Message = "Hello World"
    }
  }
  depends_on = [
    null_resource.lambda_build,
    aws_iam_role_policy_attachment.basic_policy_attachment
  ]
}

以降のブロックではIAMロールを定義しています。
function_roleというロールを作成し、AWSにデフォルトで存在しているAWSLambdaBasicExecutionRoleというポリシーをアタッチしています。

data "aws_iam_policy_document" "lambda_role_policy_document" {
  version = "2012-10-17"
  statement {
    actions = [
      "sts:AssumeRole"
    ]
    effect = "Allow"
    principals {
      type        = "Service"
      identifiers = ["lambda.amazonaws.com"]
    }
  }
}

resource "aws_iam_role" "function_role" {
  name               = "function_role"
  assume_role_policy = data.aws_iam_policy_document.lambda_role_policy_document.json
}

data "aws_iam_policy" "basic_role" {
  arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}

resource "aws_iam_role_policy_attachment" "basic_policy_attachment" {
  role       = aws_iam_role.function_role.name
  policy_arn = data.aws_iam_policy.basic_role.arn
}

terraformを実行

コードができたのでTerrafromを実行します。
次のコマンドでワークスペースを初期化します。

terraform init

ワークスペースの初期化が終わったら次のコマンドでTerraformによる実行計画を参照します。

terraform plan

実行計画が問題なければ、次のコマンドでリソースを構築します。

terraform apply

次のメッセージが表示され、作成したroleがアタッチされたLambdaが作成されます。

Apply complete! Resources: 4 added, 0 changed, 0 destroyed.

まとめ

今回は、Terraformを使った.NETのLambdaのデプロイ方法を紹介しました。
この方法ならbuildからzip化、デプロイまでを一度のterraform applyで一気に行えるので、手間を省くことができます。
TerraformでAWSのリソースを管理する際はぜひ活用して下さい。