Terraformを用いた開発環境構築について

# Terraformを用いた開発環境構築について

## 前提

・私が担当しているサービスでは、バックエンドにAWSを利用している
・Terraformについてどういったものなのか理解している

## 概要

・サービスの開発環境を構築する際に使用しているTerraformについて記載をしている

## 利用することのメリット
* Terraformを用いてIaCを実現しており、他メンバーが改修する際にすぐに対応できるようにもしている
* 新たに開発メンバーが増えた時も構築したソースコードを再利用することで、素早く開発環境を構築することができるようになった
* Terraformを利用する前は構築ドキュメントもなく、もともと作成されていた開発環境を確認しながら作成をしていましたが、構築時間の短縮が実現できた
* インフラ構築をソースコード化しているので、ソースコードを実行させることで対応ができるのでヒューマンエラーが軽減されるようになった
* ソースコード自体をバージョン管理しているので、特定のバージョンで不具合などを起こしても即座に前のバージョンに戻して以前の環境に戻すことができる

## 利用することのデメリット

* Terraformの知識が必要なため、環境を構築できるメンバーが限られる
* AWSを構築するという作業にプラスして、Terraformの構築作業が発生するため、初期構築時間が増大する  
  ただ、開発環境のように複数作成する場合は最終的にTerraformを利用した方が時短につながるハズ・・・

## 詳細

### Terraformパッケージ構成

```
.
├── developers
│   └ ＜開発者毎に実行するmain.tfを保持しているディレクトリ＞ ※ ここから開発者毎に異なるパラメータをモジュールに渡している
├── infrastructure
│   └ <開発環境共通で利用するリソースを構築するmain.tfを保持しているディレクトリ> ※ alb, lambda etc...
└── shared
    └── modules
        ├── assemble
        │   └── developenvironment ※ 開発環境を構築するリソースのモジュールを呼び出すモジュール。各AWSリソース依存性を解決させるために存在している
        ├── develop                ※ 「assemble」ディレクトリから呼び出されるAWSリソースを構築するスクリプトを記載している
        │   ├── acm
        │   ├── alb
        │   ├── auto_scaling
        │   ├── cognito
        │   │   └── resource
        │   ├── iam
        │   │   ├── role
        │   │   └── user
        │   ├── launch_template
        │   ├── rds
        │   ├── route53
        │   ├── s3
        │   ├── security_group
        │   └── sqs
        ├── infrastructure          ※ 「infrastructure」ディレクトリから呼び出される、AWSリソースを構築するスクリプトを記載している
        │   ├── acm
        │   ├── alb
        │   ├── event_bridge
        │   ├── iam
        │   │   ├── policy
        │   │   ├── role
        │   │   └── user_group
        │   ├── lambda
        │   │   ├── dist
        │   │   └── src
        │   ├── security_group
        │   └── sns
        └── tfvars                   ※ terraform実行の際に共通で利用する変数の値を保持しているディレクトリ
            ├── core
            └── resource
                ├── allowip
                ├── kms
                ├── lambda_function
                └── policy
```

### 特徴

1. 開発環境で共通化できる部分についてはモジュール化を行い、再利用できるようにしている

2. 構築前までは、実行時変数を「-var-file」オプションを利用していたのですが、<br>毎回指定するのが面倒だったためモジュール化を行い、実行時に指定しなくても<br>自動的に呼び出されるように定義を行っている

### 環境を構築する際のエントリーポイント

```
provider "aws" {
  assume_role {
    role_arn = ""
  }
  region = "ap-northeast-1"
  default_tags {
    tags = {
      Developer_name = ""
      CmBillingGroup = ""
    }
  }
}

terraform {
  backend "s3" {
    // ここに変数は使えない・・・つらみ・・・
    bucket = ""
    key    = ""
    region = "ap-northeast-1"
  }
  required_version = ""
  required_providers {
    aws = {
      source  = ""
      version = ""
    }
  }
}

module "tfvars_core" {
  source = "../../shared/modules/tfvars/core"
}

module "tfvars_kms" {
  source = "../../shared/modules/tfvars/resource/kms"
}

module "tfvars_lambda_function" {
  source = "../../shared/modules/tfvars/resource/lambda_function"
}

locals {
  environment         = "developer_name
  host                = "${local.environment}.devel"
  subject_domain_name = "${local.host}.${module.tfvars_core.domain}"
  base_domain_name    = "*.${local.subject_domain_name}"
  private_domain_name = "${local.environment}.${module.tfvars_core.private_zone_name}"
}

module "develop_environment" {
  source = "../../shared/modules/assemble/developenvironment"

  base_domain_name                                = local.base_domain_name
  environment                                     = local.environment
  host                                            = local.host
  private_domain_name                             = local.private_domain_name
  subject_domain_name                             = local.subject_domain_name
  rds_password                                    = var.rds_password
  ip_address_list_for_developer                   = var.ip_address_for_developer
  project                                         = module.tfvars_core.project
  vpc_name                                        = module.tfvars_core.vpc_name
  use_AZ                                          = module.tfvars_core.use_AZ
  developer_alb_name                              = module.tfvars_core.developer_alb_name
  domain                                          = module.tfvars_core.domain
  account_id_on_devel_environment                 = module.tfvars_core.account_id_on_devel_environment
  private_zone_name                               = module.tfvars_core.private_zone_name
  place2_dev_auto_scaling_handler_target_tag_name = module.tfvars_core.place2_dev_auto_scaling_handler_target_tag_name
  lambda_user_pool_custom_message_sender_arn      = module.tfvars_lambda_function.cognito_user_pool_custom_message_sender_function_arn
  kms_key_arn                                     = module.tfvars_kms.kms_key_arn_for_cognito_authorization_code
  topic_arn                                       = module.tfvars_core.topic_arn_for_auto_scaling
  user_id_for_slack                               = local.user_id_for_slack
  launch_template_user_data                       = <<-EOF
  EOF
}
```

### 特徴

1. コストを意識して、コスト配分タグを定義するためにデフォルトタグを利用して「コスト配分タグ」を定義している
2. AWSリソース（起動テンプレート and Auto Scaling）を利用してインスタンス構築のテンプレート化、<br>及びインスタンス構築時のインスタンスタイプをスポットインスタンスに限定していることでコスト削減を行っている

### Terraform実行後、開発環境インフラ構成図イメージ

![personal_development_environment.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2209596/b4e15204-8692-192f-826f-b8b6a09743f4.png)

### 次回以降の投稿について
* コストカット周り
* 各AWSリソースをもう少し深堀しての説明 etc...