Terraform 変数とは?初心者にもわかりやすく解説
Terraformで効率的なインフラ構築を実現するために、欠かせない機能が「変数(Variable)」です。この記事では、Terraform初心者の方にも分かりやすく、変数の基本から実践的な使い方まで解説していきます。
変数定義の基本的な書き方と型の指定方法
Terraform変数は、インフラのコード化(IaC)をより柔軟かつ再利用可能にする重要な要素です。基本的な変数の定義は以下のような形式で行います:
# 基本的な変数定義
variable "instance_type" {
type = string
default = "t2.micro"
description = "EC2インスタンスのタイプ"
}
# 数値型の変数
variable "instance_count" {
type = number
default = 1
description = "起動するインスタンスの数"
}
# リスト型の変数
variable "availability_zones" {
type = list(string)
default = ["ap-northeast-1a", "ap-northeast-1c"]
description = "使用するAZのリスト"
}
# マップ型の変数
variable "instance_tags" {
type = map(string)
default = {
Environment = "development"
Project = "terraform-demo"
}
description = "インスタンスに付与するタグ"
}
Terraformでサポートされている主な変数の型は以下の通りです:
| 型名 | 説明 | 使用例 |
|---|---|---|
| string | 文字列型 | インスタンスタイプ、リージョン名など |
| number | 数値型 | ポート番号、インスタンス数など |
| bool | 真偽値型 | 機能のON/OFF制御など |
| list | リスト型 | サブネットIDのリスト、AZのリストなど |
| map | マップ型 | タグ、環境変数の設定など |
| object | オブジェクト型 | 複合的な設定値など |
なぜTerraformで変数を使う必要があるのか
Terraform変数を使用する主なメリットは以下の4つです:
- コードの再利用性の向上
- 同じコードを異なる環境(開発・検証・本番)で使い回せる
- 環境ごとの設定値だけを変更することで柔軟な対応が可能
- 保守性の向上
- 設定値を一箇所で管理できる
- 変更が必要な場合、変数の値だけを修正すれば良い
- セキュリティの向上
- 機密情報を変数として外部管理できる
- GitHubなどでのソース管理時にセキュアな運用が可能
- チーム開発の効率化
- 設定値の標準化が容易
- レビューやデバッグが効率化される
以下は、変数を使用することで得られる具体的なメリットを示す例です:
# 変数を使用しない場合(ハードコーディング)
resource "aws_instance" "example" {
ami = "ami-0123456789abcdef0"
instance_type = "t2.micro"
tags = {
Name = "production-server"
}
}
# 変数を使用する場合
resource "aws_instance" "example" {
ami = var.ami_id
instance_type = var.instance_type
tags = var.instance_tags
}
この例からわかるように、変数を使用することで:
- AMI IDやインスタンスタイプを環境に応じて柔軟に変更可能
- タグなどの設定を一元管理できる
- コードの可読性と保守性が向上する
変数を適切に使用することで、Terraformコードの品質と運用効率を大きく向上させることができます。次のセクションでは、これらの変数を実際にどのように使用していくのか、より詳細に解説していきます。
Terraform 変数の基本的な使い方を徹底解説
このセクションでは、Terraform変数の実践的な使い方について、具体的なコード例とともに解説していきます。
変数の定義と参照の具体的な方法
Terraformでの変数の定義と参照には、いくつかの方法があります。以下に主要な方法を説明します。
- 変数の定義場所
# variables.tf - 変数定義ファイル
variable "vpc_cidr" {
type = string
default = "10.0.0.0/16"
description = "VPCのCIDRブロック"
# 検証ルールの追加
validation {
condition = can(cidrhost(var.vpc_cidr, 0))
error_message = "無効なCIDR形式です。"
}
}
# その他の変数定義
variable "environment" {
type = string
default = "development"
}
- 変数の参照方法
# main.tf - メインの設定ファイル
resource "aws_vpc" "main" {
cidr_block = var.vpc_cidr # 変数を参照
tags = {
Name = "main-vpc"
Environment = var.environment
}
}
確実な値の設定と上書きのテクニック
Terraformでは、変数の値を複数の方法で設定・上書きすることができます。優先順位は以下の通りです(上が優先):
- コマンドライン引数(-var オプション)
- 変数定義ファイル(-var-file オプション)
- terraform.tfvars ファイル
- *.auto.tfvars ファイル
- 環境変数(TF_VAR_)
- デフォルト値
具体的な使用例を見ていきましょう:
# コマンドライン引数での指定 terraform apply -var="environment=production" # 変数ファイルの使用 terraform apply -var-file="prod.tfvars"
# prod.tfvars の内容 vpc_cidr = "172.16.0.0/16" environment = "production" instance_type = "t3.medium"
環境変数としての利用方法
環境変数を使用した変数の設定は、特に機密情報の扱いに適しています:
# 環境変数での設定 export TF_VAR_db_password="secure_password123" export TF_VAR_aws_access_key="AKIAXXXXXXXXXXXXXXXX"
# variables.tf での定義
variable "db_password" {
type = string
sensitive = true # 機密情報としてマーク
description = "データベースのパスワード"
}
# main.tf での使用
resource "aws_db_instance" "example" {
identifier = "example-db"
engine = "mysql"
instance_class = "db.t3.micro"
password = var.db_password # 環境変数から取得
}
実践的なTips:
| 使用シーン | 推奨される方法 | 理由 |
|---|---|---|
| 開発環境の設定 | terraform.tfvars | チーム内で共有可能 |
| 本番環境の設定 | -var-file オプション | 環境別に管理可能 |
| 機密情報 | 環境変数 | セキュアに管理可能 |
| CI/CD | -var オプション | 自動化に適している |
変数の使用におけるベストプラクティス:
- 明確な命名規則の採用
# 良い例
variable "vpc_cidr_block" { ... }
# 避けるべき例
variable "vcb" { ... }
- 適切なデフォルト値の設定
variable "instance_count" {
type = number
default = 1 # 安全なデフォルト値
}
- バリデーションルールの活用
variable "environment" {
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "環境は dev, staging, prod のいずれかである必要があります。"
}
}
これらの基本的な使い方を押さえることで、より効率的なTerraformの運用が可能になります。次のセクションでは、より実践的な変数管理のテクニックについて解説していきます。
実践的な変数管理テクニック
実務でTerraformを使用する場合、適切な変数管理は保守性とセキュリティの両面で非常に重要です。ここでは、実践的な変数管理のテクニックについて解説します。
変数ファイルの分割と管理方法
大規模なインフラ構築では、変数の数が増加し管理が複雑になりがちです。効率的な管理のために、以下のようなファイル構成を推奨します:
project/
├── main.tf
├── variables.tf # 変数の定義
├── terraform.tfvars # デフォルト値
├── environments/
│ ├── dev.tfvars # 開発環境用
│ ├── staging.tfvars # ステージング環境用
│ └── prod.tfvars # 本番環境用
└── modules/
└── vpc/
├── main.tf
└── variables.tf
変数ファイルの分割例:
# variables.tf - 変数の定義
variable "vpc_config" {
type = object({
cidr_block = string
name = string
subnets = map(object({
cidr_block = string
zone = string
}))
})
description = "VPCの設定"
}
# terraform.tfvars - デフォルト値
vpc_config = {
cidr_block = "10.0.0.0/16"
name = "default-vpc"
subnets = {
public-1 = {
cidr_block = "10.0.1.0/24"
zone = "ap-northeast-1a"
}
public-2 = {
cidr_block = "10.0.2.0/24"
zone = "ap-northeast-1c"
}
}
}
環境ごとの設定値の切り替え方
環境ごとの設定を効率的に管理するためのテクニックを紹介します:
- 環境別の変数ファイル作成
# environments/dev.tfvars
vpc_config = {
cidr_block = "10.0.0.0/16"
name = "dev-vpc"
subnets = {
public-1 = {
cidr_block = "10.0.1.0/24"
zone = "ap-northeast-1a"
}
}
}
# environments/prod.tfvars
vpc_config = {
cidr_block = "172.16.0.0/16"
name = "prod-vpc"
subnets = {
public-1 = {
cidr_block = "172.16.1.0/24"
zone = "ap-northeast-1a"
}
public-2 = {
cidr_block = "172.16.2.0/24"
zone = "ap-northeast-1c"
}
}
}
- 環境の切り替え方法
# 開発環境へのデプロイ terraform plan -var-file="environments/dev.tfvars" terraform apply -var-file="environments/dev.tfvars" # 本番環境へのデプロイ terraform plan -var-file="environments/prod.tfvars" terraform apply -var-file="environments/prod.tfvars"
機密情報の安全な扱い方
機密情報の管理は特に注意が必要です。以下に安全な管理方法を示します:
- AWS Systems Manager Parameter Storeの利用
# データソースとして機密情報を取得
data "aws_ssm_parameter" "db_password" {
name = "/app/database/password"
}
# 変数定義
variable "db_password" {
type = string
sensitive = true # 機密情報としてマーク
description = "データベースのパスワード"
}
# リソースでの使用
resource "aws_db_instance" "main" {
password = data.aws_ssm_parameter.db_password.value
}
- 環境変数の使用
#!/bin/bash # 環境変数設定スクリプト # 機密情報の設定 export TF_VAR_db_password=$(aws ssm get-parameter --name "/app/database/password" --with-decryption --query Parameter.Value --output text) export TF_VAR_api_key=$(aws ssm get-parameter --name "/app/api/key" --with-decryption --query Parameter.Value --output text) # Terraform実行 terraform apply -var-file="environments/prod.tfvars"
変数管理におけるセキュリティチェックリスト:
| チェック項目 | 説明 | 推奨される対応 |
|---|---|---|
| 機密情報の分離 | パスワードやAPIキーの管理 | Parameter StoreやSecrets Managerの使用 |
| アクセス制御 | 変数ファイルへのアクセス制限 | GitのアクセスFu制御とgitignoreの適切な設定 |
| 暗号化 | 機密情報の暗号化 | KMSやVault使用 |
| 監査ログ | 変数アクセスの記録 | CloudTrailとの連携 |
これらのテクニックを適切に組み合わせることで、安全で効率的な変数管理が実現できます。次のセクションでは、さらに具体的なベストプラクティスについて解説していきます。
7つのTerraform Variableベストプラクティス
実務でTerraformを使用する際、変数管理の品質がコードの保守性と再利用性を大きく左右します。ここでは、実践で役立つ7つのベストプラクティスを詳しく解説します。
命名規則の統一による可読性の向上
変数名の一貫性は、コードの可読性と保守性を高める重要な要素です。
# 推奨される命名規則
variable "project_name" {
type = string
description = "プロジェクト名"
}
variable "environment_type" {
type = string
description = "環境種別(dev/staging/prod)"
}
variable "vpc_cidr_block" {
type = string
description = "VPCのCIDRブロック"
}
# 避けるべき命名例
variable "pn" { # 略語は避ける
type = string
}
variable "VpcCidrBlock" { # キャメルケースは避ける
type = string
}
命名規則のガイドライン:
| カテゴリ | 推奨形式 | 例 |
|---|---|---|
| リソース識別子 | resource_name | instance_type, subnet_id |
| 環境変数 | environment_* | environment_name, environment_type |
| タグ | tag_* | tag_project, tag_owner |
| 設定値 | config_* | config_version, config_region |
型保留による予期せぬエラーの防止
型定義を明確にすることで、実行時エラーを事前に防ぐことができます:
# 基本的な型定義
variable "instance_count" {
type = number
default = 1
description = "起動するインスタンス数"
validation {
condition = var.instance_count > 0
error_message = "インスタンス数は1以上である必要があります。"
}
}
# 複合的な型定義
variable "subnet_config" {
type = object({
cidr_blocks = list(string)
zones = list(string)
tags = map(string)
})
description = "サブネットの設定"
validation {
condition = length(var.subnet_config.cidr_blocks) == length(var.subnet_config.zones)
error_message = "CIDRブロックとアベイラビリティゾーンの数が一致する必要があります。"
}
}
バリデーションによる値の検証
入力値の検証は、設定ミスを早期に発見するために重要です:
variable "environment" {
type = string
description = "デプロイ環境"
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "環境は「dev」「staging」「prod」のいずれかである必要があります。"
}
}
variable "instance_type" {
type = string
description = "EC2インスタンスタイプ"
validation {
condition = can(regex("^t[23].micro|t[23].small|t[23].medium$", var.instance_type))
error_message = "指定されたインスタンスタイプは許可されていません。"
}
}
変数のグループ化とモジュール化
関連する変数をグループ化し、モジュールとして管理することで、コードの整理と再利用が容易になります:
# modules/vpc/variables.tf
variable "vpc_settings" {
type = object({
cidr_block = string
name = string
enable_dns = bool
tags = map(string)
})
description = "VPCの基本設定"
}
variable "subnet_settings" {
type = list(object({
cidr_block = string
zone = string
public = bool
}))
description = "サブネットの設定リスト"
}
# 使用例
module "vpc" {
source = "./modules/vpc"
vpc_settings = {
cidr_block = "10.0.0.0/16"
name = "main-vpc"
enable_dns = true
tags = {
Environment = "production"
Managed_by = "terraform"
}
}
subnet_settings = [
{
cidr_block = "10.0.1.0/24"
zone = "ap-northeast-1a"
public = true
},
{
cidr_block = "10.0.2.0/24"
zone = "ap-northeast-1c"
public = false
}
]
}
環境別の変数ファイル管理
環境ごとの設定を明確に分離することで、設定ミスを防ぎます:
# environments/base.tfvars region = "ap-northeast-1" project_name = "example-project" # environments/dev.tfvars environment = "dev" instance_type = "t2.micro" enable_monitoring = false # environments/prod.tfvars environment = "prod" instance_type = "t3.medium" enable_monitoring = true backup_retention_days = 30
セキュリティを考慮した機密情報の扱い
機密情報は適切に保護する必要があります:
# 機密情報の定義
variable "database_password" {
type = string
sensitive = true
description = "データベースのパスワード"
}
# AWS Secrets Managerの利用
data "aws_secretsmanager_secret_version" "db_password" {
secret_id = "db-password"
}
# 変数での使用
resource "aws_db_instance" "main" {
password = jsondecode(data.aws_secretsmanager_secret_version.db_password.secret_string)["password"]
}
ドキュメント作成による保守性の向上
適切なドキュメント化は、チーム開発と長期的な保守性を支援します:
# 変数定義の例
variable "vpc_config" {
type = object({
cidr_block = string
name = string
subnets = map(object({
cidr_block = string
zone = string
}))
})
description = <<EOT
VPCの設定を定義します。
引数:
- cidr_block: VPCのCIDRブロック(例: 10.0.0.0/16)
- name: VPCの名前
- subnets: サブネットの設定
- cidr_block: サブネットのCIDRブロック
- zone: アベイラビリティゾーン
使用例:
vpc_config = {
cidr_block = "10.0.0.0/16"
name = "main-vpc"
subnets = {
public-1 = {
cidr_block = "10.0.1.0/24"
zone = "ap-northeast-1a"
}
}
}
EOT
}
これらのベストプラクティスを適切に組み合わせることで、保守性が高く、安全なTerraformコードを実現できます。次のセクションでは、実際のトラブルシューティングについて解説していきます。
よくあるトラブルとその解決方法
Terraform変数の使用において発生しやすいトラブルとその解決方法について、具体的な事例とともに解説します。
変数の値が正しく渡されない場合の対処法
変数の値が期待通りに渡されないケースは、よく遭遇するトラブルの一つです。
- 変数が未定義のエラー
Error: Reference to undeclared input variable on main.tf line 12, in resource "aws_instance" "example": 12: instance_type = var.instance_type
このエラーの一般的な原因と解決方法:
| 原因 | 解決方法 | コード例 |
|---|---|---|
| 変数定義の漏れ | variables.tfに定義を追加 | variable "instance_type" { type = string } |
| tfvarsファイルの未指定 | -var-fileオプションを使用 | terraform apply -var-file="env.tfvars" |
| 環境変数の未設定 | 環境変数を設定 | export TF_VAR_instance_type="t2.micro" |
- デフォルト値の優先順位の問題
# variables.tf
variable "environment" {
type = string
default = "development"
}
# terraform.tfvars
environment = "staging"
# dev.tfvars
environment = "dev"
解決方法:
# 正しい優先順位での実行 terraform apply -var-file="terraform.tfvars" -var-file="dev.tfvars" # 特定の値を強制的に使用 terraform apply -var="environment=production"
タイプ関連のエラーとその解決方法
型の不一致は頻繁に発生するエラーです。
- 型変換エラー
Error: Invalid value for variable
on variables.tf line 15:
15: variable "instance_count" {
The number 2.5 is not a whole number.
解決例:
# 問題のあるコード
variable "instance_count" {
type = number
}
# 修正後のコード
variable "instance_count" {
type = number
validation {
condition = floor(var.instance_count) == var.instance_count
error_message = "instance_countは整数である必要があります。"
}
}
- リスト・マップの型エラー
# エラーが発生するケース
variable "subnet_cidrs" {
type = list(string)
default = { # マップ型を誤って指定
"subnet1" = "10.0.1.0/24"
}
}
# 正しい指定方法
variable "subnet_cidrs" {
type = list(string)
default = [
"10.0.1.0/24",
"10.0.2.0/24"
]
}
モジュール間の変数受け渡し問題と対策
モジュール間の変数の受け渡しでよく発生する問題とその解決方法を説明します。
- 変数のスコープの問題
# modules/vpc/variables.tf
variable "vpc_settings" {
type = object({
cidr_block = string
name = string
})
}
# main.tf - 問題のあるコード
module "vpc" {
source = "./modules/vpc"
# 直接値を渡そうとしてエラー
cidr_block = "10.0.0.0/16"
name = "main-vpc"
}
# main.tf - 正しいコード
module "vpc" {
source = "./modules/vpc"
vpc_settings = {
cidr_block = "10.0.0.0/16"
name = "main-vpc"
}
}
- 出力変数の連携問題
# modules/vpc/outputs.tf
output "vpc_id" {
value = aws_vpc.main.id
}
# modules/subnet/variables.tf
variable "vpc_id" {
type = string
}
# main.tf - 正しい連携方法
module "vpc" {
source = "./modules/vpc"
# VPC設定
}
module "subnet" {
source = "./modules/subnet"
vpc_id = module.vpc.vpc_id
}
トラブルシューティングのベストプラクティス:
- デバッグ用の出力設定
output "debug_vpc_settings" {
value = var.vpc_settings
}
# デバッグ時に使用
terraform plan -out=plan.out
terraform show plan.out
- 変数値の検証
variable "instance_type" {
type = string
validation {
condition = can(regex("^t[23]\\.", var.instance_type))
error_message = "インスタンスタイプはt2またはt3シリーズである必要があります。"
}
}
- トラブルシューティング用のチェックリスト
| 確認項目 | 確認方法 | 対処方法 |
|---|---|---|
| 変数の定義 | terraform validate | 未定義の変数を追加 |
| 型の一致 | terraform plan | 型定義を修正 |
| 値の存在 | 設定ファイルの確認 | デフォルト値を設定 |
| モジュール連携 | 出力変数の確認 | 正しい参照方法に修正 |
これらの知識を活用することで、多くの一般的なトラブルを効率的に解決できます。次のセクションでは、実践的なユースケースについて解説していきます。
実践的なユースケース
ここでは、Terraform変数の実践的な使用例を、具体的なシナリオとともに解説します。これらのユースケースは、実務での適用を想定して作成しています。
本番・開発環境の設定値管理
複数環境の設定を効率的に管理する実践的な例を示します。
- プロジェクト構成
project/
├── main.tf
├── variables.tf
├── terraform.tfvars
├── environments/
│ ├── dev.tfvars
│ ├── staging.tfvars
│ └── prod.tfvars
└── modules/
├── vpc/
├── ec2/
└── rds/
- 共通変数の定義
# variables.tf
variable "project" {
type = object({
name = string
owner = string
cost_center = string
})
description = "プロジェクトの基本情報"
}
variable "environment_config" {
type = object({
name = string
vpc_cidr = string
subnet_cidrs = map(string)
instance_type = string
rds_instance_class = string
multi_az = bool
})
description = "環境固有の設定"
}
- 環境別の設定
# environments/dev.tfvars
project = {
name = "example-project"
owner = "dev-team"
cost_center = "dev-1234"
}
environment_config = {
name = "development"
vpc_cidr = "10.0.0.0/16"
subnet_cidrs = {
public-1 = "10.0.1.0/24"
private-1 = "10.0.2.0/24"
}
instance_type = "t3.micro"
rds_instance_class = "db.t3.small"
multi_az = false
}
# environments/prod.tfvars
project = {
name = "example-project"
owner = "ops-team"
cost_center = "prod-5678"
}
environment_config = {
name = "production"
vpc_cidr = "172.16.0.0/16"
subnet_cidrs = {
public-1 = "172.16.1.0/24"
public-2 = "172.16.2.0/24"
private-1 = "172.16.3.0/24"
private-2 = "172.16.4.0/24"
}
instance_type = "t3.large"
rds_instance_class = "db.t3.large"
multi_az = true
}
AWS リソースの柔軟な構成管理
AWSリソースを変数を使って柔軟に構成する実践例を示します。
- EC2インスタンスの動的構成
# modules/ec2/variables.tf
variable "instance_config" {
type = object({
instance_type = string
ami_id = string
user_data = string
tags = map(string)
})
description = "EC2インスタンスの設定"
}
variable "scaling_config" {
type = object({
min_size = number
max_size = number
desired_capacity = number
})
description = "Auto Scalingの設定"
}
# modules/ec2/main.tf
resource "aws_launch_template" "this" {
name_prefix = "app-template"
image_id = var.instance_config.ami_id
instance_type = var.instance_config.instance_type
user_data = base64encode(var.instance_config.user_data)
tags = var.instance_config.tags
}
resource "aws_autoscaling_group" "this" {
desired_capacity = var.scaling_config.desired_capacity
max_size = var.scaling_config.max_size
min_size = var.scaling_config.min_size
launch_template {
id = aws_launch_template.this.id
version = "$Latest"
}
}
- データベースリソースの条件付き作成
# modules/rds/variables.tf
variable "db_config" {
type = object({
instance_class = string
engine_version = string
multi_az = bool
backup_retention = number
storage_encrypted = bool
})
description = "RDSインスタンスの設定"
}
# modules/rds/main.tf
resource "aws_db_instance" "this" {
instance_class = var.db_config.instance_class
engine_version = var.db_config.engine_version
multi_az = var.db_config.multi_az
backup_retention_period = var.db_config.backup_retention
storage_encrypted = var.db_config.storage_encrypted
lifecycle {
prevent_destroy = var.db_config.multi_az # 本番環境のDBは誤削除を防止
}
}
チーム開発での変数管理のベストプラクティス
チーム開発における効率的な変数管理の実践例を示します。
- 変数のモジュール化と再利用
# modules/common/variables.tf
variable "common_tags" {
type = object({
Environment = string
Project = string
Owner = string
ManagedBy = string
})
description = "共通で使用するタグ"
}
# 使用例
module "common" {
source = "./modules/common"
common_tags = {
Environment = var.environment_config.name
Project = var.project.name
Owner = var.project.owner
ManagedBy = "terraform"
}
}
- チーム共有の変数検証ルール
# modules/validation/variables.tf
variable "resource_naming" {
type = object({
prefix = string
name = string
})
validation {
condition = can(regex("^[a-z0-9-]+$", var.resource_naming.prefix))
error_message = "プレフィックスは小文字のアルファベット、数字、ハイフンのみ使用可能です。"
}
validation {
condition = length(var.resource_naming.name) <= 32
error_message = "リソース名は32文字以下である必要があります。"
}
}
実装のポイント:
| 項目 | 実装方針 | メリット |
|---|---|---|
| 環境分離 | 環境別の.tfvarsファイル | 設定の明確な分離と管理が容易 |
| モジュール化 | 共通処理のモジュール化 | コードの再利用性向上 |
| 命名規則 | 変数名の規則化 | チーム内での理解促進 |
| 検証ルール | 共通の検証ルール適用 | 設定ミスの防止 |
これらのユースケースを参考に、プロジェクトの要件に合わせて適切な変数管理を実装することで、効率的なインフラ構築が可能になります。