🎃

Cloud9環境でTerraformをリソースをモジュール化してAWSリソースをデプロイすることを試してみた

2023/10/22に公開

Terraformと依存ツールのセットアップ

Cloud9環境上でTerraform及びその依存ツールのセットアップを行います。このセクションでは、Cloud9の環境がAmazon Linux2であることを前提として進めます。
記述したEC2上でコードディングしているのでEBSにコードが格納(cloud9)※S3に格納していないです。

環境設定

  1. AWS CLIとGitのバージョン確認:

    aws --version
    git --version
    
  2. tfenvのインストール:※terraform環境の導入

    git clone https://github.com/tfutils/tfenv.git ~/.tfenv
    sudo ln -s ~/.tfenv/bin/* /usr/local/bin
    
  3. tfenvバージョン確認:

    tfenv -v
    
  4. 利用可能なTerraformバージョン一覧表示:

    tfenv list-remote
    
  5. Terraform 1.5.7インストール:

    tfenv install 1.5.7
    
  6. インストール済みのTerraformバージョン一覧表示:

    tfenv list
    
  7. Terraformバージョンの設定 (1.5.7):

    tfenv use 1.5.7
    
  8. 設定されたTerraformバージョン確認:

    terraform -v
    
  9. 新しいディレクトリ作成と移動:

    mkdir test-terraform && cd test-terraform
    

モジュール化のメリットと使い方

モジュール化のメリット

  1. 再利用性: 同じリソース設定を繰り返し利用でき、コードの重複を避ける。
  2. 整理: リソースごとにモジュール分割することで、コードの読みやすさが向上し、メンテナンスも容易に。
  3. スケーラビリティ: リソースの追加や変更が容易に行える。

モジュール使用方法

  1. main.tfでモジュールを呼び出し、必要な変数を渡す。
  2. 各モジュールディレクトリには、固有の任意の名前.tf, variables.tf, および outputs.tfを配置する。
  3. 任意の名前.tfでモジュール内のリソースを定義、variables.tfで変数を定義し、outputs.tfでモジュールの出力を定義する。

Terraformの推奨される構造とその使用方法

1. フォルダ構成とその説明

以下は、Terraformの推奨されるフォルダ構成および各フォルダ・ファイルの説明です:

test-terraform/
│
├── main.tf         - メインのTerraform設定ファイル。モジュールの呼び出しやリソースの基本的な定義を行います。
├── variables.tf    - プロジェクト全体で使用する変数を定義します。
├── outputs.tf      - プロジェクト全体の出力値を定義します。
├── providers.tf    - プロバイダ(例: AWS)の設定を行います。
│
├── env/
│   ├── dev.tfvars        - 開発環境の変数を定義するファイルです。
│   ├── staging.tfvars    - ステージング環境の変数を定義するファイルです。
│   └── prod.tfvars       - 本番環境の変数を定義するファイルです。リソースのサイズやIDなど、本番環境固有の設定を持ちます。
│
└── modules/        - 一般的なリソース設定を再利用可能なモジュールとして保存するディレクトリです。
    ├── vpc/
    │   ├── vpc.tf         - VPCに関連するリソースを定義します。
    │   ├── variables.tf    - VPCモジュール専用の変数を定義します。
    │   └── outputs.tf      - VPCモジュールの出力値を定義します。
    ├── subnet/
    │   ├── subnet.tf         - サブネットに関連するリソースを定義します。
    │   ├── variables.tf    - サブネットモジュール専用の変数を定義します。
    │   └── outputs.tf      - サブネットモジュールの出力値を定義します。
    └── ec2/
        ├── ec2.tf         - EC2に関連するリソースを定義します。
        ├── variables.tf    - EC2モジュール専用の変数を定義します。
        └── outputs.tf      - EC2モジュールの出力値を定義します。

2. モジュールの利点

  • 再利用性: 同じ設定を持つリソースや設定群を複数の場所やプロジェクトで再利用することができます。

  • 組織化: 関連するリソースをグループ化し、プロジェクトを読みやすく、管理しやすくします。

  • 変数の利用: モジュールは変数を受け入れることができ、そのため、異なる環境や条件で同じモジュールを異なる設定で使用することができます。

  • モジュールの使用方法:

    1. 任意の名前.tfにて各モジュールを呼び出し、その際に必要な変数を渡します。
    2. 各モジュールディレクトリ内には、そのモジュール固有のmain.tf, variables.tf, 及び outputs.tfを配置します。
    3. main.tfはモジュール内のリソース定義を行い、variables.tfで変数を定義し、outputs.tfでモジュールの出力を定義します。

3. .tfvars ファイルの利用

.tfvarsファイルは、変数の値を定義するためのものです。環境ごとに異なる.tfvarsファイルを持つことで、同じTerraform設定を異なる環境(開発、ステージング、本番など)で使用することが容易になります。

例えば、prod.tfvarsには本番環境用のAWSのリージョンやインスタンスタイプなどの変数値が定義され、dev.tfvarsには開発環境用のそれらの変数値が定義されます。

Terraformコードの作成

AWSプロバイダ設定

  • AWSプロバイダ設定のサンプルコード。特定のAWSリージョン(ap-northeast-1)を対象とする。
    cat << 'EOF' > providers.tf
    terraform {
        required_providers {
            aws = {
                source  = "hashicorp/aws"
                version = "~> 5.0"
            }
        }
    }
    
    provider aws {
        region = "ap-northeast-1"
    }
    EOF
    

main.tf内容

  • 各モジュール呼び出しのサンプルコード。VPC、サブネット、EC2のモジュールを利用してリソースを作成する。
cat << 'EOF' > main.tf
variable "vpc_cidr" {
  description = "CIDR block for the VPC"
  type        = string
}

variable "subnet_cidr" {
  description = "CIDR block for the subnet"
  type        = string
}

variable "ami" {
  description = "Amazon Machine Image ID"
  type        = string
}

variable "instance_type" {
  description = "EC2 instance type"
  type        = string
}

module "vpc" {
    source      = "./modules/vpc"
    vpc_cidr    = var.vpc_cidr
}

module "subnet" {
    source     = "./modules/subnet"
    vpc_id     = module.vpc.vpc_id
    subnet_cidr = var.subnet_cidr
}

module "ec2" {
    source      = "./modules/ec2"
    subnet_id   = module.subnet.subnet_id
    ami         = var.ami
    instance_type = var.instance_type
}

EOF

変数

  • var.xxxは外部から渡される変数を参照するものである。

環境別の設定

各環境(devstagingprodなど)に対する設定を適用することで、一つのTerraformコードで異なる設定やリソースをデプロイすることが可能である。以下はdev環境(開発環境)向けの設定例である:

mkdir -p env/
cat << 'EOF' > env/dev.tfvars
vpc_cidr       = "10.0.0.0/16"
subnet_cidr    = "10.0.1.0/24"
ami            = "ami-0bba69335379e17f8"
instance_type  = "t2.micro"
EOF

そして、staging環境の設定は以下の通りである:

cat << 'EOF' > env/staging.tfvars
vpc_cidr       = "[適切なCIDRブロック]"
subnet_cidr    = "[適切なサブネットのCIDRブロック]"
ami            = "[適切なAMI ID]"
instance_type  = "[インスタンスタイプ]"
EOF
mkdir -p env/
cat << 'EOF' > env/prod.tfvars
vpc_cidr       = "[適切なCIDRブロック]"
subnet_cidr    = "[適切なサブネットのCIDRブロック]"
ami            = "[適切なAMI ID]"
instance_type  = "[インスタンスタイプ]"
EOF

各環境の具体的な設定値は、実際の運用環境に応じて適切に入力

モジュールの作成

  • モジュールの役割は、特定のリソースをひとまとめにして再利用可能なコードにする。以下に、VPC, subnet, EC2のモジュールを作成。

  • VPCモジュール:

    • VPCの設定を一まとめにしたモジュールです。VPCのCIDRブロックを変数として受け取り、VPCを作成。

      mkdir -p modules/vpc
      cat << 'EOF' > modules/vpc/vpc.tf
      resource "aws_vpc" "main" {
          cidr_block = var.vpc_cidr
          tags = {
              Name = "Main VPC"
          }
      }
      EOF
      
      cat << 'EOF' > modules/vpc/variables.tf
      variable "vpc_cidr" {
          description = "CIDR block for the VPC"
          type        = string
      }
      EOF
      
      cat << 'EOF' > modules/vpc/outputs.tf
      output "vpc_id" {
          description = "The ID of the created VPC"
          value       = aws_vpc.main.id
      }
      EOF
      
  • subnetモジュール:

    • VPC内にサブネットを作成するためのモジュールです。VPCのIDとサブネットのCIDRブロックを変数として受け取り、サブネットを作成。

      mkdir -p modules/subnet
      cat << 'EOF' > modules/subnet/subnet.tf
      resource "aws_subnet" "main" {
          vpc_id     = var.vpc_id
          cidr_block = var.subnet_cidr
          tags = {
              Name = "Main Subnet"
          }
      }
      EOF
      
      cat << 'EOF' > modules/subnet/variables.tf
      variable "vpc_id" {
          description = "The ID of the VPC where the subnet will be created"
          type        = string
      }
      
      variable "subnet_cidr" {
          description = "CIDR block for the subnet"
          type        = string
      }
      EOF
      
      cat << 'EOF' > modules/subnet/outputs.tf
      output "subnet_id" {
          description = "The ID of the created subnet"
          value       = aws_subnet.main.id
      }
      EOF
      
      
  • EC2モジュール:

    • EC2インスタンスを作成するためのモジュールです。サブネットID, AMI ID, インスタンスタイプを変数として受け取り、EC2インスタンスを作成。

      mkdir -p modules/ec2
      cat << 'EOF' > modules/ec2/ec2.tf
      resource "aws_instance" "main" {
          ami           = var.ami
          instance_type = var.instance_type
          subnet_id     = var.subnet_id
          
          tags = {
              Name = "Main EC2"
          }
      }
      EOF
      
      cat << 'EOF' > modules/ec2/variables.tf
      variable "subnet_id" {
          description = "The ID of the subnet where the EC2 will be launched"
          type        = string
      }
      
      variable "ami" {
          description = "AMI ID for the EC2 instance"
          type        = string
      }
      
      variable "instance_type" {
          description = "EC2 instance type"
          type        = string
      }
      EOF
      
      cat << 'EOF' > modules/ec2/outputs.tf
      output "ec2_public_ip" {
          description = "The public IP of the launched EC2 instance"
          value       = aws_instance.main.public_ip
      }
      EOF
      

リソースのデプロイと削除

デプロイ

  1. Terraform初期化

    terraform init
    #または
    terraform init -reconfigure
    
  2. 以下のコマンドで計画を作成し、prod.tfvars を適用する。

    terraform plan -out=plan.out -var-file=env/dev.tfvars
    
  3. 出力例: `Plan

: 3 to add, 0 to change, 0 to destroy.`
4. 実際にリソースを作成。

terraform apply plan.out

削除

  1. リソースを削除するコマンド。

    terraform destroy -var-file=env/dev.tfvars
    
  2. 出力例: Plan: 0 to add, 0 to change, 3 to destroy.

参考

Docs overview | hashicorp/aws | Terraform | Terraform Registry

入門 Terraform Module

Terraformのmoduleとoutput | DevelopersIO

Terraform ベストプラクティスを整理してみました。 | DevelopersIO

[Japanese] ベストなTerraformディレクトリ構成を考察してみた - YouTube

Discussion