本記事は
ブログ書き初めウィーク
最終日の記事です。
📝
5日目
▶▶ 本記事 📅

こんにちは、柴原です。
最近、実務においてTerraformによる実装をすることになったのですが、本格的な実装は初めの経験だったので進め方が全く分かりませんでした。
そんな中でいろいろ模索したり経験豊富な先輩方からのアドバイスを受けて、「これもっと早く知ってたら実装捗ったなー」というポイントがいくつかあったのでここで共有したいと思います。
前提として、内容はTerraform初心者や新人エンジニア向けになっておりますのでご了承ください。
1. ベストプラクティスを知る
ありがたいことに「初手どうしたらいいか分からない」に対する模範的な答えは、先人たちがまとめてくれています。
「Terraform Best Practices」では、Terraformの基本的な概念からサンプルを含めたコード構造、命名規則などが書かれており、「何もわからない」から「何となく読める」までには押し上げてくれるはずです。
www.terraform-best-practices.com
また、コード構造については現場の運用方針によってさまざまかと思いますが、まずは「中規模パターン」から始めるのが良いと思います。
# 中規模パターンの例
.
├── envs
│ ├── dev
│ │ ├── backend.tf
│ │ ├── local.tf
│ │ ├── main.tf
│ │ ├── provider.tf
│ │ └── version.tf
│ ├── preprod
│ │ ├── backend.tf
│ │ ├── local.tf
│ │ ├── main.tf
│ │ ├── provider.tf
│ │ └── version.tf
│ └── prod
│ ├── backend.tf
│ ├── local.tf
│ ├── main.tf
│ ├── provider.tf
│ └── version.tf
└── modules
└── sample-app
├── main.tf
├── outputs.tf
└── variable.tf
こちらについては、下記の動画で詳しく説明されているのでおすすめです。
2. Sampleを使う
実装を進めていく際、何も参照せず白紙にカタカタとコードを書いていくのはなかなか骨が折れますね(楽しいと感じる方もいるかもしれませんが)。
しかし、そんなことをしなくてもTerraform Registryを見れば、各種AWSサービスのresourceやterraform-aws-modulesのUsageを利用して簡単に書き進めていくことができます。
以下では、例としてAWS Lambdaの実装を見てみましょう。
resourceのExample Usageを使う
AWS Lambdaをresourceとして定義する場合、Example Usageの1つにBasic Function with Node.jsというものがあります。
# IAM role for Lambda execution
data "aws_iam_policy_document" "assume_role" {
statement {
effect = "Allow"
principals {
type = "Service"
identifiers = ["lambda.amazonaws.com"]
}
actions = ["sts:AssumeRole"]
}
}
resource "aws_iam_role" "example" {
name = "lambda_execution_role"
assume_role_policy = data.aws_iam_policy_document.assume_role.json
}
# Package the Lambda function code
data "archive_file" "example" {
type = "zip"
source_file = "${path.module}/lambda/index.js"
output_path = "${path.module}/lambda/function.zip"
}
# Lambda function
resource "aws_lambda_function" "example" {
filename = data.archive_file.example.output_path
function_name = "example_lambda_function"
role = aws_iam_role.example.arn
handler = "index.handler"
code_sha256 = data.archive_file.example.output_base64sha256
runtime = "nodejs20.x"
environment {
variables = {
ENVIRONMENT = "production"
LOG_LEVEL = "info"
}
}
tags = {
Environment = "production"
Application = "example"
}
}
このように、ほぼそのまま使用できるサンプルコードとなっているので用途に近いExample Usageを見つけて改変していくのが良いと思います。
terraform-aws-modulesを使う
「terraform-aws-modules」とは、AWSリソースをベストプラクティスに基づき構築できる公式コミュニティモジュール集です。 terraform-aws-modulesを使用してLambdaを実装する場合、Lambda Function (store package locally)というUsageとして下記があります。
module "lambda_function" {
source = "terraform-aws-modules/lambda/aws"
function_name = "my-lambda1"
description = "My awesome lambda function"
handler = "index.lambda_handler"
runtime = "python3.12"
source_path = "../src/lambda-function1"
tags = {
Name = "my-lambda1"
}
}
resourceでの定義と比較すると、moduleでは信頼ポリシー(AssumeRole)が設定された IAM ロールが自動で作成されるため、ロール定義を自分で書く必要がなくなり、その分コード量を削減できるといったメリットがあります。
3. 最初はmain.tfにモノリスではじめてもいい
中規模レベルのコード構造から作り始めたものの、「どのようにモジュール化するか」「再利用性をどう確保するか」といった運用面を考えすぎてしまい、手が止まってしまうことがありました。
もちろん初期段階から運用を意識した実装は大切ですが、チーム開発である以上、いつまでも悩んで作業を進められないわけにはいきません。
そこで一つの解決策として、まずは main.tf にモノリシックにコードを書き切る方針を取りました。コード構造は後から整理できますし、運用を意識した構造化は、どちらかというと「デザイン」に近い作業だからです。しかしインフラエンジニアとして本当に重要なのは、「品質の高いシステムをしっかりデリバリーすること」です。(私はこの点をあまり意識できていませんでした。)
特に初心者・新人の段階では、まずは手を動かしてデリバリーすることを第一に考えるのが大事です。 まず動くものをつくり、PR を出し、レビューを受けて改善する――このサイクルをしっかり回していきましょう。
さいごに
慣れていないツールでのゼロからの実装って難しいですよね。 本記事が何かの役に立てば幸いです。