5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

作りながら覚えるTerraform入門(6) - ELB編

Last updated at Posted at 2021-06-09

作りながら覚えるTerraform入門シリーズの第6回です。
今回はロードバランサを作成して独自ドメインでHTTPS接続できるようにしていきます。

作りながら覚えるTerraform入門シリーズ
  1. インストールと初期設定
  2. 基本編
  3. VPC編
  4. EC2編
  5. Route53 + ACM編
  6. ELB編 => 今回はコチラ
  7. RDS編

今回の学習ポイントは・・・
Terraform観点だともう基本的なポイントはご紹介したので特にないのですが、強いて挙げれば

  • toset関数
  • for_each

でしょうか。
あと、これまでに作成してきたリソースが組み合わさって繋がるので最後の接続確認が気持ちいい。笑

ELBの作成

まず、アプリケーションロードバランサ(ALB)を作成します。
elb.tfを作成して、以下のコードを貼り付けます。

elb.tf
################################
# ELB
################################
# ELB
resource "aws_lb" "alb" {
  name                       = "${var.prefix}-alb"
  load_balancer_type         = "application"
  internal                   = false
  idle_timeout               = 60
  enable_deletion_protection = false

  subnets = [
    aws_subnet.public_subnet_1a.id,
    aws_subnet.public_subnet_1c.id
  ]

  security_groups = [
    aws_security_group.elb_sg.id
  ]
}

aws_lbでロードバランサを作成します。
load_balancer_typeは現時点で次の3種類があります。

  • application
  • network
  • gateway

コンソール画面で作成するときに見るアレですね。
ちなみに、aws_elbを使うとClassic Load Balancerを作成できます。紛らわしいので念のため。
5A153436-5472-4C59-98A3-E4E6F58B08A0.png

インターネット向けのELBを作成する場合はinternal = falseにします。
subnetsにはパブリックサブネットのIDを、security_groupsには事前に作成してあるELB向けのセキュリティグループのIDを指定します。

ターゲットグループの作成

次に、ターゲットグループを作成します。
elb.tfに以下のコードを追加します。

elb.tf
# Target group
resource "aws_lb_target_group" "alb_tg" {
  name                 = "${var.prefix}-alb-tg"
  target_type          = "ip"
  vpc_id               = aws_vpc.vpc.id
  port                 = 80
  protocol             = "HTTP"
  deregistration_delay = 300

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

resource "aws_lb_target_group_attachment" "alb_tg" {
  for_each         = toset(["10.0.11.11", "10.0.12.11"])
  target_group_arn = aws_lb_target_group.alb_tg.arn
  target_id        = each.key
}

まず、aws_lb_target_groupでターゲットグループを作成します。
target_typeipにしていますが、インスタンスIDを使う場合はinstanceを指定します。(デフォルトがinstanceなので省略できます)

ターゲットグループにインスタンスを登録するにはaws_lb_target_group_attachmentで関連付けます。ここが少しハマったのですが、、

直感的には、target_idには配列でIPを渡したいのですが、文字列にせよと怒られます。

Error: Incorrect attribute value type
│ 
│   on elb.tf line 52, in resource "aws_lb_target_group_attachment" "alb_tg":
│   52:   target_id        = ["10.0.11.11", "10.0.12.11"]
│ 
│ Inappropriate value for attribute "target_id": string required.

for_eachを使って配列を回そうとしても、mapかsetでないとダメといわれます。
for_eachには配列を渡すことができないんです。。

 Error: Invalid for_each argument
│ 
│   on elb.tf line 50, in resource "aws_lb_target_group_attachment" "alb_tg":
│   50:   for_each         = ["10.0.11.11", "10.0.12.11"]
│ 
│ The given "for_each" argument value is unsuitable: the "for_each" argument must be a map, or set of strings, and you have provided a value of type tuple.

ということで、toset 関数を使って、set型に変換しています。
恥ずかしながら、setという型を初めて知ったのですが、

  • 重複した要素がない
  • 要素に順番がない

という特徴があるみたいです。tosetで変換すると重複が取り除かれます。

terraform console

> toset(["10.0.11.11", "10.0.12.11", "10.0.12.11"])
toset([
  "10.0.11.11",
  "10.0.12.11",
])

for_eachで渡した配列もどきのリストはeach.keyで読み込むことができます。
今回は関係ありませんが、もし、mapを渡した場合はeach.keyeach.valueでキーと値をそれぞれ読み込むことができます。

リスナーの作成

続いて、リスナーを作成します。
elb.tfに以下のコードを追加します。

elb.tf
# Listener
resource "aws_lb_listener" "http" {
  load_balancer_arn = aws_lb.alb.arn
  port              = "80"
  protocol          = "HTTP"

  default_action {
    type = "redirect" # forwad / fixed-response / redirect

    redirect {
      protocol    = "HTTPS"
      port        = "443"
      host        = "#{host}"
      path        = "/#{path}"
      query       = "#{query}"
      status_code = "HTTP_301"
    }
  }
}

resource "aws_lb_listener" "https" {
  load_balancer_arn = aws_lb.alb.arn
  port              = "443"
  protocol          = "HTTPS"
  certificate_arn   = aws_acm_certificate.public.arn
  ssl_policy        = "ELBSecurityPolicy-2016-08"

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.alb_tg.arn
  }
}

