YOUTRUSTにおけるTerraformによるインフラ構成管理

こんにちは。CTOのzoo(YOUTRUST/X)です。

先日、人生で初めてリゾットを作りました。 想像以上に美味しく作ることができ、パスタ作りだけでなく、リゾット作りにもハマりそうです。

チーズリゾットと土佐甘とう

前回の記事(YOUTRUSTのインフラの全体像 - YOUTRUST Tech Blog)では、インフラの全体像を紹介しました。

YOUTRUSTでは、それらのインフラを管理するためにTerraformを用いています。 そこで、今回の記事では、YOUTRUSTのTerraformの使い方を紹介します。

インフラ環境

YOUTRUSTのサービスは主にAWSを用いて提供されています。 AWSでは、Production環境、Sandbox環境、Development環境を構築しており、それぞれの環境に対応するAWSアカウントがあります。

Sandbox環境は、インフラ構成の変更のテストをするための環境です。 そのため、Production環境とSandbox環境のインフラ構成は、ほぼ同じとなっております。リソースのスペックとアクセスの設定周りが少し異なります。

この辺りに関しては、前回のブログにも書きましたので、そちらも参照していただければと思います。

Terraformの構成

ディレクトリ構成は以下のようになっています。

.
├── components
│   ├── backend
│   ├── bastion
│   ├── chatbot_alarm
│   ├── data_platform
│   ├── deployment
│   ├── health_dashboard_notification
│   ├── iam
│   ├── network
│   ├── opensearch
│   ├── security
│   ├── tfstate_backend
│   └── webapp
└── environments
    ├── prod          # Production環境用
    └── sandbox       # Sandbox環境用

GitHubレポジトリ

Sandbox環境で動作確認を行い、Production環境に適用する、という想定のため、Sandbox環境とProduction環境のTerraformコードは、同一のGitHubレポジトリで管理しています。 Development環境は、それらとは全く異なる構成のため、別レポジトリでTerraformコードを管理しています。

componentsとenvironments

機能単位でcomponentを作成し、それをenvironments/prod/main.tfもしくはenvironments/sandbox/main.tfから使うようにしています。 例えば、backendにはデータストア関連、data_platformにはデータ分析関連、opensearchにはOpenSearch関連のリソースがまとめられています。

現在はprodとsandboxの2環境しかなく、それぞれのmain.tfから呼び出しているcomponentは同じですが、負荷試験環境やQA環境を作る際には、必要なcomponentのみを呼び出すようになると思います。

具体例

opensearchの中身を少し見てみたいと思います。

opensearch
├── alb.tf
├── cloudwatch_alerm.tf
├── iam.tf
├── lambda
│   ├── bootstrap.js
│   └── bootstrap.zip
├── lambda.tf
├── main.tf
├── outputs.tf
├── s3.tf
└── variables.tf

opensearchの中には上記のようなファイルが含まれています。 alb.tfcloudwatch_alerm.tfiam.tflambda.tfmain.tfs3.tfで必要なリソースを定義しています。OpenSearchのリソース自体は、main.tfの中で定義しています。

variables.tfは変数定義、outputs.tfは他のモジュールに渡したい値の出力に使っています。 lambdaディレクトリは少し特殊なのですが、lambdaの初期ソースコードを管理するのに使っています。

以下は、main.tfの一部を抜粋したものです。環境によらず固定したい設定は値を直接記述しています。バージョンやセキュリティの設定など、多くのものが固定された値になります。

一方で、インスタンスタイプやネットワークに関する設定は、環境ごとに変更したいため、変数を受け取るようにしています。

