0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【IaC超入門】30日でAWS CloudFormationとTerraformをマスターするロードマップ - 27日目: CloudFormationとTerraformを組み合わせるケーススタディ

Posted at

CloudFormationとTerraformを組み合わせるケーススタディ

はじめに

これまで、CloudFormationとTerraformをそれぞれ単体で学んできました。どちらのツールも強力ですが、実際のプロジェクトでは、それぞれの強みを活かして併用するケースが少なくありません。今回は、CloudFormationとTerraformを組み合わせる具体的なケーススタディを解説します。

なぜ両者を組み合わせるのか?

CloudFormationとTerraformは、それぞれ異なる得意分野を持っています。

ツール 得意なこと
CloudFormation AWS公式サービスとの深い統合、イベント駆動型デプロイ、IAMリソースの管理、自動ロールバック
Terraform マルチクラウド対応、複雑なモジュール化、ローカルでの実行計画確認、状態管理

これらの強みを活かすことで、単一のツールでは難しい、柔軟で効率的なIaCを実現できます。

ケーススタディ:ハイブリッドIaCモデル

このモデルでは、インフラを**「基盤レイヤー」「アプリケーションレイヤー」**に分割し、それぞれに最適なツールを割り当てます。

1. 基盤レイヤー(Terraformで管理)

プロジェクト全体で共有される、変更頻度の低い共通インフラをTerraformで管理します。

対象リソース:

  • VPC、サブネット、インターネットゲートウェイなどのネットワークリソース
  • 共通のIAMロール、ポリシー
  • S3バケット、RDSサブネットグループなど
  • セキュリティグループの基本設定

選択理由:

  • 再利用性の向上: 共通のVPC構成などをモジュール化し、複数のプロジェクトで再利用できます
  • 柔軟な管理: 必要に応じて、異なるクラウド(例:VPC Peering経由でGCPと連携)を管理する可能性があります
  • 状態管理: Terraformの強力な状態管理機能により、インフラの変更を安全に管理できます

Terraformコード例:基盤リソースのOutputs

# outputs.tf (基盤レイヤー)
output "main_vpc_id" {
  description = "The ID of the main VPC"
  value       = aws_vpc.main.id
}

output "public_subnet_ids" {
  description = "List of public subnet IDs"
  value       = aws_subnet.public[*].id
}

output "private_subnet_ids" {
  description = "List of private subnet IDs"
  value       = aws_subnet.private[*].id
}

output "security_group_web_id" {
  description = "Security group ID for web servers"
  value       = aws_security_group.web.id
}

2. アプリケーションレイヤー(CloudFormationで管理)

アプリケーション固有の、変更頻度が高いリソースをCloudFormationで管理します。

対象リソース:

  • EC2インスタンス、Auto Scaling Group
  • アプリケーションロードバランサー(ALB)
  • アプリケーション固有のIAMロール
  • Lambda関数やECSサービス

選択理由:

  • AWSサービスとの親和性: アプリケーションリソースは、ECSやLambdaといったAWSの他のサービスと密接に連携することが多いため、公式のCloudFormationが最も信頼性が高く、連携がスムーズです
  • 自動ロールバック: デプロイ時にエラーが発生しても、CloudFormationが自動でロールバックしてくれるため、アプリケーションのデプロイが安全に行えます
  • イベント統合: CloudFormationのイベントをSNS/SQSと連携させ、デプロイ通知を自動化できます

CloudFormationコード例:アプリケーションリソース

# application.yaml (アプリケーションレイヤー)
AWSTemplateFormatVersion: "2010-09-09"
Description: "Application layer resources"

Parameters:
  VpcId:
    Type: String
    Description: The ID of the existing VPC from Terraform
  
  PublicSubnetIds:
    Type: CommaDelimitedList
    Description: List of public subnet IDs from Terraform
  
  WebSecurityGroupId:
    Type: String
    Description: Security group ID for web servers from Terraform

Resources:
  ApplicationLoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Name: MyAppALB
      Scheme: internet-facing
      Type: application
      Subnets: !Ref PublicSubnetIds
      SecurityGroups:
        - !Ref WebSecurityGroupId

  WebServerLaunchTemplate:
    Type: AWS::EC2::LaunchTemplate
    Properties:
      LaunchTemplateName: WebServerTemplate
      LaunchTemplateData:
        ImageId: ami-0abcdef1234567890  # Amazon Linux 2023
        InstanceType: t3.micro
        SecurityGroupIds:
          - !Ref WebSecurityGroupId
        IamInstanceProfile:
          Arn: !GetAtt WebServerInstanceProfile.Arn

  AutoScalingGroup:
    Type: AWS::AutoScaling::AutoScalingGroup
    Properties:
      AutoScalingGroupName: WebServerASG
      LaunchTemplate:
        LaunchTemplateId: !Ref WebServerLaunchTemplate
        Version: !GetAtt WebServerLaunchTemplate.LatestVersionNumber
      MinSize: 1
      MaxSize: 3
      DesiredCapacity: 2
      VPCZoneIdentifier: !Ref PublicSubnetIds
      TargetGroupARNs:
        - !Ref ALBTargetGroup

  ALBTargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Name: WebServerTargetGroup
      Port: 80
      Protocol: HTTP
      VpcId: !Ref VpcId
      HealthCheckPath: /health

  WebServerRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: ec2.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore

  WebServerInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Roles:
        - !Ref WebServerRole

