頑張るときはいつも今

自称エンジニアのゴリラです。日々精進。

【AWS】TerraformでマルチAZ構成のインフラを構築をやってみた(マルチAZ, RDS, ALB, AutoScaling)

こんにちは、駆け出しエンジニアです。 前回に引き続きAWSとTerraformの記事になります。 そろそろRoRとかVueの方を勉強していかないとまずいのではと焦っています。

何をやるか

前回同様に、AWSアソシエイトの勉強を継続しています。 自分の引き出しを増やしておきたいと思いどうせなら構築はTerraformでやってみようと四苦八苦中です。 今回は前回作成した構成をより冗長性が高い構成にしようという記事です。 (経緯)

得られた内容

  • 冗長性を高めるためのインフラ構成案
  • ELB、AutoScalingについての概要
  • RDSの概要
  • Terraformを利用した、マルチAZELB(Elastic Load Balancer)RDS(Relational Database Service)の構築

12月に作成したインフラの構成

  • 単一のAZに1つのVPCを作成
  • 作成したVPC内にパブリックサブネットとプライベートサブネットを1つずつ構築
  • パブリックサブネット内に、Webサーバを想定したEC2インスタンスを1つ構築
  • プライベートサブネット内に、DBサーバを想定してEC2インスタンスを1つ構築
  • DBサーバには、EC2インスタンスからしトラフィックを受け取らないように、セキュリティグループを設定

f:id:wa_football_1120:20191222142939j:plain

W-Aにこれでもかというぐらい意に反した、我が道を行く構成になっています。

改善すべき点の洗い出し

冗長性を高めるための基本的な改善点しか思いついていません。

1点目 単一のAZインフラ構成

個人利用程度の小さなWebサービス(ブログなど)であれば問題がないのかもしれませんが、

単一のAZで構成されているためAZ自体が障害に見舞われた時に、サービスが全てダウンしてしまいます。

これはW-Aでいう信頼性を担保できていない改善点となるのではないでしょうか。

2点目 単一のEC2で稼働しているWebサーバ

トラフィック増加や予期せぬサービスダウンにより、Webサーバがダウンすることはリスクとして捉える必要があります。

先ほどの単一AZの改善点同様に、EC2も複数台による冗長な構成を作る必要があります。

実際のサービスでは複数台動いているWebサーバに対して、不可分散をしながら特定のインスタンスへアクセスが集中しないロードバランサが必要です。

3点目 自前でEC2に構築したDBサーバ

特殊な業務要件(ファイルシステムと連携する必要がある場合やミドルウェアをもっとカスタマイズしたいなど)の場合には、EC2上に自前で構築でもいいかもしれません。

今回は、このような業務要件はないことを想定して構築しますので、マネージドサービスを利用した方が、構築や運用の効率がよくなります。

改善策

上記の改善点に対する、改善案は表のようにまとめました。

VPC冗長化については今回は別ものとさせてください。

改善点 改善後の構成
単一AZのインフラ構成 マルチAZ構成をとる
単一のEC2で稼働しているWebサーバ 前段にロードバランサを配置。要求(リクエスト)に応じて水平方向のスケーリング(AutoScaling)
自前でEC2に構築したDBサーバ マネージドサービスのRDSを利用する

インフラ構成を図に示すと下記のようなイメージです。

まだまだシンプルで簡易的な構成ですが、入門編として見逃してください。

f:id:wa_football_1120:20200112173408j:plain

予備知識

今回の構成で新規に追加するELBAutoScalingRDSについて簡単にまとめていきます。

ELB

マネージド型のロードバランシングサービスです。

EC2と組み合わせて複数リソースへの不可分散やヘルスチェックができるようになります。

現状主要なELBとしてはALB(アプリケーションロードバランサ:レイヤ7で負荷分散)NLB(レイヤ4で負荷分散)がありますが、以降はALBを前提とした説明です。

