TerraformでEC2とRoute53だけのFloating IPパターンを試してみる
概要
ALBを使わない、Route53とEIPを紐付けたEC2だけで動いているアプリケーションだと、Terraformの更新時にEC2のリプレースが発生すると数分のダウンタイムが発生してしまいます。
この構成のままダウンタイムを小さくする方法がないか検討している中でFloating IPパターンというものを知り、これをTerraformでやる方法を考えてみました。
普通に構成を変更した方が楽だと思うので、こうやればできるんじゃないかというネタとしてみていただければと思います。
検証に使用したTerraformのコード
今回の検証に使用したTerraformのコードです。vpc_id
だけ実行時に渡す必要があります。
公式のサンプルコードをコピーしたのでEC2のNameタグがHelloWorldになっていたりしますが、特に意味はありません。
provider "aws" {
region = "ap-northeast-1"
}
# https://aws.amazon.com/jp/blogs/news/query-for-the-latest-amazon-linux-ami-ids-using-aws-systems-manager-parameter-store/
data "aws_ssm_parameter" "amzn2_ami" {
name = "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2"
}
resource "aws_instance" "web" {
ami = data.aws_ssm_parameter.amzn2_ami.value
instance_type = "t3.micro"
tags = {
Name = "HelloWorld"
}
user_data = file("userdata.sh")
vpc_security_group_ids = [
aws_security_group.web.id
]
}
resource "aws_eip" "web" {
instance = aws_instance.web.id
vpc = true
}
resource "aws_security_group" "web" {
name = "web-server-sg"
vpc_id = var.vpc_id
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"]
}
}
variable "vpc_id" {}
#!/bin/bash
sudo yum update -y
sudo yum install -y httpd
sudo systemctl start httpd
sudo systemctl enable httpd
userdata.shは下記の記事を参考にしました。
ダウンタイムの短縮だけならTerraformの設定で実現できる
Terraformにcreate_before_destroyというオプションがあり、apacheなどをインストールしたゴールデンイメージを作成していれば、これを設定することでダウンタイムを数秒まで短縮することができました。
ただ、この方法だと置き換えたEC2でエラーが起きた時に巻き戻すには、再度EC2を作りなおすことになるので少し時間がかかってしまいます。
既存のEC2を削除しないで置き換える
上記の方法の問題点は、既存のEC2が削除されてしまうことにありました。
ただ、調べた限りではTerraformにはリプレース対象のリソースを残したまま作り直す機能はなさそうでした。
そこで、少し強引な方法ですが、terraform state rm
というコマンドで特定のリソースをTerraformの管理外にしてから作り直す方法を試してみます。
terraform state rm aws_instance.web
上記のコマンドを実行しても、Terraformの管理外になるだけでリソースは残ったままになります。この状態で、再度terraform apply
を実行してリソースを作成します。
terraform apply -var 'vpc_id={VPCのID}'
リソースが作成されてEIPの紐付けも変更されたと思います。ここでエラーが出ていなければ完了ですが、エラーが発生したと仮定して、巻き戻す場合の手順を見ていきます。
まずは、先ほどと同じように新しく作成したEC2をTerraformの管理外にして
terraform state rm aws_instance.web
terraform import
コマンドで最初に作成したEC2をインポートして、terraform apply
でEIPを最初のリソースに紐付けます。
terraform import aws_instance.web {EC2インスタンスのID}
terraform apply -var 'vpc_id={VPCのID}'
新しく作成したEC2がそのまま残っているので、コンパネかCLIから終了させれば完了です。
Discussion