Outputs:
  LoadBalancerDNS:
    Description: DNS name of the load balancer
    Value: !GetAtt ApplicationLoadBalancer.DNSName
    Export:
      Name: !Sub "${AWS::StackName}-LoadBalancerDNS"

連携方法:OutputsとParametersの活用

Terraformで管理する基盤レイヤーのOutputsを、CloudFormationで管理するアプリケーションレイヤーのParametersに渡すことで、両者を連携させます。

連携の具体的手順

  1. TerraformでOutputsを定義: Terraformのoutputs.tfで、VPCのIDやサブネットのIDを定義
  2. TerraformでCloudFormationをデプロイ: Terraformのaws_cloudformation_stackリソースを使用
  3. パラメータの受け渡し: TerraformのOutputsをCloudFormationのParametersに渡す

Terraformコード例:CloudFormationスタックの呼び出し

# main.tf (Terraform)
locals {
  stack_name = "MyApplicationStack"
}

# CloudFormationテンプレートの読み込み
data "template_file" "application_template" {
  template = file("${path.module}/application.yaml")
}

# CloudFormationスタックのデプロイ
resource "aws_cloudformation_stack" "app_stack" {
  name         = local.stack_name
  template_body = data.template_file.application_template.rendered
  
  parameters = {
    VpcId               = aws_vpc.main.id
    PublicSubnetIds     = join(",", aws_subnet.public[*].id)
    WebSecurityGroupId  = aws_security_group.web.id
  }
  
  capabilities = ["CAPABILITY_IAM"]
  
  tags = {
    Environment = var.environment
    Project     = var.project_name
    ManagedBy   = "Terraform"
  }
}

# CloudFormationスタックの出力を取得
data "aws_cloudformation_stack" "app_stack_outputs" {
  name = aws_cloudformation_stack.app_stack.name
}

プロジェクト構成例

実際のプロジェクトでは、以下のようなディレクトリ構成を推奨します:

infrastructure/
├── terraform/                 # 基盤レイヤー
│   ├── modules/
│   │   └── network/
│   │       ├── main.tf
│   │       ├── variables.tf
│   │       └── outputs.tf
│   ├── environments/
│   │   ├── dev/
│   │   │   ├── main.tf
│   │   │   ├── terraform.tfvars
│   │   │   └── backend.tf
│   │   └── prod/
│   │       ├── main.tf
│   │       ├── terraform.tfvars
│   │       └── backend.tf
│   └── cloudformation/        # CloudFormationテンプレート
│       ├── application.yaml
│       └── database.yaml
├── scripts/
│   ├── deploy.sh
│   └── destroy.sh
└── README.md

メリット・デメリットと注意点

メリット

  • 最適なツールの使い分け: 各レイヤーで最適なツールを使用可能
  • リスクの分散: 基盤とアプリケーションで変更の影響範囲を分離
  • チーム分業: インフラチームとアプリチームで責任分担が可能

デメリット・注意点

  • 複雑性の増大: 2つのツールを管理する必要がある
  • 学習コスト: 両方のツールの知識が必要
  • 依存関係の管理: 基盤レイヤーの変更がアプリケーションレイヤーに影響する可能性
  • デバッグの困難さ: 問題発生時の原因特定が複雑になる場合がある

ベストプラクティス

  1. 明確な責任分界点: どのリソースをどちらで管理するかを明確に定義
  2. バージョン管理: 両方のコードを同じリポジトリで管理し、変更履歴を追跡
  3. CI/CDパイプライン: 自動化されたデプロイメントパイプラインの構築
  4. モニタリング: 両レイヤーのリソース状態を監視する仕組みの構築
  5. ドキュメント化: 連携方法や依存関係を明確に文書化

まとめ

CloudFormationとTerraformのハイブリッドモデルは、それぞれのツールの弱点を補完し、より堅牢でスケーラブルなIaCを実現します。

レイヤー 管理ツール 主な理由
基盤 Terraform 再利用性、マルチクラウド対応、モジュール化
アプリケーション CloudFormation AWSサービスとの親和性、自動ロールバック、イベント統合

このアプローチは、大規模なインフラを管理する多くの企業で採用されており、一つのツールに固執せず、目的に応じて最適なツールを使い分けることの重要性を示しています。

ただし、複雑性が増すことも事実なので、チームのスキルレベルやプロジェクトの規模を考慮して導入を検討することが重要です。小規模なプロジェクトでは、単一ツールでの管理の方が効率的な場合もあることを念頭に置いて選択しましょう。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?