resource "aws_opensearch_domain" "opensearch" {
  domain_name    = "youtrust-${var.env}-main"
  engine_version = "OpenSearch_2.5"

  cluster_config {
    instance_type          = var.opensearch_instance_type
    instance_count         = 3
    zone_awareness_enabled = true
    zone_awareness_config {
      availability_zone_count = length(var.opensearch_subnet_ids)
    }
  }

  ebs_options {
    ebs_enabled = true
    volume_size = 30
  }

  vpc_options {
    subnet_ids         = var.opensearch_subnet_ids
    security_group_ids = [var.security_group_id]
  }

  advanced_security_options {
    enabled                        = true
    anonymous_auth_enabled         = false
    internal_user_database_enabled = true
    master_user_options {
      master_user_name     = aws_ssm_parameter.opensearch_dashboard_master_user_id.value
      master_user_password = aws_ssm_parameter.opensearch_dashboard_master_user_password.value
    }
  }
  .
  .
  .

# 以下省略

上記のcomponentをenvironments/prod/main.tfenvironments/sandbox/main.tfから呼び出して利用します。

以下は、Production環境、Sandbox環境それぞれのmain.tfOpenSearchを構築する部分の抜粋です。 Production環境とSandbox環境で差分があるところだけを渡していることが分かります。

environments/prod/main.tf

module "opensearch" {
  source           = "../../components/opensearch"
  ssm_param_prefix = "/Prod/OpenSearch/Main"
  vpc_id           = module.network.vpc_id

  env                                 = local.env
  opensearch_instance_type            = "c6g.large.search"
  opensearch_subnet_ids               = [module.network.private_opensearch1_subnet_id, module.network.private_opensearch2_subnet_id, module.network.private_opensearch3_subnet_id]
  security_group_id                   = module.network.opensearch_security_group_id
  auto_tune_disired_state             = "ENABLED"
  auto_tune_maintenance_schedule_cron = "cron(0 19 ? * FRI *)" // # AM 4:00 JST on Friday
  auto_tune_maintenance_start_at      = "2023-04-29T20:00:00Z" // インスタンスサイズなどの変更を行った時は、この日付を未来の日付に変更しないと Apply に失敗します。
  sns_topic_arn_for_cloudwatch_alarm  = module.chatbot_alarm.sns_topic_arn_for_cloudwatch_alarm
  alb_subnet_ids                      = [module.network.public1_subnet_id, module.network.public2_subnet_id]
  alb_security_group_ids              = [module.network.opensearch_dashboard_alb_security_group_id]
  alb_target_ips                      = []
  dashboard_domain                    = local.opensearch_dashboard_domain
}

environments/sandbox/main.tf

module "opensearch" {
  source           = "../../components/opensearch"
  ssm_param_prefix = "/Sand/OpenSearch/Main"
  vpc_id           = module.network.vpc_id

  env                                = local.env
  opensearch_instance_type           = "t3.small.search"
  opensearch_subnet_ids              = [module.network.private_opensearch1_subnet_id, module.network.private_opensearch2_subnet_id, module.network.private_opensearch3_subnet_id]
  security_group_id                  = module.network.opensearch_security_group_id
  auto_tune_disired_state            = "DISABLED"
  auto_tune_maintenance_start_at     = "2023-05-24T15:00:00Z" // インスタンスサイズなどの変更を行った時は、この日付を未来の日付に変更しないと Apply に失敗します。
  sns_topic_arn_for_cloudwatch_alarm = module.chatbot_alarm.sns_topic_arn_for_cloudwatch_alarm
  alb_subnet_ids                     = [module.network.public1_subnet_id, module.network.public2_subnet_id]
  alb_security_group_ids             = [module.network.opensearch_dashboard_alb_security_group_id]
  alb_target_ips                     = []
  dashboard_domain                   = local.opensearch_dashboard_domain
}

余談ですが、ssm_param_prefix = "/Prod/OpenSearch/Main" に関しては、歴史的背景によりこのようになっているのですが、Production環境とSandbox環境で差分を持たせる必要はなく、さらに言えば持たせない方がよいので、いずれ修正したいと思っています。

Terraformの恩恵

Terraformの導入は1年半ほど前に行いました。そこから、インフラの構成管理はTerraformを用いて行っていますが、現在のところ、このディレクトリ構成において大きな問題はなく運用できています。

例えば、Terraform導入後にデータ分析関連のインフラ部分の整理を実施し、その際にdata_platformディレクトリができたのですが、迷うことなく追加することができました。 あるいは、一時的に必要なリソースにおいても、新たにディレクトリを追加して構築し、必要がなくなったらそのディレクトリを削除する、ということで対応ができています。

結果として、Terraformの恩恵を十二分に享受できていると考えています。 構成変更の動作確認をしやすくなった、変更履歴を追いやすくなった、などいろいろとあるのですが、構成変更のレビューができるようになったことが一番大きなメリットだと考えています。 特に弊社のようなフェーズですと、副業としていろいろと手伝ってもらうことも多いのですが、インフラ構成の変更もコードレビューができるため、アプリケーションの開発と同様の感覚でお願いすることができています。

まとめ

YOUTRUSTにおけるTerraformのディレクトリ構成を中心に紹介しました。 より詳細に知りたいという方は、今後開かれる弊社エンジニアイベントにぜひ参加いただければと思います。

YOUTRUSTでは絶賛エンジニアを募集中です!! ちょっとお話してみたい、でも大丈夫です! みなさまのご応募、お待ちしております! herp.careers