特徴

  • 複数AZにまたがって、トラフィックの不可分散をすることができる

  • パブリックサブネット、プライベートサブネットどちらにも配置ができる

  • インスタンスのヘルスチェックを行い、異常と判定されたインスタンスに対してはリクエストを分散しない

  • マネージドサービスで、リクエスト量に応じてELB自体も自動的にスケーリングされる

主要な機能

  • ヘルスチェック

    • 指定したプロトコルポート番号パス失敗時のしきい値を条件に指定して、インスタンスが正常に動作しているかチェックする
    • しきい値を超えた場合には、インスタンスの状態を異常と判定し、自動的に負荷分散先から切り離す f:id:wa_football_1120:20200113161105j:plain
  • 負荷分散の方式

    • AZ間の負荷分散は、DNSラウンドロビン(DNSキャッシュされている場合、特定のAZにしかリクエストが飛ばない可能性がある)
    • AZ内の負荷分散は、Least Connection(コネクション数がもっとも少ないリソースへ飛ばす)
  • SSL Termination

    • ロードバランサ側でSSL認証を実施する機能
    • ロードバランサにSSL証明書を設定することで、クライアント~ロードバランサ間はHTTPSで、ロードバランサ~リソース間はHTTPで通信を流すことができる
      • いちいち、リソース1個ずつに対して証明書をダウンロードすることが不要になってくる
  • スティッキーセッション

    • セッションを保持するアプリケーションなどで、同一のユーザからきたリクエストを全て同じインスタンスに転送する
    • HTTPレスポンスにELBがCookieを埋め込んで、リクエストの転送先を固定する
  • Connection Draining

    • メンテなどで負荷分散先から登録を削除しているインスタンスや異常が発生したインスタンスに対してリクエストを転送しないようにする
      • ただし、処理中のリクエストについては、処理を続ける
  • X-forwardedヘッダーのサポート

    • ロードバランサを介したHTTPリクエストの場合、インスタンスからみたリクエスト元のIPアドレスは全てロードバランサとなってしまう
    • X-forwardedをHTTPヘッダーに付与して、実際のリクエスト元(クライアント)のIPアドレスを判別することができる

      X-Forwarded-Forとは、HTTPヘッダフィールドの1つであり、ロードバランサなどの機器を経由して  Webサーバに接続するクライアントの送信元IPアドレスを特定する際のデファクトスタンダードです。  クライアントの送信元IPアドレスの特定は、ロードバランサなどでクライアントの送信元IPアドレスが  変換された場合でも、HTTPヘッダに元のクライアントIPアドレスの情報を付加することで実現します。

Auto-Scaling

需要(トラフィック量)やリソースの障害発生時に、自動的にインスタンスの数を増減することができる機能。

前述のELBと併用して利用されるケースが多くなる。

利用するメリット

  • 可用性の向上

    • 繁忙期やピーク時間帯には、需要量に応じて自動的にインスタンスの数をスケールアウト(台数を増やす)ことができる
    • 逆に閑散期については、スケールイン(台数を減らす)こともできる
  • 耐障害性の向上

  • コスト効率の向上

    • 需要量に応じて、適切な量のインスタンスを立ち上げるため、ピーク時に備えた台数を常に稼働させておくよりもコストがかからなくなる

設定する項目

  • Auto-Scalingグループ

    • 立ち上げるインスタンスの最小数、最大数、希望する数(増減数)を指定する
    • 設定した最小数と最大数の間でインスタンスの数を増減させる
  • Auto-Scaling Configration

    • 起動するインスタンスの種類(インスタンスタイプやストレージサイズ、AMI)を設定する
    • セキュリティグループやキーペアもここで設定
  • Auto-Scaling Plan

    • どのようにスケール(台数を増やしたり減らしたりする)かを設定する。下記の方法を複数組み合わせることもできる。
      • 手動でのスケーリング
        • 事前にスケーリングする必要が分かっている(キャンペーンやユーザ告知)した場合には手動でスケーリングすることができる
        • Auto-Scalingグループの 最小数最大数希望する数を調整する
      • スケジュールに応じてスケーリング
        • ある一定時間(お昼休みなど)だけスケーリングさせるといった設定ができる
        • 予定アクションを定義することで実現する
    • 需要に応じてスケーリング
      • CloudWatchのCPU Utilizationを監視してしきい値を超えた場合といった設定ができる
      • ポリシーを定義することで実現する

