はじめる前に
- 必須AWS アカウントを持っていること、マネジメントコンソールにサインインできること
- 必須VPC・サブネット・ルートテーブルを作成した経験
- 必須Application Load Balancer と Auto Scaling を組み合わせた経験
- 必須RDS で Multi-AZ インスタンスを作成した経験
- 必須IAM ロールの基本的な経験
- 必須ローカルに AWS CLI をインストールし、認証情報を設定済みであること
- あると良いSecrets Manager・S3・CloudWatch アラームのいずれかを単体で扱った経験
※ このハンズオンは要素が多く、所要時間も 2〜3 時間程度かかります。途中で中断する場合は、どこまで作ったかをメモしておくと再開しやすくなります。一気に終わらせなくても構いません。ローカル PC の操作は PowerShell から AWS CLI(Session Manager 経由の接続を含む)を使う想定で、SSH クライアントは使いません。
参照する公式ドキュメント
構成が複雑なので、各サービスの基本に迷ったときはここに戻ってきましょう。
※ リンク切れの場合は、ページタイトルで検索してください。
背景・シナリオ
これまでは、ALB と Auto Scaling、RDS の Multi-AZ 配置、S3、Secrets Manager、CloudWatch の監視といった要素を、ひとつずつ単独で扱ってきました。実際のサービス運用では、これらを組み合わせ、「ある層が落ちても他の層が動き続ける」「障害が起きたら気づける」という形に仕上げる必要があります。
今回は、利用者からのアクセスを受け付ける「Web 層(ALB)」、処理を行う「アプリ層(EC2・Auto Scaling、プライベートサブネット)」、データを保存する「データ層(RDS Multi-AZ、プライベートサブネット)」の 3 層構成を組み立てます。アプリは S3 の画像と、Secrets Manager 経由のデータベース認証情報を使って動作確認ページを表示し、最後に異常を検知して通知する仕組みまで作ります。
なぜアプリ層までプライベートサブネットに置くの?
ALB(インターネットからの入口)だけを外部に公開し、実際の処理を行うアプリ層やデータを持つデータ層は外部から直接到達できないようにすることで、攻撃を受ける面(アタックサーフェス)を最小限にできます。これは実務でよく使われる構成です。
NAT ゲートウェイは何のために必要なの?
プライベートサブネットのアプリ層の EC2 は、パブリック IP を持ちません。それでも S3 や Secrets Manager など AWS のサービス、あるいは OS の更新プログラムを取得するためにインターネットへの通信が必要になる場面があります。NAT ゲートウェイは、その「外向きの通信だけ」を中継する役割を持ちます。
途中で失敗したら、最初からやり直さないといけないの?
いいえ。後述の「つまずきポイント」や、フェーズごとに用意した確認ポイント(✅ マークの吹き出し)を参考に、うまくいっていないフェーズだけを見直せば十分です。フェーズごとに動作確認のタイミングを用意しているので、どこまで進んでいるかが分かりやすくなっています。
VPC 内に 3 層構成(パブリックサブネットの ALB、プライベートサブネットのアプリ層 EC2/Auto Scaling グループ、プライベートサブネットの RDS Multi-AZ)を作る。アプリは S3 の画像と Secrets Manager 経由の DB 認証情報を使って動作確認ページを表示し、ALB の DNS 名でアクセスできることを確認する。さらに CloudWatch アラームと SNS で、異常時にメール通知が届く仕組みを作る。
つくる構成
要件
通常のハンズオンより要件の数が多くなっています。フェーズ単位(06 を参照)で 1 つずつ片づけていきましょう。
| No | 要件 |
|---|---|
| 1 | リージョンは東京(ap-northeast-1)を使用する。 |
| 2 | VPC を 1 つ作成する(CIDR は自由、例:10.0.0.0/16)。 |
| 3 | パブリックサブネットを 2 つ(異なるアベイラビリティーゾーン)、プライベートアプリサブネットを 2 つ、プライベートデータサブネットを 2 つ、合計 6 つ作成する。 |
| 4 | インターネットゲートウェイ、NAT ゲートウェイ(1 つ、パブリックサブネットの片方に配置)、それぞれに対応するルートテーブルを作成する。 |
| 5 | 3 種類のセキュリティグループを作る:ALB 用(80 番をインターネットから許可)、アプリ用(80 番を ALB 用セキュリティグループからのみ許可)、DB 用(3306 番をアプリ用セキュリティグループからのみ許可)。 |
| 6 | プライベートデータサブネットを含む DB サブネットグループを作り、RDS for MySQL の Multi-AZ インスタンスを作成する(初期データベース名を指定する。例:appdb)。 |
| 7 | RDS の作成完了後、そのエンドポイントを使って Secrets Manager にシークレットを作成する(「その他のシークレットのタイプ」。キーは自由、例:host・username・password・dbname)。 |
| 8 | S3 バケットを 1 つ作成し、任意の画像ファイル(自分で用意したもの。例:小さなロゴ画像やアイコン)を 1 つアップロードする。 |
| 9 | EC2 用の IAM ロールを作成する(AmazonSSMManagedInstanceCore、手順 8 のバケットへの読み取り、手順 7 のシークレットの取得、をそれぞれ許可するポリシーをアタッチ)。 |
| 10 | 起動テンプレートを作成する(Amazon Linux 2023、IAM インスタンスプロフィールに手順 9 のロール、ユーザーデータで動作確認ページを準備する後述のスクリプトを設定)。 |
| 11 | ターゲットグループ・ALB(パブリックサブネット)とAuto Scaling グループ(プライベートアプリサブネット、希望容量 2・最小 2・最大 4)を作成する。 |
| 12 | ALB の DNS 名にブラウザでアクセスし、動作確認ページ(応答したサーバー名・S3 の画像・DB 接続状態)が表示されることを確認する。 |
| 13 | SNS トピック+E メールサブスクリプションを作成・確認(Confirm)する。CloudWatch アラームで ALB の UnHealthyHostCount を監視し、SNS へ通知する設定をする。 |
構築の進め方
構成が複雑なため、4 つのフェーズに分けて進めます。フェーズの区切りごとに、ピンク色の見出しと、フェーズの目的が書かれています。各フェーズの最後には ✅ の確認ポイントがあるので、そこまで終わったら一度立ち止まって確認してから次のフェーズに進みましょう。
-
フェーズ 1 ・ ネットワーク基盤を作る
3 層構成の土台になる VPC・サブネット・ルーティング・セキュリティグループを用意します。ここで作るネットワークの骨格が、この後のすべての層の置き場所になります。
-
マネジメントコンソールにサインインし、リージョンを東京に合わせる
画面右上のリージョンが「アジアパシフィック(東京)ap-northeast-1」になっていることを確認します。
-
VPC を 1 つ作成する
VPC コンソールで VPC を 1 つ作成します(CIDR は自由、例:
10.0.0.0/16)。 -
6 つのサブネットを作成する
異なる 2 つのアベイラビリティーゾーン(例:ap-northeast-1a・ap-northeast-1c)に、それぞれ 3 つずつ(パブリック・プライベートアプリ・プライベートデータ)、合計 6 つのサブネットを作成します。CIDR は重複しないように自由に決めます。
パブリックサブネット(例) 10.0.0.0/24(a)/ 10.0.1.0/24(c) プライベートアプリサブネット(例) 10.0.10.0/24(a)/ 10.0.11.0/24(c) プライベートデータサブネット(例) 10.0.20.0/24(a)/ 10.0.21.0/24(c) -
インターネットゲートウェイと NAT ゲートウェイを用意する
インターネットゲートウェイを作成し、VPC にアタッチします。続けて、ゾーン a 側のパブリックサブネットに Elastic IP を関連付けた NAT ゲートウェイを 1 つ作成します。
NAT ゲートウェイは 1 つで十分本来は各ゾーンに 1 つずつ置くとより堅牢になりますが、コストと複雑さを抑えるため、今回は構成全体で 1 つだけ作成します(09 の考察で、この点について考えます)。
-
ルートテーブルを 2 種類作成する
パブリック用ルートテーブル(0.0.0.0/0 → インターネットゲートウェイ)を 2 つのパブリックサブネットに関連付けます。プライベート用ルートテーブル(0.0.0.0/0 → NAT ゲートウェイ)を 4 つのプライベートサブネット(アプリ・データの両方)に関連付けます。
-
3 種類のセキュリティグループを作成する
用途ごとに分けることで、層をまたいだ最小限の通信だけを許可します。
ALB 用 インバウンド:HTTP(80)を 0.0.0.0/0から許可アプリ用 インバウンド:HTTP(80)を「ALB 用セキュリティグループ」からのみ許可 DB 用 インバウンド:MySQL/Aurora(3306)を「アプリ用セキュリティグループ」からのみ許可 -
ここまでで一度確認
VPC コンソールの「サブネット」一覧に 6 つのサブネットが、「ルートテーブル」一覧に 2 種類(パブリック用・プライベート用)が表示されていれば、フェーズ 1 は完了です。次に進みましょう。
-
フェーズ 2 ・ データ層を作る
プライベートデータサブネットに RDS の Multi-AZ インスタンスを作り、そのエンドポイントを Secrets Manager のシークレットにまとめます。
-
DB サブネットグループを作成する
RDS コンソールで、手順 4 で作った 2 つのプライベートデータサブネットを含む DB サブネットグループを作成します。
-
RDS for MySQL の Multi-AZ インスタンスを作成する
エンジン「MySQL」、可用性の設定で「マルチ AZ DB インスタンス」を選びます。VPC・DB サブネットグループ・セキュリティグループ(手順 7 の DB 用)を指定し、パブリックアクセスは「なし」にします。初期データベース名を指定します(例:
appdb)。マスターユーザー名・パスワードは自由に決めます。作成には時間がかかるMulti-AZ インスタンスの作成は 10 分前後かかることがあります。ステータスが「利用可能」になるまで待ちましょう。この間に、次のフェーズ 3 の S3 バケット作成(手順は後述)を先に進めておいても構いません。
-
RDS のエンドポイントを使って Secrets Manager のシークレットを作成する
RDS インスタンスの詳細から「エンドポイント」をコピーします。Secrets Manager コンソールで「新しいシークレットを保存する」→「その他のシークレットのタイプ」を選び、キー/値のペアとして
host(RDS のエンドポイント)・username・password・dbname(例:appdb)を登録します。シークレット名は自由に決めます(例:three-tier-db-secret)。ローテーションは無効のままで構いません。なぜ RDS を作ったあとにシークレットを作るの?シークレットの中に「RDS の実際のエンドポイント」を含める必要があるため、RDS のエンドポイントが確定してから、その内容をまとめてシークレットに保存します。順番を逆にすると、存在しないエンドポイントを保存してしまいます。
-
ここまでで一度確認
RDS のステータスが「利用可能」になっていること、Secrets Manager の詳細画面で「シークレット値を取得」から 4 つのキー/値が正しく表示されることを確認できれば、フェーズ 2 は完了です。
-
フェーズ 3 ・ アプリ層を作る
S3 バケットと IAM ロールを用意し、起動時に動作確認ページを自動で組み立てる EC2 を、ALB と Auto Scaling で本番らしく動かします。
-
S3 バケットを作成し、画像をアップロードする
S3 コンソールでバケットを 1 つ作成します(名前は全世界で一意にする必要があるため自由に決める)。バケットの中に、自分で用意した小さな画像ファイル(例:
logo.png)を 1 つアップロードします。 -
EC2 用の IAM ロールを作成する
信頼されたエンティティ「AWS のサービス」→「EC2」でロールを作成します。次の 3 つの権限を持たせます。
Systems Manager 用 AWS 管理ポリシー AmazonSSMManagedInstanceCoreをアタッチ(Session Manager で接続するために必要)S3 用 手順 8 のバケットに対する s3:GetObjectを許可するインラインポリシーを作成Secrets Manager 用 手順 12(フェーズ 2)のシークレットに対する secretsmanager:GetSecretValueを許可するインラインポリシーを作成なぜ AmazonSSMManagedInstanceCore を付けるの?アプリ層の EC2 はパブリック IP を持たないプライベートサブネットに置くため、SSH で直接ログインする手段がありません。代わりに Systems Manager の Session Manager を使えば、鍵ファイルもポート開放も使わずに、ローカルの PowerShell から
aws ssm start-sessionでこの EC2 の中に入れます。後述のトラブルシューティングで使います。 -
起動テンプレートを作成する(ユーザーデータを設定)
AMI は Amazon Linux 2023、インスタンスタイプは無料利用枠の対象(例:
t2.micro/t3.micro)を選びます。「高度な詳細」の「IAM インスタンスプロフィール」に手順 9 のロールを指定し、セキュリティグループは「アプリ用」を指定します。「ユーザーデータ」に次のスクリプトを貼り付けます(BUCKET_NAME・SECRET_NAMEは自分のものに置き換えてください)。#!/bin/bash # Web サーバーと MySQL クライアントを導入する dnf install -y httpd mariadb105 # Secrets Manager からシークレットを取得し、JSON を Python で展開する # Amazon Linux 2023 には AWS CLI と python3 が標準搭載されている SECRET_JSON=$(aws secretsmanager get-secret-value --secret-id SECRET_NAME --region ap-northeast-1 --query SecretString --output text) DB_HOST=$(echo "$SECRET_JSON" | python3 -c "import json,sys; print(json.load(sys.stdin)['host'])") DB_USER=$(echo "$SECRET_JSON" | python3 -c "import json,sys; print(json.load(sys.stdin)['username'])") DB_PASS=$(echo "$SECRET_JSON" | python3 -c "import json,sys; print(json.load(sys.stdin)['password'])") DB_NAME=$(echo "$SECRET_JSON" | python3 -c "import json,sys; print(json.load(sys.stdin)['dbname'])") # 取得した認証情報で RDS への接続を確認し、結果を変数に入れる if mysql -h "$DB_HOST" -u "$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "SELECT 1;" > /dev/null 2>&1; then DB_STATUS="OK" else DB_STATUS="NG" fi # S3 から画像を取得して Web サーバーの公開フォルダに置く aws s3 cp s3://BUCKET_NAME/logo.png /var/www/html/logo.png # 自分自身のホスト名を取得する(どのサーバーが応答したか分かるように) MY_HOSTNAME=$(hostname) # 動作確認用の index.html を書き出す cat > /var/www/html/index.html <<EOF <html><body style="font-family:sans-serif;text-align:center;padding:60px;"> <h1>3層構成 動作確認ページ</h1> <p>応答したサーバー: ${MY_HOSTNAME}</p> <img src="logo.png" style="max-width:200px"><br><br> <p>DB接続: ${DB_STATUS}</p> </body></html> EOF # Web サーバーを有効化・起動する systemctl enable httpd systemctl start httpd
スクリプトが何をしているか① httpd(Web サーバー)と mysql クライアントを入れる → ② Secrets Manager から認証情報を取得する → ③ その情報で RDS に接続できるか確認する → ④ S3 から画像を取得する → ⑤ 結果をまとめた 1 枚の HTML ページを作る → ⑥ Web サーバーを起動する、という流れです。この一連の処理は EC2 が起動するたびに 1 回だけ実行されます。
-
ターゲットグループと ALB を作成する
ターゲットグループ(タイプ:インスタンス、プロトコル HTTP・ポート 80、ヘルスチェックパス
/)を作成します。続けて ALB を作成します(スキームは「インターネット向け」、サブネットは 2 つのパブリックサブネット、セキュリティグループは「ALB 用」、リスナーは HTTP:80 で手順のターゲットグループに転送)。 -
Auto Scaling グループを作成する
手順 11 の起動テンプレートを使用し、サブネットは 2 つのプライベートアプリサブネットを指定します。希望容量 2・最小 2・最大 4 にします。「ロードバランシング」で手順 13 のターゲットグループにアタッチし、ヘルスチェックは「ELB(Elastic Load Balancing)を有効」にします。
-
ALB の DNS 名にアクセスして確認する
インスタンスが起動し、ターゲットグループのヘルスチェックが「Healthy」になるまで数分待ちます。ALB の詳細画面に表示されている「DNS 名」をブラウザにコピーしてアクセスし、動作確認ページが表示されることを確認します。何度かブラウザを再読み込みし、「応答したサーバー」の表示が 2 台のインスタンスの間で切り替わることも確認しましょう。
うまく表示されないときは Session Manager で調査するローカルの PowerShell から、Session Manager プラグインをインストール済みの状態で次のコマンドを実行すると、アプリ層の EC2 の中に入れます。
cat /var/log/cloud-init-output.logでユーザーデータの実行ログを確認できます。aws ssm start-session --target <インスタンスID>
-
ここまでで一度確認
ターゲットグループの「ターゲット」タブで 2 台とも「Healthy」になっていること、ALB の DNS 名でアクセスしたページに画像と「DB接続: OK」が表示されていれば、フェーズ 3 は完了です。
-
フェーズ 4 ・ 監視と通知を作る
これまでの 3 層構成に、異常が起きたら気づける仕組みを追加します。最後に、実際に異常を起こして通知が届く様子を観察します。
-
SNS トピックを作成し、Eメールサブスクリプションを確認する
SNS トピックを 1 つ作成し(タイプ「スタンダード」)、Eメールサブスクリプションで自分のメールアドレスを登録します。届いた確認メールの「Confirm subscription」リンクをクリックして確認を済ませます。
-
CloudWatch アラームを作成する
監視対象は ALB のメトリクス「UnHealthyHostCount」、対象のターゲットグループを指定します。しきい値「1 以上」、評価期間は短め(例:1 分間が 1 回)に設定し、アラーム発生時のアクションとして手順 16 の SNS トピックへの通知を指定します。
-
実際に異常を起こして、通知が届く様子を観察する(任意)
Auto Scaling グループのインスタンスを 1 つ選び、コンソールから終了(Terminate)します。ターゲットグループのヘルスチェックが一時的に「Unhealthy」になり、CloudWatch アラームが発生して、登録したメールアドレスに通知が届くことを確認します。その後、Auto Scaling グループが自動的に新しいインスタンスを起動し、しばらくすると台数が 2 台に戻り、アラームも自動的に元の状態に戻ることを確認します。
これが「自動で立て直る」ということ人が手動で新しいサーバーを立てなくても、Auto Scaling が指定した台数を保ち続けます。ALB は Healthy なインスタンスにだけアクセスを振り分けるため、復旧までの間も完全に停止することはありません。
つまずきポイント
構成が複雑な分、つまずきやすい箇所も増えますが、ここでは特に起きやすい 2 つに絞って先回りします。フェーズごとの ✅ 確認ポイントと合わせて活用してください。
「ALB の DNS 名にアクセスしても、502 や 504 エラーになる」
最も多い原因はセキュリティグループの許可不足です。「アプリ用」セキュリティグループが「ALB 用」セキュリティグループからの 80 番ポートを許可しているか確認しましょう。それでも解決しない場合は、Session Manager でアプリ層の EC2 に入り、systemctl status httpd と cat /var/log/cloud-init-output.log を確認してください。ユーザーデータのコピー時に余分な空白や全角文字が混ざっていないかも見直しましょう。
「画像までは表示されるのに、DB 接続だけ失敗する」
よくある原因は 3 つです。①「DB 用」セキュリティグループが「アプリ用」セキュリティグループからの 3306 番ポートを許可していない、②IAM ロールにシークレットを取得する権限(secretsmanager:GetSecretValue)が不足している、③シークレットの中の host の値が、RDS の実際のエンドポイントと違っている(コピーミスや、後からエンドポイントが変わった場合)。Session Manager で入り、ユーザーデータと同じコマンドを 1 行ずつ手で実行してみると、どこで失敗しているかが分かります。
完了チェック
要件の再確認ではなく、画面のどこを見れば達成を確認できるかをまとめました。複雑な構成なので、通常より項目が多くなっています。
- VPC の「サブネット」一覧に、3 種類×2 ゾーン=6 つのサブネットが表示されている。
- RDS のステータスが「利用可能」で、「マルチ AZ」が有効になっている。
- Secrets Manager のシークレット詳細から、4 つのキー/値が正しく取得できる。
- ターゲットグループの「ターゲット」タブで、2 台とも「Healthy」と表示されている。
- ALB の DNS 名にブラウザでアクセスすると、応答したサーバー名・画像・「DB接続: OK」が表示される。
- ブラウザを何度か再読み込みすると、「応答したサーバー」の表示が 2 台のインスタンスの間で切り替わる。
- SNS のサブスクリプションのステータスが「Confirmed」になっている。
- インスタンスを 1 つ終了させると、通知メールが届き、その後 Auto Scaling が自動的に台数を 2 台に戻す。
考えてみよう
手を動かすことに加えて、次の問いに自分の言葉で答えられるようにしておくと、理解がより深まります。
- 今回の構成の中で、単一障害点(1 つが壊れると全体に影響する箇所)になりうるのはどこでしょうか。
ヒント
ALB・アプリ層・データ層は、いずれも 2 つのアベイラビリティーゾーンに分散させました。一方で、NAT ゲートウェイは構成全体で 1 つだけでした。NAT ゲートウェイのあるゾーンに何かあったら、プライベートサブネットのアプリ層の外向き通信はどうなるかを考えてみましょう。 - アプリのコードを変更してデプロイし直したい場合、今の構成だとどういう手順になりそうでしょうか。
ヒント
起動テンプレートのユーザーデータを直接書き換えても、すでに動いているインスタンスには反映されません。新しいバージョンの起動テンプレートを作り、Auto Scaling グループのインスタンスを入れ替える(更新)という考え方から、どんな手順が必要になるか考えてみましょう。 - この構成のコストを下げるとしたら、どこから手をつけられそうでしょうか。
ヒント
RDS の Multi-AZ 配置、NAT ゲートウェイ、Auto Scaling の最小台数は、いずれも「可用性」と「コスト」のトレードオフになっています。本番運用で本当に必要な可用性のレベルと、開発・検証用途で許容できる可用性のレベルを比べながら考えてみましょう。
後片づけ
作成したリソースが非常に多いため、作った順番とおおむね逆の順番で片づけていきます。1 つずつ確実に進めましょう。
- Auto Scaling グループを削除する:先に希望容量・最小・最大をすべて 0 に変更してインスタンスを終了させてから、グループ自体を削除する。
- ALB を削除する。
- ターゲットグループを削除する。
- 起動テンプレートを削除する。
- IAM ロールを削除する。
- S3 バケットを削除する:中の画像オブジェクトを空にしてから削除する。
- Secrets Manager のシークレットを削除する。
- RDS インスタンスを削除する:最終スナップショットを作成するかどうかを選べます。残す予定がなければ「スナップショットを作成しない」を選んでよい。
- DB サブネットグループを削除する。
- CloudWatch アラームを削除し、SNS のサブスクリプション・トピックを削除する。
- NAT ゲートウェイを削除する。
- Elastic IP アドレスの関連付けを解放する。
- ルートテーブルを削除する(デフォルトのものは残す)。
- 6 つのサブネットを削除する。
- インターネットゲートウェイをデタッチしてから削除する。
- 3 種類のセキュリティグループを削除する。
- VPC を削除する。
削除を忘れると、課金が継続しやすいリソース
NAT ゲートウェイと Elastic IP、RDS インスタンスは、起動している(または関連付けられている)だけで時間単位の料金が発生し続けます。検証が終わったら、後片づけを後回しにせず、できるだけ早く削除しましょう。デフォルト VPC や、他で使っているリソースを間違えて削除しないようにも注意してください。
コストに関する注意: このハンズオンは、このシリーズの中で最もコストがかかる構成です。課金される主な要素は次のとおりです——RDS Multi-AZ インスタンス(シングル AZ の約 2 倍の料金)、NAT ゲートウェイ(起動時間+データ処理量)、Application Load Balancer(起動時間+LCU)、EC2 インスタンス 2〜4 台、Secrets Manager(シークレット数+API 呼び出し)。VPC・サブネット・ルートテーブル・セキュリティグループ・IAM ロール・S3 バケット(保存量がごく小さい場合)・SNS・CloudWatch アラームの利用には、通常ほとんど料金はかかりません。検証が終わったら、特に NAT ゲートウェイ・Elastic IP・RDS インスタンスを削除し忘れないよう、10 の後片づけを速やかに行ってください。