256bitの殺人メニュー

インフラエンジニアだったソリューションアーキテクトなくわののブログ。こちらのBlogは個人の意見となっていて会社とは全く関係ありません。お約束です。[twitter:@kuwa_tw]めんどくさがりが重い腰を上げて何かをアウトプットすることにどれほどの意味があるのかを試してみたいブログでもある。

Terraformを使ってEC2のAutoScalingやろうとしたらちょっとつらいんじゃないかなってなった話

どうもどうも乙カレー様です。桑野です。
びっくりするほどブログ書いてなくてびっくりしてます。半年書いてないやん。


Terraformを使っていたりするんですが、最近EC2のAutoScaleを入れようとして辛いことがあったりしたのでちょっとまとめてみます。

Terraform

Terraformは言わずとも知れたHashicorpさんのプロダクトですね。
インフラ構築をコード化してGithub等でレポジトリ管理することによって履歴管理や、プルリクエストベースの構築ができるのが売りだったりします。

TerraformでのAutoScale時のハマりどこ

端的にいうとこの2つです。

  • Terraform経由で実行した際のLaunchConfiguration(イカLC)とAutoScalingGroup(イカASG)の削除の順番が逆
  • LC内のuser_data更新で一網打尽になる
Terraform経由で実行した際のLaunchConfiguration(イカLC)とAutoScalingGroup(イカASG)の削除の順番が逆

何が悪いかといいますと、この2つは依存関係があるので、ASGを削除する前にそれが紐付いてるLCを削除しようとするとまだAttachされてるよってエラーが出て止まるわけです。
なので、ASG->LCの順で削除してくれればいいんだけど、実際には逆でしか動いてくれない。

* ResourceInUse: Cannot delete launch configuration launchconfig-test because it is attached to AutoScalingGroup autoscalinggroup-test
        status code: 400, request id: [12345678-1234-1234-1234-123412341234]


となると。

GithubのIssueとかでも同じような議論があってlifecycle { create_before_destroy = true }をつけたらいいぜって言ってる人もいるけど、作成タイミングの違いだからやっぱりうまく動かない。

LC内のuser_data更新で一網打尽になる

じゃあ2個作って交互に更新して行ったらええんちゃうんかでバージョン管理する。
これでOKでしょ。

# 古いLC
resource "aws_launch_configuration" "launchconfig_test_v1" {
  name = "launchconfig-test-v1"
  image_id = "${var.amis.api}"
  key_name = "${var.aws.key_name}"
  instance_type = "t2.micro"
  security_groups = ["${var.security_groups.asgtest}"]
  iam_instance_profile = "asgtest"
  associate_public_ip_address = 0
  user_data = "${file("user_data/app_userdata.sh")}"
}
# 新しいLC
resource "aws_launch_configuration" "launchconfig_test_v2" {
  name = "launchconfig-test-v2"
  image_id = "${var.amis.api}"
  key_name = "${var.aws.key_name}"
  instance_type = "t2.micro"
  security_groups = ["${var.security_groups.asgtest}"]
  iam_instance_profile = "asgtest"
  associate_public_ip_address = 0
  user_data = "${file("user_data/app_userdata.sh")}"
}

ぼくが気付かなかっただけだけど、この場合はuser_data/app_userdata.shが更新されるとどっちも再作成になって⊂ミ⊃^ω^ )⊃ アウアウ!!

* ResourceInUse: Cannot delete launch configuration launchconfig-test because it is attached to AutoScalingGroup autoscalinggroup-test-v1
        status code: 400, request id: [12345678-1234-1234-1234-123412341234]

TerraformでのAutoScale時する時のベストプラクティス?

じゃあどうしたらいいんだって話ですが、一旦色々考えたり話したりした挙句こんな感じになりました。

  • ASG, LC, user_dataはバージョニングする
  • 追加/削除時の作業順を厳密に指定する
    • 1. user_data作成
    • 2. 新LC, ASG作成
    • 3. 旧ASGの desired_capacity を0にして既存系のインスタンス削除する
    • 4. 旧ASGを削除する
    • 5. 旧LCを削除する

この手順だと実際にApplyするのは、2. 3. 4. 5.で4回です(2. と3. はまとめられますがそれでも3回)。多いですね。

3.の時の設定の状態
# 古いLC
resource "aws_launch_configuration" "launchconfig_test_v1" {
  name = "launchconfig-test-v1"
  image_id = "${var.amis.api}"
  key_name = "${var.aws.key_name}"
  instance_type = "t2.micro"
  security_groups = ["${var.security_groups.asgtest}"]
  iam_instance_profile = "asgtest"
  associate_public_ip_address = 0
  user_data = "${file("user_data/app_userdata_v1.sh")}"
}
# 古いASG(この後削除する)
resource "aws_autoscaling_group" "autoscalinggroup_test_v1" {
  availability_zones = ["ap-northeast-1c"]
  name = "autoscalinggroup-test-v1"
  max_size = 0
  min_size = 0
  health_check_grace_period = 300
  health_check_type = "ELB"
  desired_capacity = 0
  force_delete = true
  launch_configuration = "${aws_launch_configuration.launchconfig_test_v1.id}"
  vpc_zone_identifier = ["${var.subnets.asgtest}""]
  load_balancers = ["${aws_elb.asgtest.name}"]
  tag = {
    key = "Name"
    value = "app-asg"
    propagate_at_launch = true
  }
  tag = {
    key = "SERVER"
    value = "APP"
    propagate_at_launch = true
  }
}
新しい設定
# 新しいLC
resource "aws_launch_configuration" "launchconfig_test_v2" {
  name = "launchconfig-test-v2"
  image_id = "${var.amis.api}"
  key_name = "${var.aws.key_name}"
  instance_type = "t2.micro"
  security_groups = ["${var.security_groups.asgtest}"]
  iam_instance_profile = "asgtest"
  associate_public_ip_address = 0
  user_data = "${file("user_data/app_userdata_v2.sh")}"
}
# 新しいASG
resource "aws_autoscaling_group" "autoscalinggroup_test_v2" {
  availability_zones = ["ap-northeast-1c"]
  name = "autoscalinggroup-test-v2"
  max_size = 4
  min_size = 2
  health_check_grace_period = 300
  health_check_type = "ELB"
  desired_capacity = 2
  force_delete = true
  launch_configuration = "${aws_launch_configuration.launchconfig_test_v2.id}"
  vpc_zone_identifier = ["${var.subnets.asgtest}""]
  load_balancers = ["${aws_elb.asgtest.name}"]
  tag = {
    key = "Name"
    value = "app-asg"
    propagate_at_launch = true
  }
  tag = {
    key = "SERVER"
    value = "APP"
    propagate_at_launch = true
  }
}

で、

この人は何故ここまで頑張ってTerraformを使う必要があるのだろうか、、、っていう部分は聞かないでください!
でもやってて開発者の人にもサーバ構成を共有するとか、インスタンス作成部分とかは作業してこっちでもプルリクエストベースでのコードレビュー(構成レビュー)させてもらえるのは非常にいいと思ってます。


そして、バージョン0.6以降で上手く使えるようになることを祈っていますね。。。


でも ↑ この時よりは状況良くなっていると思います!貢献していきたい。

テラフォーマーズ 13 (ヤングジャンプコミックス)

テラフォーマーズ 13 (ヤングジャンプコミックス)

じょうじょ