リソース削除の設定

需要が減ったりすれば、余剰なインスタンスを終了(Terminate)する必要があります。 この時、どのインスタンスを削除するかについて設定することが可能です。

  • OldestInstance/NewestInstance
    • 作成されてから最も古い/新しいインスタンスから削除
      • 後からAuto-Scaling作成した場合、オリジナルのEC2(スケール時のクローン元)が削除される
  • OldestLaunch Configration
  • ClosestToNextInstanceHour
  • デフォルト設定
    • インスタンスを削除する対象のAZを選択
      • 最も多くのインスタンスが設置されているAZを選択
      • 同数の場合にはランダム
    • 対象のAZから削除対象のインスタンスを削除
      • OldestLaunch ConfigrationからClosetLaunch Configrationの順に削除対象を決めていく
      • 複数の削除候補がいる場合には、候補からランダムで選択

RDS

マネージドサービス型のリレーショナルDBサーバです。

パッチ適用といった運用業務が不要なりますが、VPC内に配置されるため可用性の確保は利用者側で設定が必要です。

また、OSのログインは不可であることから、DBサーバの細かい設定をした場合やNFS(Network File System)を利用するといったカスタマイズはできません。

代表的な仕組みとしてマルチAZ構成(マスタ/スレーブ構成)リードレプリカがある。

マルチAZ構成

1つのリージョン内の2つのAZにDBインスタンスを配置して、障害発生時やメンテナンス時に自動的にフェイルオーバさせる

マスタとスレーブでインスタンスを待機させていて、それぞれのインスタンスは同期レプリケーションされている

リードレプリカ

参照専用のDBインスタンスを配置されることができる(マスタのインスタンスと別AZにも配置ができる)

非同期レプリケーションであるため、更新された内容が即時反映されていない場合がある

Terraformによるコード実装

実際に予備知識は置いたということで、Terraformで実装していきたいと思います。

ディレクトリ構成は下記の通りです。

.
├── README.md
├── alb
│   ├── main.tf
│   └── output.tf
├── autoscaling
│   ├── main.tf
│   └── output.tf
├── config.tfvars
├── ec2
│   ├── main.tf
│   ├── output.tf
│   └── setup.sh
├── main.tf
├── network
│   ├── main.tf
│   └── output.tf
├── rds
│   ├── main.tf
│   └── output.tf
├── sg
│   ├── main.tf
│   └── output.tf
|── variables.tf

ソースの細かい説明は省くので、詳細はgitリポジトリにコードを挙げていますので参照ください。

以下、自分用の忘備録になるので、飛ばしてもらって大丈夫です。

VPC構築

基本的に前回作成したコードを流用します。

前回との変更点としては、マルチAZ構成に変更することがメインです。

実際にコードを見てもらった方が分かりやすいかと思います。

組み込み関数のlengthlookupelementを利用して、冗長な書き方にならないようにしました。

組み込み関数を全て説明してくれている記事がありました

例えばこんな感じで、変数でmapを使って複数のサブネットを作成しました。

######################################
# Varibales                          #
######################################
variable "vpc_parameter" {
    default = {
        vpc_subnets       = "10.0.0.0/16"
        public_subnets    = {
            "0" = "10.0.1.0/24",
            "1" = "10.0.2.0/24"
        },
        private_subnets   = {
            "0" = "10.0.5.0/24",
            "1" = "10.0.6.0/24"
        },
        availability_zones = {
            "0" = "ap-northeast-1a",
            "1" = "ap-northeast-1c"
        }
    }
}

######################################
# VPC                                #
######################################
resource "aws_vpc" "example_vpc" {
    cidr_block           = var.vpc_parameter.vpc_subnets
    enable_dns_support   = true # DNS名前解決をサポート
    enable_dns_hostnames = true # パブリックIPアドレスをもつインスタンスの名前解決を有効化

    tags = {
        Name = "Example"
    }
}

