メインコンテンツへスキップ

Terraformゼロダウンタイムデプロイの実現方法

·
インフラ Terraform 実践 DevOps
目次

今日学んだこと
#

Terraform で ASG(Auto Scaling Group)を使ったゼロダウンタイムデプロイを実現する方法を学びました。create_before_destroy ライフサイクルと min_elb_capacity を組み合わせることで、サービスを停止せずにインフラを更新できます。

学習内容
#

背景と問題
#

webserver-cluster モジュールで user-data.sh の内容(server_text など)を変更した場合、以下のような動作になります。

  • 新しい Launch Configuration が作成される
  • ASG が新しい Launch Configuration を参照するようになる
  • しかし、既存の EC2 インスタンスはそのまま!

Launch Configuration は新しいインスタンスを起動する際のテンプレートであり、既存のインスタンスには影響しません。

解決策の比較
#

方法手順問題点
ASG を削除して再作成古い ASG 削除 → 新しい ASG 作成ダウンタイムが発生
create_before_destroy新しい ASG 作成 → 古い ASG 削除ダウンタイムなし ✅

ゼロダウンタイムデプロイに必要な3つの設定
#

#設定目的
1name を起動設定の名前に依存させる起動設定が変わると ASG 名も変わり、置き換えが発生
2create_before_destroy = true新しい ASG を先に作成してから古いものを削除
3min_elb_capacity = min_size新しいインスタンスが ELB のヘルスチェックに合格するまで待機

コード例:ゼロダウンタイムデプロイ対応の ASG
#

resource "aws_autoscaling_group" "example" {
  # 1. ASG名が起動設定の名前を参照(起動設定が変わるとASGも置き換え)
  name = "${var.cluster_name}-${aws_launch_configuration.example.name}"

  launch_configuration = aws_launch_configuration.example.name
  vpc_zone_identifier  = data.aws_subnets.default.ids
  target_group_arns    = [aws_lb_target_group.asg.arn]
  health_check_type    = "ELB"

  min_size = var.min_size
  max_size = var.max_size

  # 3. ヘルスチェックに合格するまで待機
  min_elb_capacity = var.min_size

  # 2. 新しいASGを先に作成してから古いASGを削除
  lifecycle {
    create_before_destroy = true
  }

  tag {
    key                 = "Name"
    value               = var.cluster_name
    propagate_at_launch = true
  }

  dynamic "tag" {
    for_each = {
      for key, value in var.custom_tags:
      key => upper(value)
      if key != "Name"
    }

    content {
      key                 = tag.key
      value               = tag.value
      propagate_at_launch = true
    }
  }
}

デプロイの流れ
#

server_text 変更
    ↓
user-data.sh の内容が変更
    ↓
新しい Launch Configuration 作成(名前が変わる)
    ↓
ASG の name が変わる → ASG の置き換えが必要と判断
    ↓
新しい ASG を作成(create_before_destroy)
    ↓
min_elb_capacity 台がヘルスチェック合格を待つ
    ↓
古い ASG を削除
    ↓
ゼロダウンタイムで完了!

動作確認方法
#

while true; do curl http://<load_balancer_url>; sleep 1; done

1秒ごとにリクエストを送り、デプロイ中もレスポンスが途切れないことを確認します。

状態レスポンス
デプロイ前古いメッセージのみ
デプロイ中古い/新しいが混在(両方の ASG が稼働)
デプロイ後新しいメッセージのみ

デプロイ中もレスポンスが途切れなければ、ゼロダウンタイム達成です。

ゼロダウンタイムデプロイの制限事項
#

制限1:Auto Scaling ポリシーとは組み合わせて使えない
#

デプロイのたびに ASG のサイズが min_size にリセットされてしまいます。

通常運用中:Auto Scaling により 10 台で稼働
    ↓
デプロイ実行(create_before_destroy)
    ↓
新しい ASG 作成時に min_size(例:2台)でスタート
    ↓
トラフィックに対してインスタンス数が不足!

回避策としては、recurrence パラメータの調整や desired_capacity パラメータの明示的な設定があります。

制限2:ネイティブなデプロイ方法がない(なかった)
#

以前の Terraform にはゼロダウンタイムデプロイのようなネイティブなデプロイ方法がありませんでした。最近の Terraform ではネイティブなデプロイ方法がサポートされてきているため、適宜公式ドキュメントの確認が必要です。

まとめ
#

  • ゼロダウンタイムデプロイには3つの設定が必要:ASG名の依存、create_before_destroymin_elb_capacity
  • create_before_destroy で新しい ASG を先に作成してから古い ASG を削除する
  • min_elb_capacity でヘルスチェック合格まで待機することで、サービス断を防ぐ
  • Auto Scaling ポリシーとの併用には注意が必要

参考
#