aws_lb_listenerでHTTPとHTTPSのリスナーを追加しています。
portprotocolの組み合わせで受付ポートとプロトコルを、default_actionでアクションを定義します。

HTTPのリスナーではdefault_actionのタイプをredirectにして、HTTPSにリダイレクトするようにしています。redirect {}の中にはリダイレクト時に書き換える内容を指定します。

protocolがHTTP → HTTPSに、portが80 → 443に書き換えられますが、残りのホスト名、パス、クエリは変更を加えずデフォルトを利用するという意味になります。status_code = "HTTP_301"は「完全に移動」を表します。

コンソール画面で以下のように入力した場合と同じですね。
963417EE-621B-4578-AFE6-7756DE1E918F.png

HTTPSのリスナーではdefault_actionのタイプをforward にして、先に作成したターゲットグループに転送するようにしています。また、前回のRoute53 + ACM編で作成したパブリック証明書をここで関連付けします。

エイリアスレコードの登録

最後に独自ドメインとELBを紐付けるエイリアスレコードを登録します。
route53.tfに追加したくなるかもしれませんが、ここは関連するリソースのライフサイクルに合わせてelb.tfに追加します。

elb.tf
################################
# Route 53 (Alias record)
################################
resource "aws_route53_record" "alb" {
  name    = "www.${aws_route53_zone.public.name}"
  zone_id = aws_route53_zone.public.zone_id
  type    = "A"

  alias {
    name                   = aws_lb.alb.dns_name
    zone_id                = aws_lb.alb.zone_id
    evaluate_target_health = true
  }
}

レコードの名前は独自ドメインの頭にwww.を付けた形にしていますが、ACMをワイルドカード証明書にしてあるのでapp.とかでも構いませんし、何も付け加えずにaws_route53_zone.public.nameとしてネイキッドドメインで接続する形にしてもOKです。ネイキッドドメインを登録できるのは、エイリアスレコードならではの特徴ですね。

ELB編のコードは以上です。
terraform applyを実行して、もろもろ作成されていることを確認しましょう。

問題なければ独自ドメインでアクセスしてみましょう。
鍵アイコンをクリックして証明書を確認するとAmazon発行のものであることがわかります。
また、ELBには2台のEC2がぶら下がっているので、ブラウザを更新するたびにweb-01web-02が交互に切り替わるかと思います。(ラウンドロビン)
image.png

ブラウザのURLをhttpに変更してもリダイレクトされることが確認できますが、curlコマンドでも確認することができます。Locationを見るとプロトコルとポートが書き換わっていることがわかります。

curl -I http://www.example.com
HTTP/1.1 301 Moved Permanently
Server: awselb/2.0
Date: Wed, 09 Jun 2021 04:59:29 GMT
Content-Type: text/html
Content-Length: 134
Connection: keep-alive
Location: https://www.example.com:443/

今回は以上です。次回はRDS編ということで、MySQLのRDSをマルチAZ構成で構築してみたいと思います!

参考リンク

5
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?