######################################
# Public Subnet                      #
######################################
resource "aws_subnet" "example_public" {
    vpc_id                  = aws_vpc.example_vpc.id
    count                   = length(var.vpc_parameter.public_subnets)
    cidr_block              = lookup(var.vpc_parameter.public_subnets     , count.index, "Not Found")
    availability_zone       = lookup(var.vpc_parameter.availability_zones, count.index, "Not Found")
    map_public_ip_on_launch = true

    tags = {
        Name = format("Example-VPC-Public-Subnet-%d", count.index)
    }
}

複数作成したリソースの出力を取得したい場合は、joinを使えば良さそうです。

配列要素をマージして1つの文字列として出力してくれます。

output "private_subnets_id" {
    value = join(",", aws_subnet.example_private.*.id)
}

output "public_subnets_id" {
    value = join(",", aws_subnet.example_public.*.id)
}

Security Group作成

プライベートサブネットに作成したRDS用のセキュリティグループに、NAT Gatewayのみ(2つのAZにそれぞれ1つずつ)をルールに加える必要がありました。

サブネット/32で指定したかったので、forを使って実現しています。

resource "aws_security_group_rule" "egress_all_rds" {
    type                     = "egress"
    from_port                = 0
    to_port                  = 0
    protocol                 = "tcp"
    cidr_blocks              = [for ip in local.nat_gateway_ips : "${ip}/32"]
    security_group_id        = aws_security_group.rds_sg.id
}

EC2作成

EC2は各AZのパブリックサブネットに1つずつ作る必要がありましたが、aws_instanceを2ブロック書くのは冗長になってしまいます。。

countを使って、複数のリソースを1つのブロックで書けるようにしました。

resource "aws_instance" "web_servers" {
    count                  = length(var.subnet_ips)
    ami                    = data.aws_ami.recent_amazon_linux_2.id
    instance_type          = var.instance_type
    key_name               = aws_key_pair.instance_ssh_key_pairs.id
    vpc_security_group_ids = [var.sg_id]
    subnet_id              = element(split(",", var.subnet_ids), count.index)

    tags                   = {
        Name = "Test ELB Web Server ${count.index}"
    }

    user_data = file("./ec2/setup.sh")

    depends_on             = [var.subnet_ids]
}

ただ、countを利用する際には、terraform planの段階で何個リソースを作成するか分かっていないければいけません。

別のモジュールで作成したリソースの個数は指定することができません。

下記のようなErrorが出てしまうことがあります。

The "count" value depends on resource attributes that cannot be determined
until apply, so Terraform cannot predict how many instances will be created.
To work around this, use the -target argument to first apply only the
resources that the count depends on.

今回のコードではcountの値にvar.subnet_ipsを利用しているのですが、これは事前にvariables.tfに定義している変数なので、繰り返す回数がすでに分かっている状態です。

ALB作成

まずは、ALBのアクセスログを保管するたhttps://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/load-balancer-access-logs.htmlめのBucketを作成しました。

S3のBucketポリシーを定義していく必要があります。参考

dataリソースを定義して、Bucketポリシーを外部リソースとして定義することができます。

################################################
# S3 bucket to writing access logs Settings    #
################################################
resource "aws_s3_bucket" "alb-logs-bucket" {
    bucket        = "turedure-alb-logs-bucket-test-one"
    acl           = "private"
    # For test
    force_destroy = true

    lifecycle_rule {
        enabled = true
        id      = "alb-log"
        prefix  = "alb-log/"

        transition {
            days          = 30
            storage_class = "STANDARD_IA"
        }
        transition {
            days          = 60
            storage_class = "GLACIER"
        }
        expiration {
            days          = 90
        }
    }
}

resource "aws_s3_bucket_public_access_block" "alb-logs-bucket" {
    bucket                  = aws_s3_bucket.alb-logs-bucket.id
    block_public_acls       = true
    block_public_policy     = true
    ignore_public_acls      = true
    restrict_public_buckets = true
}

