開発日報

窓際エンジニアの開発備忘。日報は嘘です。

【連載】terraform によるAWS環境構築入門 第5回 ~ ロードバランサの作成 ~

はじめに

この記事ではterraformを用いてロードバランサーを作成してみましょう。

連載記事一覧

本連載での使用技術

  • AWS
  • Docker
  • VPC
  • ECS(fargate)
  • ELB
  • IAM
  • Route53
  • RDS
  • ElastiCache
  • codexxx

1. アプリケーションロードバランサ定義

ALB定義

最初にアプリケーションロードバランサーを以下のように定義してみましょう。

# ALBの定義
resource "aws_lb" "example" {
  name                       = "example"
  load_balancer_type         = "application"
  internal                   = false
  idle_timeout               = 60
  enable_deletion_protection = true

  subnets = [
    aws_subnet.public_0.id,
    aws_subnet.public_1.id,
  ]

  access_logs {
    bucket  = aws_s3_bucket.alb_log.id
    enabled = true
  }

  security_groups = [
    module.http_sg.security_group_id,
  ]
}

・「internal」でALBがVPC内部向けなのか、インターネット向けなのか指定します。今回は外部向けなのでfalseにします。

・「enable_deletion_protection」を trueにすると削除保護が有効になります。本番環境では誤って削除しないよう有効にしておきましょう。

・ALB が所属するサブネットを「subnetsて」゙指定します。2つのサブネットを指定しクロスゾーン負荷分散を実現します。

セキュリティグループ

セキュリティグループを以下のように定義します

# ALB用のセキュリティグループ定義
module "http_sg" {
  source      = "./security_group"
  name        = "http-sg"
  vpc_id      = aws_vpc.example.id
  port        = 80
  cidr_blocks = ["0.0.0.0/0"]
}

リスナー

リスナーでどのポートのリクエストを受け付けるか設定します。リスナーはALBに 複数アタッチできます

# ALBリスナーの定義
resource "aws_lb_listener" "http" {
  load_balancer_arn = aws_lb.example.arn
  port              = "80"
  protocol          = "HTTP"

  default_action {
    type = "fixed-response"

    fixed_response {
      content_type = "text/plain"
      message_body = "これは『HTTP』です"
      status_code  = "200"
    }
  }
}

リスナーは複数のルールを設定して異なるアクションを実行できます。
いずれのルールにも合致しない場合はdefault_actionの定義内容が実行されます

  • forward - リクエストを別のターゲットグループに転送
  • fixed-response - 固定のHTTPレスポンスを応答
  • redirect - 別のURLにリダイレクト

上記では固定のHTTPレスポンスを設定しています。

2. リクエスフォワーディング

ターゲットグループ

ALBがリクエストをフォワードする対象を「ターゲットグループ」と呼び以下のように定義します。

# ターゲットグループ
resource "aws_lb_target_group" "example" {
  name                 = "example"
  vpc_id               = aws_vpc.example.id
  target_type          = "ip"
  port                 = 80
  protocol             = "HTTP"
  deregistration_delay = 300

  health_check {
    path                = "/"
    healthy_threshold   = 5
    unhealthy_threshold = 2
    timeout             = 5
    interval            = 30
    matcher             = 200
    port                = "traffic-port"
    protocol            = "HTTP"
  }

  depends_on = [aws_lb.example]
}
  • 今回は、次章のECSで使用するインスタンスがfargateなので、「target_type」をipにします。
  • ターゲットグループに ipを指定した場合はさらに、vpc_id、port、protocolを設定します。
  • アプリケーションロードバランサとターゲットグループを、次章で登場するECSサービスと同時に作成するとエラーになります。そこで「depends_on」で依存関係を制御し、エラーを回避します。

リスナールール

ターゲットグループにリクエストをフォワードするリスナールールを作成します。

# リスナールール
resource "aws_lb_listener_rule" "example" {
  listener_arn = aws_lb_listener.http.arn
  priority     = 100

  action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.example.arn
  }

  condition {
    field  = "path-pattern"
    values = ["/*"]
  }
}
  • リスナールールは複数定義でき、優先順位を「priority」で設定します。数字が小さいほど優先順位が高いです。フォルトルールはもっとも優先順位が低いです。
  • 「action」で、フォワード先のターゲットグループを設定します。
  • 条件を「condition」で設定します。

3. まとめ(最終成果物の作成)

以上の解説をまとめて、最終成果物を作成しましょう。 フォルダ構成は以下の通り。 今回新しくlb.tfが追加になります。

exaple
 |
 |--- iam_role
 |    |___ main.tf
 |
 |--- security_group
 |    |___ main.tf
 |
 |--- lb.tf (新)
 |
 |--- main.tf (変更)
 |
 |--- network.tf
 |
 |___ S3.tf

まず、「main.tf」にセキュリティーグループを追記しましょう。

# ALB用のセキュリティグループ定義
module "http_sg" {
  source      = "./security_group"
  name        = "http-sg"
  vpc_id      = aws_vpc.example.id
  port        = 80
  cidr_blocks = ["0.0.0.0/0"]
}

次に、「lb.tf」に以下の内容を記述し、ロードバランサーとその周辺設定を定義しましょう。

# ALBの定義
resource "aws_lb" "example" {
  name                       = "example"
  load_balancer_type         = "application"
  internal                   = false
  idle_timeout               = 60
  enable_deletion_protection = true

  subnets = [
    aws_subnet.public_0.id,
    aws_subnet.public_1.id,
  ]

  access_logs {
    bucket  = aws_s3_bucket.alb_log.id
    enabled = true
  }

  security_groups = [
    module.http_sg.security_group_id,
  ]
}

# ALBリスナーの定義
resource "aws_lb_listener" "http" {
  load_balancer_arn = aws_lb.example.arn
  port              = "80"
  protocol          = "HTTP"

  default_action {
    type = "fixed-response"

    fixed_response {
      content_type = "text/plain"
      message_body = "これは『HTTP』です"
      status_code  = "200"
    }
  }
}

# ターゲットグループ
resource "aws_lb_target_group" "example" {
  name                 = "example"
  vpc_id               = aws_vpc.example.id
  target_type          = "ip"
  port                 = 80
  protocol             = "HTTP"
  deregistration_delay = 300

  health_check {
    path                = "/"
    healthy_threshold   = 5
    unhealthy_threshold = 2
    timeout             = 5
    interval            = 30
    matcher             = 200
    port                = "traffic-port"
    protocol            = "HTTP"
  }

  depends_on = [aws_lb.example]
}

# リスナールール
resource "aws_lb_listener_rule" "example" {
  listener_arn = aws_lb_listener.http.arn
  priority     = 100

  action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.example.arn
  }

  condition {
    field  = "path-pattern"
    values = ["/*"]
  }
}

output "alb_dns_name" {
  value = aws_lb.example.dns_name
}

4. 実行

まずはinitしましょう。これをやらないと、モジュールの呼び出しができません。

$ terraform init

実行計画の確認。前回にも書きましたが、破壊的な変更が入っていないか入念に確認しましょう。

$ terraform plan

実行。実行されたら、AWSの管理画面から確認しましょう。
うまくいっていればIAMページ左上の「Search IAM」のフォームに「describe-regions-for-ec2」と入力て検索ができるはずです。

$ terraform apply