「Cycle」循環参照エラーの原因と解決方法

1. 概要

  • 「Cycle」エラー(循環参照)とは
  • 発生原因(リソースAがBを参照し、BがAを参照する)
  • よくある発生パターン
  • 解決方法(参照を外す・depends_on除去・設計の見直し)

循環参照エラーは、2つ以上のリソースが互いに依存し合ってしまったときに発生します。TerraformはDAG(有向非巡回グラフ)で依存関係を管理するため、ループする依存関係は解決できません。


2. エラーメッセージ

Error: Cycle: aws_security_group.app, aws_security_group.db

または:

Error: Cycle
aws_instance.web (destroy) -> aws_security_group.web -> aws_instance.web

3. 典型的な循環参照の例

セキュリティグループの相互参照

terraform {
  required_version = ">= 1.9"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "ap-northeast-1"
}

variable "environment" {
  description = "環境名"
  type        = string
  default     = "dev"
}

resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
  tags = {
    Name        = "${var.environment}-main"
    Environment = var.environment
    ManagedBy   = "terraform"
  }
}

# ❌ エラー: app_sgがdb_sgを参照し、db_sgがapp_sgを参照 → 循環参照
resource "aws_security_group" "app" {
  name   = "${var.environment}-app-sg"
  vpc_id = aws_vpc.main.id

  egress {
    from_port       = 5432
    to_port         = 5432
    protocol        = "tcp"
    security_groups = [aws_security_group.db.id]  # db_sgに依存
  }

  tags = {
    Name        = "${var.environment}-app-sg"
    Environment = var.environment
    ManagedBy   = "terraform"
  }
}

resource "aws_security_group" "db" {
  name   = "${var.environment}-db-sg"
  vpc_id = aws_vpc.main.id

  ingress {
    from_port       = 5432
    to_port         = 5432
    protocol        = "tcp"
    security_groups = [aws_security_group.app.id]  # app_sgに依存 → 循環!
  }

  tags = {
    Name        = "${var.environment}-db-sg"
    Environment = var.environment
    ManagedBy   = "terraform"
  }
}

4. 解決方法: aws_security_group_rule を分離する

# ✅ 解決: SGを空で作成し、ルールを別リソースで追加

resource "aws_security_group" "app" {
  name   = "${var.environment}-app-sg"
  vpc_id = aws_vpc.main.id

  tags = {
    Name        = "${var.environment}-app-sg"
    Environment = var.environment
    ManagedBy   = "terraform"
  }
}

resource "aws_security_group" "db" {
  name   = "${var.environment}-db-sg"
  vpc_id = aws_vpc.main.id

  tags = {
    Name        = "${var.environment}-db-sg"
    Environment = var.environment
    ManagedBy   = "terraform"
  }
}

# ルールを別リソースで追加(循環参照が解消される)
resource "aws_security_group_rule" "app_to_db" {
  type                     = "egress"
  from_port                = 5432
  to_port                  = 5432
  protocol                 = "tcp"
  source_security_group_id = aws_security_group.db.id
  security_group_id        = aws_security_group.app.id
}

resource "aws_security_group_rule" "db_from_app" {
  type                     = "ingress"
  from_port                = 5432
  to_port                  = 5432
  protocol                 = "tcp"
  source_security_group_id = aws_security_group.app.id
  security_group_id        = aws_security_group.db.id
}

5. depends_on による意図しない循環参照

# ❌ depends_onの設定ミスで循環参照が起きることがある
resource "aws_instance" "web" {
  ami           = data.aws_ami.amazon_linux_2023.id
  instance_type = "t3.micro"

  depends_on = [aws_instance.app]  # appに依存
}

resource "aws_instance" "app" {
  ami           = data.aws_ami.amazon_linux_2023.id
  instance_type = "t3.micro"

  depends_on = [aws_instance.web]  # webに依存 → 循環!
}
# ✅ 解決: 不要なdepends_onを削除する
# 実際の参照依存関係だけを使う
resource "aws_instance" "web" {
  ami           = data.aws_ami.amazon_linux_2023.id
  instance_type = "t3.micro"
}

resource "aws_instance" "app" {
  ami           = data.aws_ami.amazon_linux_2023.id
  instance_type = "t3.micro"
}

6. 循環参照の発見方法

# terraform graph で依存グラフを可視化
terraform graph | dot -Tpng -o graph.png

# または planでエラーを確認
terraform plan

7. 関連記事


8. まとめ

  • 循環参照(Cycle)はリソースAがBを参照し、BがAを参照する状態で発生
  • 最も多い例がセキュリティグループの相互参照(SGのingressとegressで互いを参照)
  • 解決策はSGを空で作成し、aws_security_group_ruleでルールを別途追加する
  • depends_onの誤設定でも循環参照が発生するため、不要なdepends_onは削除する
  • terraform graphで依存グラフを可視化して問題箇所を特定できる

動作確認バージョン: Terraform >= 1.9 公式ドキュメント: https://developer.hashicorp.com/terraform/language/meta-arguments/depends_on