Site cover image

Site icon imageViserhaut Tech Blog

This blog is a blog that records the daily learning of an infrastructure engineer. It aims to "Viser Haut" or strive for the highest.

Terragruntを活用したインフラ管理実装例:ECRモジュールの設定と解説

TerraformやOpenTofuを用いたインフラ管理において、Terragruntを活用することでコードの再利用性を高め、環境ごとの設定を効率的に管理できます。本記事では、Terragruntを使用してAWSのECR(Elastic Container Registry)モジュールを管理する実装例を紹介し、各設定ファイルの内容を丁寧に解説します。

ディレクトリ構造

まず、以下のディレクトリ構造を用いてプロジェクトを構築します。

.
├── environments/
│   ├── dev/
│   │   ├── ecr/
│   │   │   └── terragrunt.hcl
│   │   ├── ecs/
│   │   │   └── terragrunt.hcl
│   │   ├── terragrunt.hcl
│   │   └── env_vars.yaml
│   ├── stg/
│   │   ├── ecr/
│   │   │   └── terragrunt.hcl
│   │   ├── ecs/
│   │   │   └── terragrunt.hcl
│   │   ├── terragrunt.hcl
│   │   └── env_vars.yaml
│   ├── prd/
│   │   ├── ecr/
│   │   │   └── terragrunt.hcl
│   │   ├── ecs/
│   │   │   └── terragrunt.hcl
│   │   ├── terragrunt.hcl
│   │   └── env_vars.yaml
│   ├── common_vars.yaml
│   └── terragrunt.hcl
└── modules/
    ├── ecr/
    │   ├── main.tf
    │   ├── outputs.tf
    │   └── variables.tf
    └── ecs/
        ├── main.tf
        ├── outputs.tf
        └── variables.tf
ディレクトリ説明
  • environments/: 各環境(dev, stg, prd)ごとの設定を格納。
    • dev/, stg/, prd/: 開発、ステージング、本番環境のディレクトリ。
      • ecr/: ECR関連のTerragrunt設定ファイル。
      • ecs/: ECS関連のTerragrunt設定ファイル(今回は詳細を省略)。
      • terragrunt.hcl: 環境全体の親設定ファイル。
      • env_vars.yaml: 環境固有の変数定義。
  • common_vars.yaml: すべての環境で共通の変数定義。
  • modules/: 再利用可能なTerraform/OpenTofuモジュールを格納。
    • ecr/: ECRリポジトリを管理するモジュール。
    • ecs/: ECSクラスターを管理するモジュール(詳細は省略)。

実装例:開発環境(dev)のECR設定