resource "aws_s3_bucket_policy" "alb-logs-bucket-policy" {
    bucket = aws_s3_bucket.alb-logs-bucket.id
    policy = data.aws_iam_policy_document.alb_log.json

    depends_on = [aws_s3_bucket_public_access_block.alb-logs-bucket]
}

# Bucket Policy
data "aws_iam_policy_document" "alb_log"{
    statement {
        effect    = "Allow"
        actions   = ["s3:PutObject"]
        resources = ["arn:aws:s3:::${aws_s3_bucket.alb-logs-bucket.id}/*"]

        principals {
            type = "AWS"
            identifiers = ["582318560864"]
        }
    }
}

次にALBを作成していきます。

作成時に定義する必要があるリソースは下記です。

リソース名 説明
aws_lb ELBの本体。LBのタイプやセキュリティグループをアタッチする。
aws_lb_target_group LBのターゲットグループ。負荷分散するグループを定義する。
aws_lb_listener LBのリスナーを作成。ターゲットグループをアタッチしてルーティングをどのようにするかを設定する
aws_lb_target_group_attachment ターゲットグループとインスタンス(ECSの場合はコンテナ)を紐付ける

aws_lb

パラメータ名 説明 必須か?
name ALBの名前 No
internal trueであればInternal LB(プライベートサブネット用のLB) No
security_groups アタッチするセキュリティグループ No
subnets ALBを紐付けるサブネットID No
access_logs ELBのアクセスログの保存先 No
resource "aws_lb" "example_alb" {
    name               = "turedure-example-alb"
    internal           = false
    load_balancer_type = "application"
    security_groups    = [var.alb_sg_id]
    subnets            = local.public_subnets_list

    access_logs {
        bucket         = aws_s3_bucket.alb-logs-bucket.bucket
        enabled        = true
    }

    tags = {
        Name           = "Test-Alb"
        Environment    = "development"
    }

    # S3のアクセス許可が出るまでペンディング
    depends_on         = [aws_s3_bucket_policy.alb-logs-bucket-policy]
}

aws_lb_target_group

パラメータ名 説明 必須か?
name ターゲットグループの名前 Yes
port ターゲットグループがトラフィックを待ち受けるポート Yes
protocol ターゲットグループがトラフィックを待ち受けるプロトコル Yes
vpc_id ターゲットグループが所属するVPCのID Yes
deregistration_delay ELBが異常と判断してから実際にターゲットを登録解除するまでに待つ時間 No
health_check ヘルスチェックの設定 No
resource "aws_lb_target_group" "example_alb" {
    name                 = "turedure-example-target-group"
    port                 = 80
    protocol             = "HTTP"
    deregistration_delay = 300
    vpc_id               = var.vpc_id

    health_check {
        interval            = 30
        path                = "/index.html"
        port                = 80
        timeout             = 5
        unhealthy_threshold = 2
        matcher             = 200
    }
    depends_on          = [aws_lb.example_alb]
}

aws_lb_listener

今回は証明書などは発行していないく、HTTPでクライアントからリクエストが来る想定です。

パラメータ名 説明 必須か?
load_balancer_arn LBのARN Yes
port LBが待ち受けるポート Yes
protocol クライアント~LB間のプロトコル No
default_action LBがトラフィックを受けた際にどのように処理するか Yes
resource "aws_lb_listener" "example_alb" {
    load_balancer_arn  = aws_lb.example_alb.arn
    port               = "80"
    protocol           = "HTTP"
    default_action {
        target_group_arn = aws_lb_target_group.example_alb.arn
        type             = "forward"
    }
    depends_on         = [aws_lb_listener.example_alb]
}

aws_lb_target_group_attachment

パラメータ名 説明 必須か?
target_group_arn 紐づけるターゲットグループのARN Yes
target_id ターゲットグループに紐づけるインスタンスのID Yes
port ターゲットが待ち受けるポート番号 Yes

複数のインスタンスを紐付ける必要があったためcountで回しています。

