nazolabo

フリーランスのWebエンジニアが近況や思ったことを発信しています。

Terraform AWS modulesでざっくりAWSインフラを作る

https://github.com/terraform-aws-modules には、TerraformですぐにAWSリソースを立ち上げるためのModuleがいくつか存在します。

VPCの作成

terraform-aws-vpcでは、主に以下のリソースを作ってくれます。オプションでNATとかも用意してくれます。

module "vpc" {
  source = "terraform-aws-modules/vpc/aws"

  name = "test"
  cidr = "10.0.0.0/16"

  azs             = ["ap-northeast-1a", "ap-northeast-1c", "ap-northeast-1d"]
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
  public_subnets  = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]

  enable_nat_gateway = false
  enable_vpn_gateway = false
}

ALBの作成

terraform-aws-albでは、主に以下のリソースを作ってくれます。

Security Group は作ってくれないので、自前で用意しましょう。

resource "aws_security_group" "alb" {
  name        = "alb"
  description = "alb"
  vpc_id      = module.vpc.vpc_id
}

module "alb" {
  source  = "terraform-aws-modules/alb/aws"
  version = "~> 5.0"

  name = "test"

  load_balancer_type = "application"

  vpc_id          = module.vpc.vpc_id
  subnets         = module.vpc.public_subnets
  security_groups = [aws_security_group.alb.id]

  target_groups = [
    {
      name             = "test"
      backend_protocol = "HTTP"
      backend_port     = 80
      target_type      = "ip"
      deregistration_delay = 10
    }
  ]

  http_tcp_listeners = [
    {
      port               = 80
      protocol           = "HTTP"
      target_group_index = 0
    }
  ]
}

ACM

terraform-aws-acmでは、ACM証明書を一発で作ってくれます。これは定型フォーマットなので、そのまま利用して問題ないでしょう。(手元にRoute53管理のドメインがなかったので試してはいません)

module "acm" {
  source  = "terraform-aws-modules/acm/aws"
  version = "~> v2.0"

  domain_name  = "my-domain.com"
  zone_id      = "Z2ES7B9AZ6SHAE"

  subject_alternative_names = [
    "*.my-domain.com",
    "app.sub.my-domain.com",
  ]

  tags = {
    Name = "my-domain.com"
  }
}

SNSのSlack通知

terraform-aws-notify-slackを使うと、SNSトピックをSlackに通知させるやつも簡単にTerraformで管理することが可能です。おそらくこれが一番使うのではないでしょうか。

使い方も簡単で、よくあるCloudWatch AlarmをSlackに通知するのは以下の書き方で実装できます。(手元に通知するものがなかったので試していません)

  
provider "aws" {
  region = "eu-west-1"
}

resource "aws_kms_key" "this" {
  description = "KMS key for notify-slack test"
}

# Encrypt the URL, storing encryption here will show it in logs and in tfstate
# https://www.terraform.io/docs/state/sensitive-data.html
resource "aws_kms_ciphertext" "slack_url" {
  plaintext = "https://hooks.slack.com/services/AAA/BBB/CCC"
  key_id    = aws_kms_key.this.arn
}

module "notify_slack" {
  source = "../../"

  sns_topic_name = "slack-topic"

  slack_webhook_url = aws_kms_ciphertext.slack_url.ciphertext_blob
  slack_channel     = "aws-notification"
  slack_username    = "reporter"

  kms_key_arn = aws_kms_key.this.arn

  lambda_description = "Lambda function which sends notifications to Slack"
  log_events         = true

  tags = {
    Name = "cloudwatch-alerts-to-slack"
  }
}

resource "aws_cloudwatch_metric_alarm" "LambdaDuration" {
  alarm_name          = "NotifySlackDuration"
  comparison_operator = "GreaterThanOrEqualToThreshold"
  evaluation_periods  = "1"
  metric_name         = "Duration"
  namespace           = "AWS/Lambda"
  period              = "60"
  statistic           = "Average"
  threshold           = "5000"
  alarm_description   = "Duration of notifying slack exceeds threshold"

  alarm_actions = [module.notify_slack.this_slack_topic_arn]

  dimensions = {
    FunctionName = module.notify_slack.notify_slack_lambda_function_name
  }
}

https://github.com/terraform-aws-modules/terraform-aws-notify-slack/blob/master/examples/cloudwatch-alerts-to-slack/main.tf

まとめ

公式とはいえ外部にあるmoduleだと、例えば最新の機能を入れたい場合にmoduleの反映を待たないといけないですし、そういう理由以外でもカスタマイズすることが難しく、また、moduleが勝手にアップデートされることが嬉しくないことも多いため、実際に使うのであればローカルにmoduleまるごどcloneして利用するのがいいのではないでしょうか。

SNSのSlack通知やACMに関してはほぼそのまま使っても問題ないと思います。

今はVPC一通りとALBがあればECS on Fargateでクラスタを作ればサービスを上げられるので(DBとかは別にして)、Terraformで管理したいけど書き方が難しいという場合は使ってみるのもありなのではないでしょうか(そんなに難しくないですが…)。