ここでは、**environments/dev/**ディレクトリ内の設定ファイルを中心に解説します。

1. 共通変数の定義 (environments/common_vars.yaml)
region: ap-northeast-1
name: fumis-infra

解説:

  • region: AWSリージョンを指定(ここでは東京リージョン)。
  • name: インフラ全体の名前(ここではfumis-infra)。

これらの変数は、すべての環境で共通して使用されます。

2. 環境固有変数の定義 (environments/dev/env_vars.yaml)
env: dev

解説:

  • env: 現在の環境を指定(ここでは開発環境dev)。
3. 環境全体のTerragrunt設定 (environments/dev/terragrunt.hcl)
# environments/dev/terragrunt.hcl

remote_state {
  backend = "s3"

  generate = {
    path      = "_backend.tf"
    if_exists = "overwrite_terragrunt"
  }

  config = {
    bucket               = "terragrunt-${local.env}-${local.name}-terraform-tfstate-s3-bucket"
    key                  = "${path_relative_to_include()}/terraform.tfstate"
    region               = "${local.region}"
    encrypt              = true
    bucket_sse_algorithm = "AES256"

    s3_bucket_tags = {
      "Environment"        = "${local.env}"
      "ServiceName"        = "${local.name}"
      "CreatedByTerragrunt" = "true"
    }
  }
}

generate "provider" {
  path      = "_provider.tf"
  if_exists = "overwrite_terragrunt"
  contents  = <<EOF
provider "aws" {
  region = "${local.region}"
  default_tags {
    tags = {
      Environment        = "${local.env}"
      ServiceName        = "${local.name}"
      ManagedByTerraform = true
    }
  }
}
EOF
}

generate "version" {
  path      = "_terraform.tf"
  if_exists = "overwrite_terragrunt"
  contents  = <<EOF
terraform {
  required_version = "~> 1.9.0"
  required_providers {
    aws = {
      version = "~> 5.59.0"
      source  = "hashicorp/aws"
    }
  }
}
EOF
}

locals {
  env_vars    = yamldecode(file(find_in_parent_folders("env_vars.yaml")))
  common_vars = yamldecode(file(find_in_parent_folders("common_vars.yaml")))

  env    = local.env_vars.env
  region = local.common_vars.region
  name   = local.common_vars.name
}

解説:

  1. locals ブロック:
    • env_vars: 環境固有の変数をenv_vars.yamlから読み込む。
    • common_vars: 共通変数をcommon_vars.yamlから読み込む。
    • env: 環境名(dev)。
    • region: AWSリージョン(ap-northeast-1)。
    • name: インフラの名前(fumis-infra)。
  2. remote_state ブロック:
    • backend: S3をバックエンドに指定。
    • generate: backend.tfを自動生成。
    • config:
      • bucket: S3バケット名。terragrunt-dev-fumis-infra-terraform-tfstate-s3-bucketのように環境と名前を組み合わせ。
      • key: 各モジュールの状態ファイルのキー。
      • region: AWSリージョン。
      • encrypt: S3バケットの暗号化を有効化。
      • bucket_sse_algorithm: 暗号化アルゴリズムを指定。
      • s3_bucket_tags: S3バケットにタグを付与。
  3. generate "provider" ブロック:
    • path: provider.tfを自動生成。
    • contents: AWSプロバイダーの設定を記述。
      • region: AWSリージョン。
      • default_tags: 全リソースに共通のタグを付与。
  4. generate "version" ブロック:
    • path: terraform.tfを自動生成。
    • contents: Terraformのバージョンとプロバイダーの設定。
      • required_version: Terraformのバージョン指定。
      • required_providers: AWSプロバイダーのバージョンとソース指定。
4. ECRモジュールのTerragrunt設定 (environments/dev/ecr/terragrunt.hcl)
# environments/dev/ecr/terragrunt.hcl

include "root" {
  path = find_in_parent_folders()
}

terraform {
  source = "../../modules/ecr"
}

inputs = {
  env  = local.env
  name = local.name
}

locals {
  env_vars    = yamldecode(file(find_in_parent_folders("env_vars.yaml")))
  common_vars = yamldecode(file(find_in_parent_folders("common_vars.yaml")))

  env  = local.env_vars.env
  name = local.common_vars.name
}

解説:

  1. include ブロック:
    • 親設定ファイル(environments/dev/terragrunt.hcl)を継承。
  2. terraform ブロック:
    • source: ECRモジュールのパスを指定(ここでは相対パス../../modules/ecr)。
  3. inputs ブロック:
    • モジュールに渡す入力パラメータを指定。
      • env: 環境名(dev)。
      • name: インフラの名前(fumis-infra)。
  4. locals ブロック:
    • 親ファイルと同様に、環境固有と共通の変数を読み込み、ローカル変数として定義。
5. ECRモジュールのTerraform設定 (modules/ecr/main.tf)
# modules/ecr/main.tf

resource "aws_ecr_repository" "this" {
  name                 = "${var.name}-ecr-${var.env}"
  image_tag_mutability = "MUTABLE"

  tags = {
    Environment = var.env
    Service     = var.name
  }
}

解説:

  • aws_ecr_repository リソース:
    • name: ECRリポジトリの名前をfumis-infra-ecr-devのように設定。
    • image_tag_mutability: タグの不変性を設定(ここでは変更可能)。
    • tags: リポジトリにタグを付与(環境名とサービス名)。
6. ECRモジュールの変数定義 (modules/ecr/variables.tf)
# modules/ecr/variables.tf

variable "env" {
  description = "The environment name (e.g., dev, stg, prd)"
  type        = string
}

variable "name" {
  description = "The name of the service or infrastructure"
  type        = string
}

解説:

  • env: 環境名を受け取る変数。
  • name: サービス名やインフラの名前を受け取る変数。
7. ECRモジュールの出力定義 (modules/ecr/outputs.tf)
# modules/ecr/outputs.tf

output "repository_url" {
  description = "The URL of the ECR repository"
  value       = aws_ecr_repository.this.repository_url
}

解説:

  • repository_url: 作成したECRリポジトリのURLを出力。

実装の流れ

以下のステップでTerragruntを使用してECRリポジトリをデプロイします。

ステップ1: 環境設定の確認

開発環境の変数定義を確認します。

  • common_vars.yaml
    region: ap-northeast-1
    name: fumis-infra
    
  • env_vars.yaml
    env: dev
    
ステップ2: Terragruntの設定ファイルを確認
  • environments/dev/terragrunt.hcl
    • リモート状態の設定をS3に一元化。
    • AWSプロバイダーの設定を共通化。
    • Terraformのバージョンとプロバイダーのバージョンを指定。
  • environments/dev/ecr/terragrunt.hcl
    • 親設定を継承。
    • ECRモジュールのソースを指定。
    • モジュールに環境名とインフラ名を入力パラメータとして渡す。
ステップ3: Terraformモジュールの準備
  • modules/ecr/main.tf
    • AWS ECRリポジトリを作成。
    • 環境名とインフラ名を組み合わせてリポジトリ名を生成。
    • タグを付与。
  • modules/ecr/variables.tf
    • 環境名とインフラ名を受け取る変数を定義。
  • modules/ecr/outputs.tf
    • 作成したリポジトリのURLを出力。
ステップ4: Terragruntコマンドの実行

開発環境のECRリポジトリをデプロイするために、以下のコマンドを実行します。

cd environments/dev/ecr
terragrunt init
terragrunt apply

解説:

  1. terragrunt init:
    • Terragruntが指定されたリモート状態の設定を読み込み、必要な初期化を実行します。
    • S3バケットが存在しない場合、自動的に作成されます。
  2. terragrunt apply:
    • Terraform/OpenTofuがECRリポジトリを作成します。
    • terraform.tfstateがS3に保存され、DynamoDBテーブルで状態のロックが管理されます。
ステップ5: 出力結果の確認

コマンド実行後、以下のような出力が得られます。

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Outputs:

repository_url = "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/fumis-infra-ecr-dev"

解説:

  • repository_url: 作成されたECRリポジトリのURLが出力されます。

CI/CDパイプラインとの統合

この設定をAWS CodePipelineなどのCI/CDツールに統合することで、コードの変更に応じて自動的にインフラをデプロイできます。以下は、簡単な統合手順の概要です。

ステップ1: CodePipelineの設定
  1. ソースステージ:
    • GitHubやCodeCommitなど、コードリポジトリをソースとして設定。
  2. ビルドステージ:
    • CodeBuildを使用して、Terragruntコマンドを実行。
    • environments/dev/ecr/terragrunt.hclディレクトリに移動し、terragrunt applyを実行。
ステップ2: CodeBuildのビルド仕様 (buildspec.yml)
version: 0.2

phases:
  install:
    runtime-versions:
      python: 3.8
    commands:
      - curl -LO <https://github.com/gruntwork-io/terragrunt/releases/download/v0.45.0/terragrunt_linux_amd64>
      - chmod +x terragrunt_linux_amd64
      - mv terragrunt_linux_amd64 /usr/local/bin/terragrunt
  pre_build:
    commands:
      - terragrunt --version
  build:
    commands:
      - cd environments/dev/ecr
      - terragrunt init
      - terragrunt apply -auto-approve

解説:

  • install フェーズ:
    • Terragruntのバイナリをダウンロードし、実行可能に設定。
  • pre_build フェーズ:
    • Terragruntのバージョンを確認。
  • build フェーズ:
    • ECRモジュールのディレクトリに移動し、Terragruntコマンドを実行。
ステップ3: CodePipelineの実行

CodePipelineがトリガーされると、CodeBuildが自動的にTerragruntを実行し、ECRリポジトリをデプロイします。成功すれば、CI/CDパイプラインが完了します。

まとめ

本記事では、Terragruntを使用してAWSのECRリポジトリを管理する実装例を紹介しました。Terragruntを活用することで、以下のメリットが得られます。

  • コードの再利用性向上: モジュール化により、共通コードを一元管理。
  • 設定の一貫性確保: リモート状態の一元管理と自動生成による設定の統一。
  • 効率的な環境管理: 複数環境(dev, stg, prd)での設定の簡素化。
  • CI/CDとの統合: 自動デプロイによるインフラ管理の自動化と信頼性向上。

Terragruntを活用することで、インフラ管理がより効率的かつ安全になります。ぜひ本実装例を参考に、あなたのプロジェクトにもTerragruntを導入してみてください。

参考資料