resource "aws_lb_target_group_attachment" "example_alb" {
    count              = length(var.public_subnet_ips)
    target_group_arn   = aws_lb_target_group.example_alb.arn
    target_id          = element(local.instance_ids_list, count.index)
    port               = 80
    depends_on         = [aws_lb.example_alb]
}

Auto Scaling作成

|リソース名|説明| |aws_launch_configuration| Auto Scalingから作成されるインスタンスの起動設定| |aws_autoscaling_group| Auto Scalingグループ| |aws_autoscaling_policy| スケール(イン or アウト)の設定| |aws_cloudwatch_metric_alarm| CloudWatchとAutoScalingを連携させるためのアラート処理|

aws_launch_configuration

事前にAMIを作成済みであればここら辺の細かい設定が不要になると思います。

パラメータ名 説明 必須か?
name_prefix AMIの設定名(nameにすると、terraformで再作成できなくなる。) No
image_id AMIのID Yes
instance_type インスタンスタイプ Yes
key_name 作成したインスタンスに接続するためのキー名 No
security_groups アタッチするセキュリティグループ No
associate_public_ip_address 作成したインスタンスにパブリックIPアドレスをアタッチするか No
user_data インスタンスを作成する際に実行するスクリプト No
resource "aws_launch_configuration" "example_as_conf" {
    name_prefix                 = "webserver"
    image_id                    = var.ami_id
    instance_type               = var.instance_type
    key_name                    = var.key_name
    security_groups             = [var.sg_id]
    associate_public_ip_address = true
    user_data                   = file("./ec2/setup.sh")

    lifecycle {
        create_before_destroy   = true
    }
}

aws_autoscaling_group

パラメータ名 説明 必須か?
name_prefix グループ名 Yes
max_size インスタンスの最大数 Yes
min_size インスタンスの最小数 Yes
launch_configuration 起動するAMIの設定 No
vpc_zone_identifier インスタンスを配置するサブネットのID No
desired_capacity デフォルト(Auto Scaling起動時)のインスタンスの台数 No
health_check_grace_period インスタンスが起動してからヘルスチェックするまでの時間 No
health_check_type ヘルスチェックの方式(EC2単体かELBと連携するか) No
target_group_arns ターゲットグループのARN No
resource "aws_autoscaling_group" "example_asg" {
    name_prefix                 = "turedure-websv-v1"
    max_size                    = 4
    min_size                    = 1
    launch_configuration        = aws_launch_configuration.example_as_conf.name
    vpc_zone_identifier         = split(",", var.public_subnets_id)
    # Number of creating instance size when initialize auto scaling group
    desired_capacity            = 1

    health_check_grace_period   = 300
    health_check_type           = "ELB"
    target_group_arns           = [var.alb_target_group_arn]

    force_delete                = true

    lifecycle {
        create_before_destroy   = true
    }

    tags = [
        {
            key                 = "Name"
            value               = "test-autoscaling-group"
            propagate_at_launch  = false
        },
        {
            key                 = "Environment"
            value               = "development"
            propagate_at_launch = false
        }
    ]
}

auto_scaling_policy, aws_cloudwatch_metric_alarm

auto_scaling_policyで増減する方法を定義して、aws_cloudwatch_metric_alarmと連携させるイメージです。

  • auto_scaling_policy
パラメータ名 説明 必須か?
name ポリシー名 Yes
scaling_adjustment 何台増減させるか No
adjustment_type 増減のさせかた(ChangeInCapacityは指定した値だけ既存の値から増減) No
cooldown 一度増減させてから、次に増減できるまでの間隔(一時的なリクエスト増で何台もインスタンスが作成されないようにする) No
autoscaling_group_name AutoScalingグループの名前 Yes
  • aws_cloudwatch_metric_alarm
