Terraform入門その一(インストール)
Terraform入門その二(AWSのEC2作成)
Terraform入門その三(hello worldの表示)
Terraform入門その四(AWSのELB&ASGの導入)[本記事]
前回EC2インスタンスにapcheの導入→helloworldをブラウザに表示させるところまで記述しました。
しかし、実際の現場ではインスタンス1台の稼働では冗長性や障害対応の観点では心もとないです。
そこで、AWSのELB
とASG
の追加をterraformに記述していきます。
最終的なディレクトリ構成図
working
├── main.tf
├── outputs.tf
└── vars.tf
ASG(Auto Scaling Group)とは
登録したEC2を管理し、例えば何かしらの原因でインスタンスに障害が発生した場合に、自動的に追加のインスタンスを生成する等を自動してくれるものです。
ASGの設定
main.tf
に、下記を記述していきます。
前回記事までに記載していたresource "aws_instance
を書き換える形になります。
resource "aws_launch_configuration" "example" {
image_id = "ami-04b2d1589ab1d972c"
instance_type = "t2.micro"
security_groups = ["${aws_security_group.instance.id}"]
user_data = <<-EOF
#! /bin/bash
sudo yum update
sudo yum install -y httpd
sudo chkconfig httpd on
sudo service httpd start
echo "<h1>hello world</h1>" | sudo tee /var/www/html/index.html
EOF
lifecycle {
create_before_destroy = true
}
}
lifecycle
の記述ですが、create_before_destroy = true
にしておくと、何かの変更を実行した際に、その全ての変更が完了した時点で既存のインスタンスが破棄される仕様です。
参照:https://www.terraform.io/docs/providers/aws/r/launch_configuration.html#using-with-autoscaling-groups
続いて、aws_security_group
にも、lifecycle
の記述を追加します。
resource "aws_security_group" "instance" {
name = "terraform-example-instance"
ingress {
from_port = "${var.server_port}"
to_port = "${var.server_port}"
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
# 追加
lifecycle {
create_before_destroy = true
}
}
ここまでの記述で、ようやくASG本体の設定ができます。
下記を記述します。
resource "aws_autoscaling_group" "example" {
launch_configuration = "${aws_launch_configuration.example.id}"
min_size = 2
max_size = 10
tag {
key = "Name"
value = "terraform-asg-example"
propagate_at_launch = true
}
}
ASGが2〜10台のEC2インスタンスを管理する設定です。立ち上がると最小単位の2台のインスタンスが立ち上がります。
propagate_at_launch = true
は、インスタンス作成の際に記述したタグを付ける設定です。
availability zones(AZ)の記述
下記記述で、region(今回の設定ですとap-northeast-1
)内のAZを拾ってきてくれます。
AZ = ap-northeast-1a, ap-northeast-1c, ap-northeast-1d
data "aws_availability_zones" "all" {}
これをASGの設定内容に組み込みます。
data "aws_availability_zones" "all" {}
resource "aws_autoscaling_group" "example" {
launch_configuration = "${aws_launch_configuration.example.id}"
# 追加
availability_zones = "${data.aws_availability_zones.all.names}"
min_size = 2
max_size = 10
tag {
key = "Name"
value = "terraform-asg-example"
propagate_at_launch = true
}
}
ELB(Load Balancer)の導入
ASGの設定により、複数インスタンスを管理できるようになりました。
しかし、ユーザ支店から考えた場合、一つのIPアドレスでアクセスできるようにしたいです。
そこで、ELB
を導入し各インスタンスへの窓口としての役割を果たしてもらいます。
security_groupの記述
ELBが外部からのアクセスを許可するためのsecurity_group
を作成します。
インバウンドは80番ポートへのアクセスを許可、アウトバウンドは全許可を表します。
resource "aws_security_group" "elb" {
name = "terraform-example-elb"
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
次にELB自身の設定です。
先程記述した、security_group
を反映させています。
listener
はどのポートからのアクセスを、どのインスタンス(厳密にはポート)へ転送するのかの記述です。
resource "aws_elb" "example" {
name = "terraform-asg-example"
availability_zones = "${data.aws_availability_zones.all.names}"
security_groups = ["${aws_security_group.elb.id}"]
listener {
lb_port = 80
lb_protocol = "http"
instance_port = "${var.server_port}"
instance_protocol = "http"
}
}
ヘルスチェックの追加
ELBの主要機能である、ヘルスチェック(health check)の記述を追加します。
30秒毎に/
へアクセスしにいき(この場合、自動的にindex.html
へ向かうことになる)、2回連続でステータスコード200が帰ったこなかった場合unhealthと判定されます。
resource "aws_elb" "example" {
name = "terraform-asg-example"
availability_zones = "${data.aws_availability_zones.all.names}"
security_groups = ["${aws_security_group.elb.id}"]
listener {
lb_port = 80
lb_protocol = "http"
instance_port = "${var.server_port}"
instance_protocol = "http"
}
# 追加
health_check {
healthy_threshold = 2
unhealthy_threshold = 2
timeout = 3
interval = 30
target = "HTTP:${var.server_port}/"
}
}
最後にELB
の情報をASG
に紐づけます。
health_check_type = "ELB"
と記述することで、ELBがunhealth
と判断した場合、ASGが作動して新しいインスタンスを作成することになります。
resource "aws_autoscaling_group" "example" {
launch_configuration = "${aws_launch_configuration.example.id}"
availability_zones = "${data.aws_availability_zones.all.names}"
# 追加
load_balancers = ["${aws_elb.example.name}"]
health_check_type = "ELB"
min_size = 2
max_size = 10
tag {
key = "Name"
value = "terraform-asg-example"
propagate_at_launch = true
}
}
main.tfの全体図
provider "aws" {
profile = "default"
region = "ap-northeast-1"
}
resource "aws_launch_configuration" "example" {
image_id = "ami-04b2d1589ab1d972c"
instance_type = "t2.micro"
security_groups = ["${aws_security_group.instance.id}"]
user_data = <<-EOF
#! /bin/bash
sudo yum update
sudo yum install -y httpd
sudo chkconfig httpd on
sudo service httpd start
echo "<h1>hello world</h1>" | sudo tee /var/www/html/index.html
EOF
lifecycle {
create_before_destroy = true
}
}
data "aws_availability_zones" "all" {}
resource "aws_autoscaling_group" "example" {
launch_configuration = "${aws_launch_configuration.example.id}"
availability_zones = "${data.aws_availability_zones.all.names}"
load_balancers = ["${aws_elb.example.name}"]
health_check_type = "ELB"
min_size = 2
max_size = 10
tag {
key = "Name"
value = "terraform-asg-example"
propagate_at_launch = true
}
}
resource "aws_security_group" "instance" {
name = "terraform-example-instance"
ingress {
from_port = "${var.server_port}"
to_port = "${var.server_port}"
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
lifecycle {
create_before_destroy = true
}
}
resource "aws_elb" "example" {
name = "terraform-asg-example"
availability_zones = "${data.aws_availability_zones.all.names}"
security_groups = ["${aws_security_group.elb.id}"]
listener {
lb_port = 80
lb_protocol = "http"
instance_port = "${var.server_port}"
instance_protocol = "http"
}
health_check {
healthy_threshold = 2
unhealthy_threshold = 2
timeout = 3
interval = 30
target = "HTTP:${var.server_port}/"
}
}
resource "aws_security_group" "elb" {
name = "terraform-example-elb"
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
outputの作成
現在の状態でメインは完成したので、terraform apply
コマンドを実行すれば動作します。
しかし、ブラウザへ確認しにいくときにELBのドメイン名をマネジメントコンソール画面で確認するのは面倒です。
そこで、outputs.tf
を作成し、作成完了後にアクセスすべきドメイン名をターミナルに出力するようにします。
output "elb_dns_name" {
value = "${aws_elb.example.dns_name}"
}
terraform applyの実行
terraform apply
をターミナルで実行しますと、最終的に以下のようなドメイン名が帰ってくるかと思います。
elb_dns_name = terraform-asg-example-73024.ap-northeast-1.elb.amazonaws.com
こちらにアクセスしますとhello world
が表示されます。
また、AWSマネジメントコンソールにアクセスしますとEC2
ELB
ASG
が作成されていることも確認できます。
ためしに、2つあるEC2インスタンスのうちの一つ(terraform-asg-example
)を削除してみてください。
ASGが作動し、自動的にインスタンスを複製してくれます(多少時間がかかります、少なくとも5分後には新しいものができているはず)。
リソースの削除
今回terraformで作成したリソースは下記コマンドで簡単に削除することができます。
mbp:terraform mac$ terraform destroy