読者です 読者をやめる 読者になる 読者になる

Carpe Diem

備忘録。https://github.com/jun06t

TerraformでAutoScaling環境の構築

概要

Terraformを使ってAutoScaling環境を構築します。
以下の状態をゴールとします

  • デフォルト1台
  • CPUが30%超えたら1台増やす
  • CPUが5%以下なら1台減らす

環境

  • Terraform 0.6.9

Terraform設定

セキュリティグループなどはTerraformでAWSのセキュアな構成を構築をベースにしています。
最終的なソースは以下です。

github.com

LaunchConfig

主にセキュリティグループやどんなインスタンスを使うか、などを設定します。

resource "aws_launch_configuration" "dev_api" {
    name = "dev-api"
    image_id = "${var.amis.api}"
    instance_type = "t2.micro"
    key_name = "${var.key_name}"
    vpc_security_group_ids = ["${aws_security_group.internal.id}"]
    associate_public_ip_address = 0
    lifecycle {
        create_before_destroy = true
    }
}

主な項目の説明は以下です。

項目 意味
image_id 使用するAMIのID ${var.amis.api}
key_name 登録するSSHキー ${var.key_name}
associate_public_ip_address PublicIPを付与するか 0(しない)
create_before_destroy 削除する前に新規作成する true

AutoScalingGroup

何台まで増やすか、どのELBに紐付けるか、などを設定します。

resource "aws_autoscaling_group" "dev_api" {
    availability_zones = ["ap-northeast-1a"]
    name = "dev-api"
    max_size = 4
    min_size = 1
    desired_capacity = 1
    health_check_grace_period = 300
    health_check_type = "ELB"
    force_delete = true
    launch_configuration = "${aws_launch_configuration.dev_api.id}"
    vpc_zone_identifier = ["${aws_subnet.private_1a.id}"]
    load_balancers = ["${aws_elb.dev_elb.name}"]
    tag = {
        key = "Name"
        value = "dev-api-asg"
        propagate_at_launch = true
    }
    tag = {
        key = "Environment"
        value = "Development"
        propagate_at_launch = true
    }
    tag = {
        key = "Type"
        value = "API"
        propagate_at_launch = true
    }
    lifecycle {
        create_before_destroy = true
    }
}

主な項目の説明は以下です。

項目 意味
max_size 最大スケール幅 4
min_size 最小スケール幅 1
desired_capacity デフォルトの台数 1
launch_configuration LauchConfigの指定 ${aws_launch_configuration.dev_api.id}
vpc_zone_identifier サブネット ${aws_subnet.private_1a.id}
load_balancers インスタンスを登録するELB ${aws_elb.dev_elb.name}
propagate_at_launch 生成されたインスタンスにこのタグを付けるか true
create_before_destroy 削除する前に新規作成する true

Policy

どのようにスケールアウト・スケールインさせるかの設定です。

source "aws_autoscaling_policy" "dev_api_scale_out" {
    name = "Instance-ScaleOut-CPU-High"
    scaling_adjustment = 1
    adjustment_type = "ChangeInCapacity"
    cooldown = 300
    autoscaling_group_name = "${aws_autoscaling_group.dev_api.name}"
}

resource "aws_autoscaling_policy" "dev_api_scale_in" {
    name = "Instance-ScaleIn-CPU-Low"
    scaling_adjustment = -1
    adjustment_type = "ChangeInCapacity"
    cooldown = 300
    autoscaling_group_name = "${aws_autoscaling_group.dev_api.name}"
}

主な項目の説明は以下です。

項目 意味
scaling_adjustment 増減させる台数 1 or -1
adjustment_type 台数の増やし方。下記詳細参照 ChangeInCapacity
cooldown この期間はイベント発火はしません。秒間。 300
autoscaling_group_name どのASGへ設定するか ${aws_autoscaling_group.dev_api.name}

adjustment_typeは以下の設定ができます。

項目 意味
ChangeInCapacity 指定した値だけ既存の値から増減させる
ExactCapacity 既存の値に関係なく指定した値にする
PercentChangeInCapacity 指定した値を百分率とした割合で増減させる

Alarm

どういう状況になったらスケールアウト、スケールインするか、の設定です。

resource "aws_cloudwatch_metric_alarm" "dev_api_high" {
    alarm_name = "dev-api-CPU-Utilization-High-30"
    comparison_operator = "GreaterThanOrEqualToThreshold"
    evaluation_periods = "1"
    metric_name = "CPUUtilization"
    namespace = "AWS/EC2"
    period = "300"
    statistic = "Average"
    threshold = "30"
    dimensions {
        AutoScalingGroupName = "${aws_autoscaling_group.dev_api.name}"
    }
    alarm_actions = ["${aws_autoscaling_policy.dev_api_scale_out.arn}"]
}

resource "aws_cloudwatch_metric_alarm" "dev_api_low" {
    alarm_name = "dev-api-CPU-Utilization-Low-5"
    comparison_operator = "LessThanThreshold"
    evaluation_periods = "1"
    metric_name = "CPUUtilization"
    namespace = "AWS/EC2"
    period = "300"
    statistic = "Average"
    threshold = "5"
    dimensions {
        AutoScalingGroupName = "${aws_autoscaling_group.dev_api.name}"
    }
    alarm_actions = ["${aws_autoscaling_policy.dev_api_scale_in.arn}"]
}

主な項目の説明は以下です。

項目 意味
alarm_name アラーム名。変更不可。区別しやすい名称がいい dev-api-CPU-Utilization-Low-5
comparison_operator 条件式 LessThanThreshold
evaluation_periods 何回periodが起きたら発火するか 1
metric_name 監視する項目 CPUUtilization
period statisticの上限期間。この秒数を超えたら発火 300
statistic データのどの値を使うか。Sum、Minimumなど Average
threshold 値の上限・下限値 5
dimensions 監視するグラフ ${aws_autoscaling_group.dev_api.name}
alarm_actions どのPolicyを発火させるか ${aws_autoscaling_policy.dev_api_scale_in.arn}

ELB

resource "aws_elb" "dev_elb" {
    name = "dev-elb"
    subnets = [
        "${aws_subnet.public_1a.id}",
    ]
    security_groups = [
        "${aws_security_group.internal.id}",
        "${aws_security_group.http.id}",
    ]
    listener {
        instance_port = 80
        instance_protocol = "http"
        lb_port = 80
        lb_protocol = "http"
    }
    health_check {
        healthy_threshold = 2
        unhealthy_threshold = 2
        timeout = 5
        target = "HTTP:80/"
        interval = 30
    }
    cross_zone_load_balancing = true
    idle_timeout = 400
    connection_draining = true
    connection_draining_timeout = 400
    tags {
        Environment = "Development"
        Name = "dev-elb"
        Role = "ELB"
    }
}

ポイントとしてinstancesを付けないことです。
つけると再実行した際にASGのインスタンスが外れてしまいます。

ソース