パラメータ名 説明 必須か?
alarm_name アラートの名前 Yes
comparison_operator しきい値からどうなった場合にアラートが発生するか Yes
evaluation_periods しきい値を超えるイベントが繰り返し発生した回数 Yes
metric_name しきい値に使うメトリック名 No
namespace メトリックの名前空間。metric_nameとセットで使う No
period チェックする間隔 No
statistic どの統計値を判断材料に利用するか No
dimentions AutoScalingグループ名を指定して、通知されるように設定(よくわからん) No
alarm_actions アラートが生成された際に、自動的に行う動作
resource "aws_autoscaling_policy" "scale_out" {
    name                   = "Instance-Scaleout-Policy"
    scaling_adjustment     = 1
    adjustment_type        = "ChangeInCapacity"
    cooldown               = 300
    autoscaling_group_name = aws_autoscaling_group.example_asg.name
}

resource "aws_autoscaling_policy" "scale_in" {
    name                   = "Instance-Scalein-policy"
    scaling_adjustment     = -1
    adjustment_type        = "ChangeInCapacity"
    cooldown               = 300
    autoscaling_group_name = aws_autoscaling_group.example_asg.name
}

resource "aws_cloudwatch_metric_alarm" "cpu_usage_high" {
    alarm_name             = "test-cpu-usage-high"
    comparison_operator    = "GreaterThanOrEqualToThreshold"
    evaluation_periods     = "1"
    metric_name            = "CPUUtilization"
    namespace              = "AWS/EC2"
    period                 = "300"
    statistic              = "Average"
    dimensions             = {
        AutoScalingGroupName = aws_autoscaling_group.example_asg.name
    }
    alarm_actions          = [aws_autoscaling_policy.scale_out.arn]
}
resource "aws_cloudwatch_metric_alarm" "cpu_usage_low" {
    alarm_name             = "test-cpu-usage-low"
    comparison_operator    = "LessThanThreshold"
    evaluation_periods     = "1"
    metric_name            = "CPUUtilization"
    namespace              = "AWS/EC2"
    period                 = "300"
    statistic              = "Average"
    dimensions             = {
        AutoScalingGroupName = aws_autoscaling_group.example_asg.name
    }
    alarm_actions          = [aws_autoscaling_policy.scale_in.arn]
}

RDS

RDSのリソース名は、シンプルなので説明を省きます。(疲れました)

aws_db_parameter_groupで動作するDBのパラメータをいじることができます。

あとは、skip_final_snapshottrueにしておかないと、terraform destory時にエラーが吐かれて削除できません。

(GUIでも、スナップショットをどうするか問われるダイアログがあったので、コードベースだと明示的に定義する必要があるのだろうと思っています)

resource "aws_db_parameter_group" "db_parameter" {
    name     = "${var.db_parameter_group.name}-parameter"
    family   = var.db_parameter_group.family

    parameter {
        name  = "character_set_server"
        value = "utf8"
    }

    parameter {
        name  = "character_set_client"
        value = "utf8"
    }
    
}

resource "aws_db_subnet_group" "db_subnets" {
    name       = "private-subnet"
    subnet_ids = split(",", var.private_subnets_ids)

    tags       = {
        Name = "Private Subnet"
    }
}

resource "aws_db_instance" "db_server" {
    identifier                 = "test"
    allocated_storage          = 20
    engine                     = "mysql"
    engine_version             = "5.7.22"
    instance_class             = "db.t2.micro"
    name                       = var.rds_name
    db_subnet_group_name       = aws_db_subnet_group.db_subnets.name
    vpc_security_group_ids     = [var.db_security_group_id]
    parameter_group_name       = aws_db_parameter_group.db_parameter.name
    multi_az                   = true
    backup_retention_period    = "7"
    backup_window              = "23:00-23:30"
    apply_immediately          = true
    auto_minor_version_upgrade = false
    username                  = var.db_identifilter.user_name
    password                   = var.db_identifilter.password
    skip_final_snapshot        = true
}

まとめ

今回の記事では、

  • ELBAutoScalingを使って冗長性が高い構成についてterraformで実装しました。
  • ついでにRDSを使ってマネージドサービスを利用しました。

まだまだシンプルなサービス(サービスを利用したとしても代表的な設定)しか利用していませんが、

来週以降も記事を投稿していきます。