※本記事はAIが書いて、人間がファクトチェックしています。
IaC連載企画の第2回です。
こんにちは!「絶対止めない」デプロイ戦略ハンズオン、第2回です。
前回(第1回)は、稼働中のサーバーを1台まるごと「壊して・作り直す(インプレースデプロイ)」という力技を試した結果、見事に数分間のダウンタイム(瞬断)が発生してしまいましたね。
今回はその反省を活かし、**「ユーザーに全く気づかれずに、裏側でコッソリとバージョンアップを完了させる」**魔法のようなデプロイを体験します。
1. 【プロローグ】 「もう絶対止めないぞ!」若手エンジニアの決意
若手エンジニア(あなた):
「前回のデプロイで数分間サイトが落ちて、SNSで『〇〇のサイト繋がらないんだけどw』って書かれちゃいました……。もうあんな思いは嫌です!」
先輩エンジニア:
「じゃあ今回は、サーバーを2台に増やしてみようか。1台をアップデートしている間、もう1台でユーザーのアクセスを受け止めれば、サイトは落ちないよね?」
若手エンジニア:
「なるほど!ロードバランサー(ALB)を前に置いて、後ろのサーバーを順番に入れ替えていくんですね。それなら誰も気づかないうちに青(v1)から緑(v2)へ移行できる!」
2. 【図解インプット】 ローリングアップデートの仕組み
今回実践するのは**「ローリングアップデート(Rolling Update)」**という戦略です。
【開始時】
[ ALB ] ──┬──> [ EC2 (青 v1) ]
└──> [ EC2 (青 v1) ]
【アップデート中(1台ずつ入れ替え)】
[ ALB ] ──┬──> [ EC2 (緑 v2) ] ← 新しいのを作って繋ぐ
└──> [ EC2 (青 v1) ] ← 古いのは後で消す
【完了時】
[ ALB ] ──┬──> [ EC2 (緑 v2) ]
└──> [ EC2 (緑 v2) ]
AWSでこれを実現するには、Application Load Balancer (ALB) と Auto Scaling Group (ASG) を組み合わせます。
ASGは「常に指定した台数のサーバーを維持する」機能を持っています。Terraformの instance_refresh という機能を使うと、この入れ替え作業を全自動で、かつ無停止でやってくれるのです。
3. 【ハンズオン】 止まらないデプロイを体感せよ!(所要時間:約40分)
Step 1: ALB + ASG構成のTerraformコード準備
今回はコードが少し長くなります。適当な作業用フォルダに main.tf を作成し、以下のコードを貼り付けてください。
(※学習用のため、デフォルトVPCを利用するシンプルな構成にしています)
provider "aws" {
region = "ap-northeast-1"
}
# デフォルトVPCとサブネットの情報を自動取得
data "aws_vpc" "default" { default = true }
data "aws_subnets" "default" {
filter {
name = "vpc-id"
values = [data.aws_vpc.default.id]
}
}
# 最新のAmazon Linux 2023のAMIを動的に取得
data "aws_ami" "amazon_linux" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["al2023-ami-2023.*-x86_64"]
}
}
# 1. セキュリティグループ(ALB用とEC2用を兼用)
resource "aws_security_group" "web_sg" {
name = "rolling-update-sg"
description = "Allow HTTP"
vpc_id = data.aws_vpc.default.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"]
}
}
# 2. ALB(ロードバランサー)とターゲットグループ
resource "aws_lb" "web_alb" {
name = "handson-alb"
internal = false
load_balancer_type = "application"
security_groups = [aws_security_group.web_sg.id]
subnets = data.aws_subnets.default.ids
}
resource "aws_lb_target_group" "web_tg" {
name = "handson-tg"
port = 80
protocol = "HTTP"
vpc_id = data.aws_vpc.default.id
}
resource "aws_lb_listener" "web_listener" {
load_balancer_arn = aws_lb.web_alb.arn
port = "80"
protocol = "HTTP"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.web_tg.arn
}
}
# 3. 起動テンプレート(EC2の設計図)
resource "aws_launch_template" "web_lt" {
name = "handson-web-lt"
image_id = data.aws_ami.amazon_linux.id # 最新のAMIをセット
instance_type = "t2.micro"
vpc_security_group_ids = [aws_security_group.web_sg.id]
# ★ここがアプリのバージョン(今回はv1の青)
user_data = base64encode(<<-EOF
#!/bin/bash
dnf install -y nginx
systemctl start nginx
systemctl enable nginx
echo '<body style="background-color: blue;"><h1 style="color: white;">Version 1 (Blue)</h1></body>' > /usr/share/nginx/html/index.html
EOF
)
lifecycle {
ignore_changes = [image_id]
}
}
# 4. Auto Scaling Group (ASG)
resource "aws_autoscaling_group" "web_asg" {
name = "handson-asg"
desired_capacity = 2 # 常に2台稼働させる
max_size = 4
min_size = 2
vpc_zone_identifier = data.aws_subnets.default.ids
target_group_arns = [aws_lb_target_group.web_tg.arn]
# ★超重要:ALBのヘルスチェックを基準にする設定
# これがないと、Nginxが起動する前に「新しいEC2ができたから古いものを消す」と誤認され、瞬断します。
health_check_type = "ELB"
health_check_grace_period = 120
launch_template {
id = aws_launch_template.web_lt.id
version = aws_launch_template.web_lt.latest_version
}
# ★ここがローリングアップデートの魔法!
instance_refresh {
strategy = "Rolling"
preferences {
min_healthy_percentage = 50 # 最低1台は生き残らせる
}
}
}
# 最後にALBのURLを表示
output "alb_dns_name" {
value = aws_lb.web_alb.dns_name
}
Step 2: v1(青アプリ)のデプロイ
ターミナルで以下を実行します。今回はロードバランサーを作るため、約3〜4分かかります。コーヒーでも飲みながら待ちましょう。
terraform init
terraform apply
完了すると、ターミナルの一番下に alb_dns_name = "handson-alb-xxxx.ap-northeast-1.elb.amazonaws.com" のようなURLが出力されます。これをブラウザで開いて、青い画面が出れば準備完了です!
Step 3: 【真骨頂】ダウンタイムなしのv2(緑アプリ)デプロイ
さあ、無停止デプロイの実験です。
まず、別のターミナルウィンドウを開き、**1秒に1回アクセスし続けるコマンド(curlループ)**を実行します。
※ の部分は、さっき出力された自分のURLに変えてください
【Mac / Linux (bash, zsh等) の場合】
while true; do curl -s http://<ALBのURL> | grep -o "Version .*"; sleep 1; done
【Windows (PowerShell) の場合】
while ($true) { curl.exe -s http://<ALBのURL> | Select-String "Version"; Start-Sleep -Seconds 1 }
画面に Version 1 (Blue)</h1></body> が1秒ごとに出力され続けますね。
この状態のまま、元のターミナルに戻り、main.tf の user_data を「緑色(v2)」に書き換えます。
# ★v2の緑に変更!
user_data = base64encode(<<-EOF
#!/bin/bash
dnf install -y nginx
systemctl start nginx
systemctl enable nginx
echo '<body style="background-color: green;"><h1 style="color: white;">Version 2 (Green)</h1></body>' > /usr/share/nginx/html/index.html
EOF
)
保存したら、いざデプロイ!
terraform apply
【curlループの画面に注目してください】
デプロイが進むにつれて、出力が劇的に変化します。(※切り替わるまで数分かかります)
Version 1 (Blue)</h1></body>
Version 1 (Blue)</h1></body>
Version 2 (Green)</h1></body> ← おっ!?
Version 1 (Blue)</h1></body> ← 混ざってきた!
Version 2 (Green)</h1></body>
Version 2 (Green)</h1></body>
Version 2 (Green)</h1></body> ← 完全に切り替わった!
一度もエラー(接続拒否など)が出ることなく、徐々に青から緑へ移行したのがお分かりいただけたでしょうか?
これがローリングアップデートの力です。ユーザーから見れば「サイトを使っていたら、いつの間にか新しいバージョンになっていた」という体験になります。
4. 【トラシュー体験】 恐怖!「状態」を忘れたTerraform
大成功に喜んだのも束の間。ここで、IaC初心者が高確率で踏む 「絶望の罠」 を体験しておきましょう。
Terraformは、AWS上のどこに何を作ったかを terraform.tfstate というファイルに記録しています。
もし、このファイルをうっかり消してしまったら……?
わざとファイル名を変更して、消えた状態を疑似体験してみましょう。
# tfstateファイルを隠す(消したのと同じ状態にする)
mv terraform.tfstate terraform.tfstate.hidden
この状態で、terraform plan を実行してみてください。
terraform plan
【結果】
Terraformは「あれ?何もないぞ? よし、ALBもASGも全部ゼロから新しく作ろう!」と提案してきます。
しかし、AWS上にはすでに同じ名前のALBが存在するため、もし apply すると 「名前が重複しています(AlreadyExists)」という真っ赤なエラー を吐いてパニックになります。
実際の画面:
現場でこれが起きると冷や汗が止まりません。本来であれば、コマンドラインから terraform import aws_security_group.web_sg sg-01234... のように叩いて、AWS上に実在するリソースのIDとTerraformコードを1つずつ手作業で紐付け直す、非常に泥臭い復旧作業(import) が必要になります。
今回は学習用なので、隠したファイルを元に戻して復旧させましょう。
mv terraform.tfstate.hidden terraform.tfstate
これでもう一度 terraform plan を打つと、「No changes」と表示され、無事に元の平和な状態に戻ります。
「tfstateファイルは命より重い(だから実務ではS3などの安全な場所に保存する)」 という教訓を胸に刻んでください。
実際の画面:
5. 【今回のリザルト】 ローリングアップデート
お片付けを忘れずに!
terraform destroy
| 評価項目 | 結果 | 現場でのリアルな声 |
|---|---|---|
| コスト(AWS費用) | ★★☆ (普通) | 一時的に新旧のサーバーが同時に立ち上がるため、少しだけ費用が増える。 |
| デプロイの速さ | ★☆☆ (遅い) | 1台(または数台)ずつ徐々に入れ替えるため、台数が多いと数十分かかることも。 |
| 安全性(無停止か) | ★★☆ (高い) | ダウンタイムなし! ただし、新旧のバージョンが混在する時間帯があるため、DBの設計変更などが絡むと少し工夫が必要。 |
💡 まとめ:
ローリングアップデートは、コストと安全性のバランスが取れた非常に優秀な戦略です。ただし「デプロイ完了までに時間がかかる」という弱点があります。
【次回予告】
「無停止なのは最高だけど、デプロイに5分も10分も待ってられないよ! もしバグがあったら、戻すのにも同じ時間がかかるんでしょ!?」
鋭いですね。その弱点を克服するのが、次回(第3回)の 「ブルーグリーンデプロイ」 です。
CloudFormationとECS(コンテナ)を使って、「一瞬で切り替え、一瞬で戻す」 という最強のスピード感を体験しましょう。お楽しみに!



