はじめに
生成AIへの注目が高まり、社内でも生成AIが業務のサポートに使用されています。技術的な不明点があれば生成AIに聞くと、回答が生成されます。この記事ではGoogleの生成AIであるGeminiに、Terraformのベストプラクティス10箇条を聞いてみます。そして、Geminiから出力された内容の詳細を前編、後編で5箇条ずつに分けて解説します。
Terraformとは、Infrastructure as Code(IaC)ツールです。インフラストラクチャの構成と管理をコードとして記述し、自動化することができます。
ベストプラクティス10箇条(前編)
1.モジュール化
①モジュール化の利点
②モジュールの作成
- 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 |
variable "project_id" { type = string description = "The ID of the Google Cloud project." } variable "region" { type = string description = "The region to deploy resources to." default = "us-central1" } variable "zone" { type = string description = "The zone to deploy resources to." default = "us-central1-f" } variable "machine_type" { type = string description = "The machine type for the Compute Engine instance." default = "e2-medium" } variable "source_image" { type = string description = "The source image for the Compute Engine instance." default = "debian-cloud/debian-9" } variable "network_name" { type = string description = "Name of the VPC network" default = "default" } variable "subnet_name" { type = string description = "Name of the subnet" default = "default" } |
- outputs.tf: モジュールから出力される値を定義
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
output "instance_name" { value = google_compute_instance.default.name description = "Name of the created instance" } output "instance_zone" { value = google_compute_instance.default.zone description = "Zone of the created instance" } output "instance_ip" { value = google_compute_instance.default.network_interface.0.access_config.0.nat_ip description = "Public IP address of the created instance" } output "instance_self_link" { value = google_compute_instance.default.self_link description = "Self-link of the created instance" } |
- main.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 49 50 51 52 |
# Google Cloud プロバイダの構成 terraform { required_providers { google = { source = "hashicorp/google" version = "~> 4.0" } } } # 変数の定義 (variables.tfで定義) # variable "project_id" {} # variable "region" {} # variable "zone" {} # variable "machine_type" {} # variable "source_image" {} # variable "network_name" {} # variable "subnet_name" {} # Compute Engine インスタンスの作成 resource "google_compute_instance" "default" { project = var.project_id name = "terraform-instance" machine_type = var.machine_type zone = var.zone boot_disk { initialize_params { image = var.source_image } } network_interface { subnetwork = "projects/${var.project_id}/regions/${var.region}/subnetworks/${var.subnet_name}" } tags = ["http-server"] } # ファイアウォールルールの作成 resource "google_compute_firewall" "allow_http" { project = var.project_id name = "allow-http" network = var.network_name source_ranges = ["0.0.0.0/0"] allowed { IP_protocol = "tcp" ports = ["80"] } target_tags = ["http-server"] } |
2.適切な命名規則
①基本原則
②詳細な推奨事項
効果的なリソース命名規則は、リソースのタイプ、環境、役割といった要素を明確に示すことが重要です。例えば、「dev_web_server_instance_01」のように、開発環境(dev)にあるWebサーバーインスタンスの1番目であることを示す名前は、一目でリソースの特性を理解できます。リソースタイプを名前に含めることで、それがデータベースなのか、サーバーなのか、すぐに判別できます。
環境を含めることで、開発環境、ステージング環境、本番環境など、リソースがどこに存在するのかが明確になります。また、役割を含めることでそのリソースがWebサーバーなのか、データベースサーバーなのか、具体的な機能を理解しやすくなります。
さらに、同じ種類のリソースが複数ある場合は、番号を付けることで個々のリソースを区別できます。また、略語を避け、完全な単語を使用することで、名前の意図がより明確になります。
このように、リソース名に情報を詰め込むことで、運用管理の効率化、エラーの削減、チーム内でのコミュニケーションの円滑化などが期待できます。
3.変数の活用
①変数の目的を明確にする
変数を活用することは、コードの品質と保守性を向上させる上で非常に有効な手段です。まず、同じ値を複数箇所で使用する場合にその値を変数として定義することで、コードの重複を避けることができます。値を変更する必要が生じた場合でも、変数の定義箇所を一箇所修正するだけで、全ての使用箇所に反映させることができます。これにより、修正漏れのリスクを減らし、効率的なコード管理が可能になります。
また、開発環境、ステージング環境、本番環境といった異なる環境ごとに異なる値を設定する場合にも、変数が役立ちます。環境ごとに異なる値を格納した変数を用意しておけば、環境が変わるたびにコードを書き換える必要はありません。さらに、APIキーやパスワードなどの機密情報を変数として定義し、別途管理することで、セキュリティを強化することができます。機密情報をコードに直接記述するリスクを軽減し、より安全なシステム運用に繋がります。このように、変数を適切に活用することで、コードの再利用性、柔軟性、セキュリティを向上させることができます。
②変数の型とデフォルト値
Terraformの変数を効果的に使用するには、いくつかのポイントがあります。まず、変数の値に合った型を指定することが重要です。string、number、bool、list、mapなど、適切な型を指定することで、コードの可読性と信頼性を高めます。また、可能な限りデフォルト値を設定することで、変数を省略できる場合を明確にし、モジュールの使い勝手を向上させます。
次に、変数のスコープも重要な要素です。ローカル値、モジュールレベルなど、変数のスコープを適切に選択することで、意図しない値の変更を防ぎ、コードの安全性を確保します。
また、モジュールを再利用しやすくするためには、入力変数を効果的に活用します。入力変数を使用することで、モジュールを呼び出す際に必要な値を外部から渡すことができ、モジュールの柔軟性を高めることができます。これらのポイントを意識することで、Terraformの変数をより効果的に活用し、効率的で保守性の高いコードを作成することができます。
③変数のドキュメント化
Terraformの変数を効果的に管理し利用を促進するためには、適切なドキュメントが不可欠です。まず、variableブロック内にdescriptionを記述することで、変数の用途を明確にすることができます。これにより、コードを読む人が変数の役割を理解しやすくなり適切な値を設定することができます。
さらに、プロジェクトのREADMEファイルに変数の使い方を記述することも重要です。READMEに具体的な使用例や設定時の注意点などを記載することで、コードを読む人だけでなく、実際にモジュールを利用する人にとっても有益な情報を提供することができます。これらのドキュメントを整備することで、Terraformコードの可読性、保守性、再利用性を高めることができます。
④変数の管理
Terraformの変数を安全かつ効率的に管理するためには、いくつかのベストプラクティスがあります。まず、変数の定義をバージョン管理システム(Gitなど)で管理することで、変更履歴を追跡し、問題発生時の切り戻しを容易にすることができます。
また、変数の値をコードから分離するために、.tfvarsファイルに格納します。これにより、設定値とコードを分けて管理することができ、可読性や保守性が向上します。さらに、APIキーやパスワードなどの機密情報は、コードに含めるべきではありません。これらの値は環境変数として設定し、Terraformのコードから参照することで、セキュリティを確保します。
4.出力値の定義
①出力値の目的を明確にする
Terraformの出力値は、モジュールの連携、デプロイ結果の確認、外部システムとの連携など、様々な場面で重要な役割を果たします。例えば、複数のモジュールを組み合わせてインフラを構築する場合、あるモジュールで作成したリソースの情報を別のモジュールで利用することがあります。この時、出力値として情報を公開することで、モジュール間の連携をスムーズに行うことができます。
また、Terraform apply実行後に出力値を表示することで、作成したリソースのID、IPアドレス、URLなどの重要な情報を容易に確認することができます。これにより、デプロイ結果の確認作業を効率化することができます。
さらに、Terraformで作成したリソースの情報を外部システムに渡す必要がある場合にも、出力値が役立ちます。例えば、CI/CDツールや監視ツールなど、外部のシステムと連携する際に、出力値を活用することで、スムーズな情報伝達を実現できます。
このように、Terraformの出力値は、モジュール間の連携、デプロイ結果の確認、外部システムとの連携など様々な場面で重要な役割を果たし、Terraformの利用を促進する上で欠かせない機能です。
②出力値の命名規則
Terraformの出力値にも、適切な命名規則を適用することで、コードの可読性と保守性を向上させることができます。出力値の名前には「2.適切な命名規則」でも記述した通り、スネークケースを採用し、全て小文字で単語をアンダースコア(_)で区切ります。例えば、instance_ipやvpc_idのように、出力値の内容が明確に伝わる名前にすることで、コードを読む人がその値の役割を容易に理解することができます。
プロジェクト全体で同じ命名規則を適用することで、一貫性を保ち、混乱を避けることが重要です。このように、出力値の命名規則を定めることで、Terraformコードの可読性、保守性、そしてチーム内での情報共有を促進することができます。
③出力値の型
Terraformの出力値を定義する際には、出力値の型を適切に指定することが重要です。string、number、bool、list、mapなど、値に合った型を指定することで、出力値を扱う際のエラーを防ぎ、コードの信頼性を高めることができます。
また、必要に応じてリストやマップなどの複雑なデータ構造を出力値として定義することも可能です。これにより、複数の値をまとめて出力したり、より構造化された情報を提供したりすることができます。
④出力値のドキュメント化
Terraformの出力値を効果的に活用するためには、適切なドキュメントが重要です。outputブロックにdescriptionを記述することで、出力値の内容を明確にすることができます。これにより、コードを読む人が出力値の役割を理解しやすくなり、その値を適切に利用することができます。
また、プロジェクトのREADMEファイルに出力値の使い方を記述することも重要です。READMEに具体的な使用例や注意点などを記載することで、コードを読む人だけでなく、実際にモジュールを利用する人にとっても有益な情報を提供することができます。これらのドキュメントを整備することで、Terraformコードの可読性、保守性、再利用性を高めることができます。
⑤出力値の属性
Terraformの出力値を扱う上で、セキュリティと依存関係の管理は重要な考慮事項です。パスワードなどの機密情報を出力値として定義する場合は、sensitive = trueを指定することで、値がコンソールに表示されないようにします。
これにより、意図しない情報漏洩のリスクを軽減することができます。また、出力値が依存するリソースがある場合は、depends_onを指定することで、リソースが作成される前に出力値が参照されるのを防ぎます。予期せぬエラーを回避し、安定したインフラ構築を実現することができます。これらの設定を適切に行うことで、Terraformの出力値を安全かつ確実に管理することができます。
⑥出力値の利用
5.依存関係の明示
前編の最後の5つ目は、依存関係の明示です。Terraformは、リソース間の依存関係を自動的に検出して適切な順序で作成・更新しますが、複雑なインフラストラクチャでは、Terraformが自動的に検出できない依存関係が発生することがあります。このような場合に、depends_onメタ引数を使用して依存関係を明示することで、リソースが意図した順序で作成・更新されるように制御し、エラーや予期せぬ動作を防ぐことができます。
①depends_on のベストプラクティス
Terraformのdepends_onは、リソース間の依存関係を明示的に指定するための機能ですが、その使用には注意が必要です。Terraformは多くの依存関係を自動的に処理できるため、depends_onは本当に必要な場合にのみ使用します。過剰な使用はコードの可読性を低下させ、Terraformの依存関係グラフの解析を複雑にする可能性があります。可能な限りリソース属性の参照など、暗黙的な依存関係を使用します。暗黙的な依存関係は、Terraformが依存関係を理解し、より効率的に処理するのに役立ちます。
depends_onを使用するときに注意すべき点として、循環依存関係があります。循環依存関係は、Terraformがリソースを作成・更新できなくなる原因となるため、絶対に避ける必要があります。
モジュール間の依存関係を管理するためにdepends_onを使用することもできます。あるモジュールが別のモジュールで作成されたリソースに依存している場合、depends_onを使用して依存関係を明示します。また、リソースのライフサイクル(create_before_destroyやprevent_destroyなど)設定と組み合わせて使用することで、リソースの削除・置換時の依存関係を制御できます。depends_onを使用する場合は、なぜ明示的な依存関係が必要なのかをコメントで説明することでコードの可読性を向上させることが重要です。
②depends_onを使用する例
例:VPCとサブネット: サブネットはVPCに依存するため、サブネットリソースでdepends_onを使用してVPCリソースへの依存関係を明示します。
1 2 3 4 5 6 7 8 |
resource "google_compute_network" "main" { # ... } resource "google_compute_subnetwork" "main" { # ... depends_on = [google_compute_network.main] } |
最後に
執筆者プロフィール

- tdi クラウドビジネス推進室
-
AWS、Azure、GCPの全てを極めることを目標に日々奮闘しております。
新しい技術が好きで、常に情報収集しています。皆様に有益な情報を届けられるようにしていきたいです。
この執筆者の最新記事
Pick UP!2025.03.12Geminiに聞くTerraformのベストプラクティス10箇条(前編)
Pick UP!2024.05.13Google CloudでインフラCI/CDを実現する
Pick UP!2023.04.27クラウドの構築をInfrastructure as Code(IaC)で実現する