※本記事はAIが書いて、人間がファクトチェックしています。
IaCの連載企画、第1回です。
こんにちは!本連載では、実務で役立つ「絶対にサービスを止めないAWSデプロイ戦略」をハンズオン形式で学んでいきます。
第0回で安全なAWS環境とローカルツール(VS CodeやTerraform)の準備はバッチリですね?
いよいよ今回から、実際にAWS上にWebサーバーを構築していきます。……が、その前に。まずは**「やってはいけない危険なデプロイ」**を体験していただきます。
1. 【プロローグ】 先輩の「ちょっと直しておいて」が招く悲劇
先輩エンジニア:
「あ、ごめん!本番環境のトップページ、背景色が間違ってるわ。ちょっと直しておいてくれない?パパッとでいいから!」
若手エンジニア(あなた):
「了解です!本番サーバーにSSHログインして、直接 index.html を書き換えちゃいますね。えーっと、vi index.html で色を青から緑に変更して……よし、保存!Nginxを再起動っと(ターンッ!)」
先輩エンジニア:
「……おい、サイトに繋がらないぞ!? エラー画面が出てる!!」
若手エンジニア:
「えっ!? ああっ、HTMLのタグを閉じ忘れて文法エラーになってます! すみません、すぐ直します! 手が震えてタイピングが……(冷や汗ダラダラ)」
いかがでしょうか。胃が痛くなりますね。
「本番サーバーに直接入って手作業で書き換える(手動デプロイ)」は、手順漏れやタイポのリスクが高く、ミスした瞬間にサービスが停止します。
では、手作業をやめて 「IaC(Infrastructure as Code)」 を使えば全て解決するのでしょうか?
実は、IaCを使って自動化しても 「デプロイ戦略」 を間違えれば、やはりサービスは止まってしまうのです。百聞は一見に如かず、実際にやってみましょう。
2. 【図解インプット】 デプロイ戦略のキホンとIaC
デプロイ(新しいバージョンのアプリを本番環境に配置すること)には、いくつかのアプローチがあります。まずは全体のイメージを掴んでみましょう。
【1. インプレース(再作成)デプロイ】※今回体験
[旧サーバー(青)] ──(削除して作り直す)──> [新サーバー(緑)]
🚨この間はユーザーがアクセスできない!(瞬断)
【2. ローリングアップデート】※第2回で体験
[旧(青)][旧(青)] ──(1台ずつ順番に入れ替える)──> [新(緑)][新(緑)]
✅サービスは止まらないが、時間がかかる
【3. ブルーグリーンデプロイ】※第3回で体験
┌─(いま繋がっている)─> [旧環境一式 (青)]
[ロードバランサー] ┤
└─(一瞬で切り替える)─> [新環境一式 (緑)]
✅一瞬で切り替わり、失敗してもすぐ戻せる!
【4. カナリアリリース】※第4回で体験
[ロードバランサー] ──(10%の客だけ案内)──> [新環境 (緑)] 様子見...
そして、これらの環境を「コード」で定義して自動構築するツールがIaCです。AWSでは主に以下の3つが使われます。
- Terraform: クラウド業界のデファクトスタンダード。独自の書き方(HCL)で直感的に書ける。
- AWS CloudFormation (CFn): AWS純正。YAMLやJSONで書く。
- AWS CDK: TypeScriptやPythonなどのプログラミング言語でインフラを書ける最新ツール。
今回は、最も人気のあるTerraformを使って、一番上の「インプレース(再作成)デプロイ」を実行してみましょう。
3. 【ハンズオン】 恐怖のダウンタイム体験(所要時間:約30分)
今回は、アクセスすると「青い画面(v1)」が表示されるシンプルなEC2サーバーを立ち上げ、それを「緑の画面(v2)」にアップデートします。
※注意
このハンズオンは、お使いのAWSアカウントに「デフォルトVPC」が存在することを前提としています(通常、アカウント作成時から存在します)。
Step 0: AWSクレデンシャルの確認
前回作成した作業用IAMユーザーが設定されているかを確認してください。設定できていない場合は第0回に戻って作業用IAMユーザーのアクセスキーを発行し、aws configureコマンドで設定してください。
aws sts get-caller-identity
{
"UserId": "XXXXXXXXXXXXXXXXXXXXX",
"Account": "<your-accountid>",
"Arn": "arn:aws:iam::<your-accountid>:user/<your-user-name>"
}
Step 1: Terraformコードの準備
適当な作業用フォルダ(例: deploy-handson)を作り、その中に main.tf というファイルを作成して以下のコードをコピペしてください。
# main.tf
provider "aws" {
region = "ap-northeast-1"
}
# 最新のAmazon Linux 2023のAMIを取得
data "aws_ami" "amazon_linux" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["al2023-ami-2023.*-x86_64"]
}
}
# セキュリティグループ(HTTPアクセスを許可)
resource "aws_security_group" "web_sg" {
name = "handson-web-sg"
description = "Allow HTTP inbound traffic"
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"]
}
}
# EC2インスタンスの作成
resource "aws_instance" "web" {
ami = data.aws_ami.amazon_linux.id
instance_type = "t2.micro"
# セキュリティグループを紐付け
vpc_security_group_ids = [aws_security_group.web_sg.id]
# ★ここがアプリのバージョン(今回はv1の青)
user_data = <<-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
# user_dataが変更されたらEC2を作り直す設定
user_data_replace_on_change = true
tags = {
Name = "Handson-Web-Server"
}
}
# Elastic IP (固定IP) を付与
# これがないと、サーバーが作り直された時にURL(IPアドレス)が変わってしまいます
resource "aws_eip" "web_eip" {
instance = aws_instance.web.id
domain = "vpc"
}
# デプロイ完了後にアクセスすべきURLをターミナルに表示する
output "website_url" {
value = "http://${aws_eip.web_eip.public_ip}"
description = "ブラウザでアクセスするURL"
}
Step 2: v1(青アプリ)のデプロイ
ターミナルを開き、main.tf があるディレクトリに移動して以下のコマンドを順番に実行します。
# Terraformの初期化
terraform init
# 実行計画の確認
terraform plan
# デプロイの実行(yesと入力してEnter)
terraform apply
数分待つとデプロイが完了し、ターミナルの最後に以下のような文字が表示されます。
Outputs:
website_url = "[http://xx.xx.xx.xx](http://xx.xx.xx.xx)"
このURLをコピーしてブラウザで開いてみてください。
**真っ青な背景に「Version 1 (Blue)」**と表示されれば成功です!
Step 3: 【わざと失敗】v2(緑アプリ)へのアップデートと「瞬断」
さて、ここからが本番です。「緑色(v2)」へのアップデート作業を行います。
main.tf の user_data の部分を以下のように「green」と「Version 2」に書き換えて上書き保存してください。
# ★v2の緑に変更!
user_data = <<-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
保存したら、再度デプロイを実行します。ここからが非常に重要です。
コマンドを実行したら、すぐに先ほどのブラウザ画面を何度もリロード(F5)し続けてください。
terraform apply
↓
↓
【ブラウザで起こること】
- 最初は「青い画面」が出ます。
- 突然、 「このサイトにアクセスできません(ERR_CONNECTION_TIMED_OUT)」または「ぐるぐる回って読み込まれない」 状態に陥ります。
- 3分〜5分ほど気長にリロードを続けていると、ようやく「緑の画面」が表示されます。
これが 「ダウンタイム(瞬断)」 です。
Terraformは「設定(user_data)が変わったから、今のEC2を一度削除(Destroy)して、新しいEC2を作り直す(Create)」という挙動をとりました。新しくサーバーが立ち上がり、Nginxがインストールされるまでの数分間、サーバーは存在しないため、ユーザーはエラー画面を見ることになります。
IaCを使って手作業のミスは防げましたが、「1台しかないサーバーを壊して作り直す」という戦略のままでは、本番環境のデプロイとしては失格です。
Step 4: お片付け(重要!)
次回のハンズオンのために、今回作ったリソースを削除しておきましょう。
terraform destroy
yes と入力してEnterを押せば、AWS上のリソースが綺麗に削除され、課金はストップします。IaCの素晴らしいところですね。
4. 【今回のリザルト】 インプレース(再作成)デプロイ
| 評価項目 | 結果 | 現場でのリアルな声 |
|---|---|---|
| コスト(AWS費用) | ★★★ (安い) | サーバーは常に1台分なので一番安上がり。 |
| デプロイの速さ | ★★☆ (普通) | 古いものを消して新しいものを作る時間がかかる。 |
| 安全性(無停止か) | ☆☆☆ (最悪) | 確実にダウンタイムが発生する。本番では絶対NG! |
💡 まとめ:
IaCを使えば「手順書を見ながら手動でコマンドを打つ」ミスはなくなります。しかし、アーキテクチャやデプロイ戦略そのものが古ければ、ダウンタイムは防げません。
【次回予告】
「じゃあ、サーバーを2台以上にして、1台ずつ順番にアップデートすれば止まらないのでは!?」
その通りです!次回(第2回)は、ロードバランサー(ALB)とオートスケーリング(ASG)を組み合わせた 「ローリングアップデート」 をTerraformで実装します。ダウンタイムなしで青から緑へ、ジワジワと切り替わっていく感動を味わいましょう。お楽しみに!





