Terraformで作るサーバレスアプリケーション

どもども、気づけば2024年も残り1ヶ月をきりましたね。子育てを始めてからというもの、時の流れが非常に早く感じます。

さて、今回は2024年を締めくくる最後の記事です。

皆さん、サーバレスアプリケーションは開発していますか?AWSのLambdaやGCPのCloud Functionsなんかを利用して開発されることが多く、開発者がサーバーを管理する必要なくアプリケーションを構築および実行できることが魅力です。

そんなサーバレスアプリケーションに用いられる基盤ですが、たとえばAWS Lambdaを用いる場合はAWS SAMやAWS CDKを用いた開発が多いように見受けられます。特にSAMなんかはサーバレスアプリケーション開発に特化した仕様になってますから人気ですね…。

しかし、そんな中今回あえてPushしてみるのは terraformを利用したサーバレスアプリケーション開発です!実はterraformでのサーバレスアプリケーションの開発と管理もSAM等に比べひけを取らないほどやりやすかったので、今後の選択肢の一つとして是非とも押さえておいていただきたいなと思います。

構成

まずは今回のディレクトリ構成から!あくまで一例で、Lambdaをデプロイするための最小構成です。

.
├── lambda
│   ├── bootstrap
│   ├── go.mod
│   ├── go.sum
│   └── main.go
└── terraform
    ├── backend.tf
    ├── lambda.tf
    ├── iam.tf
    ├── main.tf
    └── provider.tf

まずlambdaディレクトリとterraformディレクトリの2つに分けています。見ての通りでアプリケーションの定義と基盤の定義に分かれているだけです。

TerraformでデプロイするLambda

続いてTerraformの定義をみていきましょう。Lambdaディレクトリの内容はあえて触れる必要はないと思いますので割愛します。今回はGoを利用しておりますので詳細を確認したい場合は公式ドキュメントを参照ください。

またterraformを利用する上での初期設定(initなど)は完了している想定で進めます。terraformに馴染みがないという方は公式チュートリアルで事前にキャッチアップしていただければと思います。

さて、今回の記事で目玉となるのがterraformによるLambda定義かと思います。具体的には以下のようになります。

# ソースコードの取得
data "archive_file" "test_terraform" {
  type        = "zip"
  source_dir  = "../lambda"
  output_path = "test-function.zip"
}

# AWSへ作るlambda function
resource "aws_lambda_function" "test_function" {
  function_name    = "test-function"
  filename         = data.archive_file.test_terraform.output_path
  source_code_hash = data.archive_file.test_terraform.output_base64sha256
  runtime          = "provided.al2"
  role             = aws_iam_role.lambda_role.arn
  handler          = "main"

  environment {
    variables = {
      EXAMPLE_ENV = "example"
    }
  }
}

LambdaのログをCloudwatch logsに送るためのIAM RoleとPolicyも作成しておきます。

resource "aws_iam_role" "lambda_role" {
  name = "test-function-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "lambda.amazonaws.com"
        }
      }
    ]
  })
}

# IAM Policy for Lambda Function to create logs and get costs from Cost Explorer
resource "aws_iam_role_policy" "lambda_policy" {
  name = "test-function-policy"
  role = aws_iam_role.lambda_role.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = [
          "logs:CreateLogGroup",
          "logs:CreateLogStream",
          "logs:PutLogEvents"
        ]
        Resource = "*"
      }
    ]
  })
}

こうして定義してみるととても直感的でわかりやすいですね!

ここで感のいい方は気づいたと思います。あれ、デプロイするためのzipファイルがないじゃないかと。SAMやCDKの場合、わざわざzipファイルなんて意識しなくてもよかったが、terraformは手動で作らなければならないのかと。

ご安心ください、確かにterraformでLambdaをデプロイする場合はzipファイルが必要です。ですが、terraform planを実行した際に、lambda.tfのdataで定義した情報をもとにzipファイルを自動で作成してくれます。

つまり、開発者がわざわざ意識する必要はないのです!

.
├── lambda
│   ├── bootstrap
│   ├── go.mod
│   ├── go.sum
│   └── main.go
└── terraform
    ├── backend.tf
    ├── lambda.tf
    ├── iam.tf
    ├── main.tf
    ├── provider.tf
    └── test-function.zip # 自動で作成される

つまり開発者のサイクルとしては、コード修正->再コンパイル->terraform planでzipファイル置き換えとなるので使用感としては他のIaCツールとそんなに遜色ないかなと思います。

あとはterraform applyすればLambdaがデプロイされていることを確認できますので、是非実際にやってみてください!

まとめ

AWS SAMや他のツールでこれまで作成してきたサーバレスアプリケーションやその開発手順をterraformに移行するのはオーバーコストと思われるかもしれません。

しかし、ご覧いただいたように定義や使用感自体は直感的ですし、他のアーキテクチャをterraformで作成していてサーバレスだけまた別のIaCで…というようなチームにとっては技術の統一によるキャッチアップの簡易化を目指すことだってできるかもしれません。

terraformはGCPやDatadogなど他のサービスのproviderも豊富に揃ってますし、Cloud Formationを介すよりは差分が見やすいなどのメリットも多く統一するかちは十分にあるIaCツールだと個人的には思います。

ただ、AWS SAMやCDKは公式に開発されているツールですし、今後シナジーが高い機能が開発されていくのはおそらくこれらのツールでしょう。

組織に合わせた戦略の選択肢の一つとして本記事が参考になれば幸いです。

ここまで読んでいただきありがとうございました!来年もよろしくおねがいします!

AWS,Terraform

Posted by CY