1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【AWS ハンズオン】おみくじアプリで学ぶ! 冗長性を持たせた Web3 層構成の構築ガイド

1
Last updated at Posted at 2026-03-07

はじめに

Web 構築の基本として 3 層構成という形があることを知りました。
今回は、3 層構成を実際に AWS で構成してみようと思います。(Python でおみくじアプリを作成します)

初めて AWS を利用したため、時間がかかりましたが、調べたり、AI を活用することで構築できたので、記録として残しておきます。

また、構築手順も記載しますので、同様の手順を踏んでいただければ、初めての方でも 3 層構成ができるようにしていますので、自己学習の参考になれば幸いです。

Info
次回の記事で、構築した環境で行ったポイントについてまとめています。
記事の末尾に URL を添付しておりますので、併せてご覧いただけますと幸いです。

3 層構成とは

そもそも 3 層構成についてですが、プレゼンテーション層 ・ アプリケーション層 ・ データ層の 3 つに分けて構成することです。

メリットやデメリットについては簡単に調べてみましたが、以下のようなものがあります。

メリット デメリット
負荷分散できる 各層でのデータのやり取りによるネットワーク遅延や負荷
保守性の向上 開発やテストの工程複雑化
拡張性が高い 導入コストの上昇

メリットデメリットについては、こちらの YouTube を参考にしました。

構築内容

今回は、以下のような構成図の元、3 層構成を構築していこうと思います。

全体像把握のために、簡単に作成してしてみました。

image.png

せっかくなので、冗長性を持たせた構成にしようと思い、2 つのアベイラビリティゾーンで構築します。

プライベートサブネットから外向きの通信として、AWS のマネージドサービスである NAT Gateway がありますが、利用料金も高く、学習が目的のため、今回は NAT インスタンスで代用しています。

また、今回はおみくじアプリを Python を利用して作成しています。

プログラミング経験はほぼないため、AI に丸投げとなっています。
(Web アプリの見た目の部分がシンプルでは面白さに欠けると思い、ポケモンバージョンで作成してもらうように指示しました笑)

利用するリソース

VPC (Amazon Virtual Private Cloud) × 1

Internet Gateway × 1

サブネット × 6

ALB (Application Load Balancer) × 1

EC2 (Amazon EC2) × 5 (内 1 つは NAT インスタンス)

Elastic IP × 1

AWS Network Manager

RDS (Amazon Relational Database Service) × 1 (マルチ AZ に対応しているので 1 つとしています。)

今回は、AWS の無料枠で行ったため、利用料金は 0 円で構築することができました!

構築手順

  1. VPC の作成
  2. サブネットの作成
  3. Internet gateway の作成
  4. セキュリティグループ (SG) の作成
  5. NAT インスタンスのデプロイ
  6. ルートテーブルの設定
  7. Web サーバー A と AP サーバー A の作成
  8. RDS の作成と通信確認
  9. RDS ・ AP サーバー A ・ Web サーバー A の構築
  10. ALB の作成
  11. 冗長化前の単一アベイラビリティゾーンの構成が完成
  12. AZC に Webサーバー C と AP サーバー C の作成と構築
  13. ALB のターゲットグループに Webサーバー C を追加
  14. RDS の設定を「マルチ AZ」に変更

今まで簡易的な Web サーバーの構築経験はありますが、階層ごとやネットワーク設定をがっつりはしていなかったので、一旦冗長構成せずに単一のアベイラビリティゾーンで構成してから、冗長するような手順としています。

構築作業開始

先に AWS アカウントの作成のほうだけお願いします。

1. VPC の作成

・ 名前タグ : omikuji-vpc
・ IPv4 CIDR ブロック : 10.0.0.0/16

VPC 作成画面
image.png

VPC 作成後、[アクション] > [VPC 設定の編集] から [DNS 解決を有効化] と [DNS ホスト名を有効化] の両方にチェックを入れて保存する。

2. サブネットの作成

名前 AZ IPv4 CIDR 役割
Public-subnet-A 東京 a 10.0.1.0/24 ALB,NAT インスタンス
Public-subnet-C 東京 c 10.0.2.0/24 ALB
Private-subnet-A1 東京 a 10.0.10.0/24 WebServer-A,APServer-A
Private-subnet-C1 東京 c 10.0.11.0/24 WebServer-B,APServer-B
Private-subnet-A2 東京 a 10.0.20.0/24 RDS (メイン)
Private-subnet-C2 東京 c 10.0.21.0/24 RDS (スタンバイ)

上記の表に沿ってサブネットの設定をします。

Info
サブネット設定で「Public-subnet-A」と「Public-subnet-C」の [パブリック IPv4 アドレスを自動割り当て] を有効にすることで、NAT インスタンス作成時に楽になります。

3. Internet gateway の作成

名前 : omikuji-igw

  1. [インターネットゲートウェイ] メニューから作成します。
  2. 作成直後は、「Detached」 となっていますので、アクションから [VPC にアタッチ] を選択し、作成した VPC を選択します。

4. セキュリティグループ (SG) の作成

ALB はまだ作成しませんが、先にセキュリティグループの作成をしておきます。
また、作成画面で [説明] は必須項目のため、何かしら入力しておいてください。

SG 名 インバウンド アウトバウンド
ALB-SG ポート : 80.443 送信元 : 0.0.0.0/0 (Internet Gateway) ポート : 80.443 送信先 : Web-Server-SG
Web-Server-SG ポート : 80 送信元 : ALB-SG [ポート : 80.8080 送信先 : AP-Server-SG] [ポート : 80.443 送信先 : 0.0.0.0/0]
AP-Serveer-SG ポート : 80.8080 送信元 : Web-Server-SG [ポート : 3306 送信先 : RDS-SG] [ポート : 80.443 送信先 : 0.0.0.0/0]
RDS-SG ポート : 3306 送信元 : AP-Server-SG なし
NAT-SG ポート : [すべてのプロトコル 送信元 : Web-Server-SG と AP-Server-SG] [ポート : 22 送信元 : 自分の IP] [ポート : 22 送信元 : 自分の IP] [ポート : 80.443 送信先 : 0.0.0.0/0]

Info
基本的にアウトバウンドの通信はデフォルトのすべて許可で問題ありません。
今回はセキュリティも意識して構築しようと思ったので、設定しています。

なお、今回は、セキュリティグループを基準に設定を行っているため、アウトバウンド通信を設定する場合は、一度インバウンド設定を行った後に、再編集でアウトバウンド設定を行う必要があります。

5. NAT インスタンスのデプロイ

指定のない項目はデフォルト設定です。

5-1. NATインスタンスの内部設定

EC2 ダッシュボードの左メニューの AMI から検索画面 (パブリックイメージ) で「NAT」と検索し、コミュニティ AMI タブからamzn-ami-vpc-natを選択し、[AMI からインスタンスを起動] をクリックします。

5-2. EC2 の作成

・ OS (AMI) : amzn-ami-vpc-nat
・ インスタンスタイプ : t3.micro
・ ネットワーク : pubric-subnet-A
・ セキュリティグループ : NAT-SG
・ パブリック IP : 有効化
・ キーペア : 新規作成 (今回の構築自体に大きな影響はありませんが、ネットワーク確認のためにアクセスできるように作成します)

5-3. 詳細設定

  1. 作成したインスタンスを右クリック > [ネットワーキング] > [ソース/宛先チェックを変更] を選択します。
  2. [停止] にチェックを入れて保存します。

5-4. Elastic IP の割り当て

  1. VPC のコンソール画面左メニューの [Elastic IP] から [Elastic IP アドレスを割り振る] でデフォルト設定のまま [割り振る] をクリックします。
  2. 作成した Elastic IP を右クリックし、[Elastic IP アドレスを関連付ける] を選択します。
  3. 以下の内容で設定し、[関連付ける] をクリックします。
    ・ リソースタイプ : インスタンス
    ・ インスタンス : NATインスタンス

6. ルートテーブルの設定

2 種類のルートテーブルを作成します。

6-1. パブリック用ルートテーブル

・ 名前 : public-rt
・ VPC : omikuji-vpc
・ ルート編集 : 0.0.0.0/0 → [Internet Gateway]
・ サブネットの関連付け : Public-subnet-APublic-subnet-Cを選択

image.png

ルート編集やサブネットの関連付けは、AWS コンソール画面右上の [アクション] ボタンか、対象のルートテーブルを右クリックしてから設定画面に移行してください。

6-2. プライベート用ルートテーブル

・ 名前 : private-rt
・ ルート編集 : 0.0.0.0/0 → NAT インスタンス ID
・ サブネットの関連付け : Private-subnet-A1Private-subnet-C1を選択

image.png

6-3. NAT インスタンスの通信確認

  1. PC のコマンドプロンプト or ターミナルを起動します。
  2. 以下のコマンドを入力し、NAT インスタンスに接続します。
bash
ssh -i "あなたの鍵.pem のファイルパス" ec2-user@"Elastic IP" 

"あなたの鍵 ~" の部分はご自身環境に合わせて確認し、変更してコマンドを実行してください。

3. 通信確認

bash
curl google.com 

上記コマンド実行後、以下の内容が返ってきたら通信成功です。

<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8"> 
<TITLE>301 Moved</TITLE></HEAD><BODY> 
<H1>301 Moved</H1> 
The document has moved 
<A HREF="http://www.google.com/">here</A>. 
</BODY></HTML> 

7. Web サーバー A と AP サーバー A の作成

指定のない項目はデフォルト設定です。

7-1. Webサーバー A の情報

・ 名前 : Web-Server-A
・ OS (AMI) : Amazon Linux 2023 AMI
・ インスタンスタイプ : t3.micro
・ キーペア : なし
・ IAM インスタンスプロフィール : 以下で作成した 「AmazonSSMManagedInstanceCore」 権限を持つロールを選択

[新しい IAM プロファイルの作成] から別タブを開いてロールを作成します。


IAM ロール作成画面
ステップ 1
・ 信頼されたエンティティを選択 : AWS のサービス
・ サービスまたはユースケース : EC2
・ ユースケース : EC2 Role for AWS Systems Manager → 次へ

ステップ 2
次へ

ステップ 3
・ ロール名 : 任意 (今回は、SSM) → ロールを作成


ロール作成後、EC2 作成タブに戻り、[新しい IAM プロファイルの作成] の更新ボタンをクリックすると、作成したロールを選択できるようになります。

ネットワーク設定
・ VPC : omikuji-vpc
・ サブネット : private-subnet-A1
・ パブリック IP : 無効
・ セキュリティグループ : Web-Server-SG

Info
Web と AP サーバーの作成後はプライベート IP アドレスを控えておくと後の手順をスムーズに行えます。

7-2. AP サーバー A の情報

・ 名前 : AP-Server-A
・ OS (AMI) : Amazon Linux 2023 AMI
・ インスタンスタイプ : t3.micro
・ キーペア : なし
・ IAM インスタンスプロフィール : 「AmazonSSMManagedInstanceCore」 権限を持つロールを選択

ネットワーク設定
・ VPC : omikuji-vpc
・ サブネット : private-subnet-A1
・ パブリック IP : 無効
・ セキュリティグループ : AP-Server-SG

7-3. 作成した EC2 の疎通確認

  1. AWS コンソールの検索バーで「Reachability Analyzer」と検索し、[VPC Reachability Analyzer] をクリックします。
  2. [パスの作成と分析] をクリックし、以下の設定を行います。

・ パス設定 : 任意の名前
・ パスの送信元
・ 送信元タイプ : instance
・ 送信元 : Web-Server-A
・ パスの送信先
・ 送信先タイプ : instance
・ 送信先 : AP-Server-A
・プロトコル : TCP

3. [パスの作成と分析] をクリックします。
4. 分析の項目のステータスで 「到達可能」 になっていたら通信成功

image.png

8. RDS の作成と通信確認

8-1. DB サブネットグループの作成

RDS コンソール > 左メニュー [サブネットグループ] > [DB サブネットグループを作成] をクリックし、以下の内容で設定します。

・ 名前 : omikuji-db-subnet-group1
・ VPC : omikuji-vpc
・ サブネットの追加 :
・ AZ : 「東京 a」と「東京 c」を選択
・ サブネット : 手順 2 で作成したサブネット (private-subnet-A2 と private-subnet-B2 を選択します。)

8-2. RDS 本体の作成

・ データベース作成方法 : フル設定
・ エンジンの選択 : MySQL
・ テンプレート : 無料利用枠

設定
・ DB インスタンス識別子 : omikuji-db
・ マスターユーザー名 : admin
・ マスターパスワード : 独自のパスワード (忘れないよう控えておいてください)
・ インスタンス 設定 : db.t4g.micro

接続
・ VPC : omikuji-vpc
・ DB サブネットグループ : omikuji-db-subnet-group1
・ パブリックアクセス : なし
・ VPC セキュリティグループ : RDS-SG
・ アベイラビリティーゾーン : ap-northest-1a (東京 a)

8-3. SSM で AP サーバー A にログイン

ログイン手順

  1. EC2 コンソールを開き、一覧から接続するインスタンスにチェックを入れます。
  2. 画面右上の [接続] ボタンをクリックします。
  3. 「インスタンスに接続」 の画面から [SSM Session Manager] を選択します。
  4. [接続] ボタンをクリックします。
  5. 接続が完了し、ターミナル画面となります。

注意
[接続] ボタンが押せない場合、IAM ロールが反映されていない可能性があります。
そのため、数分まってブラウザを更新してから再度試してみてください。

ログイン後
ネットワークへの疎通確認

bash
curl –I https://google.com 

結果が OK 以外であれば、NAT インスタンスの設定やルートテーブル、セキュリティグループの設定を再確認してください。

Info
今回は、おみくじアプリを引いたときに冗長性の確認ができるように処理を行った AP サーバーの情報が表示されるようにしています。
以下のコマンドでホスト名を変更しておくことで構築後の動作結果が分かりやすくなります。
sudo hostnamectl set-hostname AP-server-A

hostnameコマンドで変更されたことを確認できます。

8-4. エンドポイントの確認と疎通確認

RDS のステータスが 「利用可能」 になったら、接続用のエンドポイントを確認します。

  1. 作成した DB の詳細画面にある 「エンドポイント (例 : omikuji-db.xxxx.ap-northeast-1.rds.amazonaws.com)」 をコピーしてメモします。

※ 後述の Python スクリプトで使用します。

2. AP サーバー A にSSM でログインして、以下のコマンドを入力します。

bash
sudo dnf install nmap –y 
nmap -Pn -p 3306 "RDS のエンドポイント" 

3306/tcp openと表示されると疎通成功です。

9. RDS ・ AP サーバー A ・ Web サーバー A の構築

9–1. RDS の構築

  1. AP サーバーに SSM で接続し、OS のアップデートと MySQL のインストールします。
bash
sudo dnf update –y 
p mariadb105 -y 

2. RDS にログインします。

bash
mysql -h "RDS のエンドポイント" -u admin -p 

上記コマンド入力後、RDS 作成時に設定したパスワードを入力します。

info
パスワード入力時は何も表示されませんが、入力されているので、自分を信じてEnterを押しましょう!

3. データを投入します。
データベースにログイン後、プロンプトがmysql>という表示になったら、以下の SQL を実行します。

SQL Query
CREATE DATABASE omikuji_db;
USE omikuji_db; 
CREATE TABLE fortunes ( 
    id INT AUTO_INCREMENT PRIMARY KEY, 
    result VARCHAR(10), 
    message TEXT 
); 
INSERT INTO fortunes (result, message) VALUES   
('大吉', 'こうかは ばつぐんだ! なにをやっても うまくいくぞ!'),  
('中吉', 'きゅうしょに あたった! ラッキーなことが おきそうだ。'),  
('小吉', 'まずまずの けっかだ。 じっくり レベルを あげていこう。'),  
('凶',   'おみくじは こんらんしている! ひとまず やすんで 態勢を たてなおそう。'); 

4. 入力内容を確認する。

SQL Query
SELECT * FROM fortune; 

表形式で表示されれば、データ投入の完了です。

すべて実行後は、exitコマンドもしくはCtrl + Dで AP サーバーのターミナルに戻ってください。

9-2. AP サーバー の構築

  1. AP サーバーに SSM で接続し、OS のアップデートと Python のインストールします。
bash
sudo dnf update –y 
sudo dnf install python3 python3-pip  

2. アプリで使用するライブラリのインストールをします。

bash
pip3 install flask mysql-connector-python gunicorn 
pip3 install gunicorn 

3. アプリ (app.py) の作成

bash
mkdir ~/omikuji-app 
cd ~/omikuji-app 
vi app.py 

4. vi エディター起動後に、以下のスクリプトを張り付けます。

Python スクリプト
vi エディター
# app.py 
from flask import Flask, jsonify 
import mysql.connector 
import socket 
import random 

app = Flask(__name__) 

# RDSの接続情報(ここを書き換えてください) 
db_config = { 
    'host': 'your-rds-endpoint.xxxx.ap-northeast-1.rds.amazonaws.com', 
    'user': 'admin', 
    'password': 'Atakumia0520', 
    'database': 'omikuji_db' 
} 

@app.route('/api/fortune') 
def get_fortune(): 
    try: 
        # 1. RDSに接続 
        conn = mysql.connector.connect(**db_config) 
        cursor = conn.cursor(dictionary=True) 

        # 2. ランダムに1件取得するクエリ 
        cursor.execute("SELECT result, message FROM fortunes ORDER BY RAND() LIMIT 1") 
        row = cursor.fetchone() 

        # 3. 自分のホスト名を取得 
        my_hostname = socket.gethostname() 

        # 4. 接続を閉じる 
        cursor.close() 
        conn.close() 

        # 5. 全てをまとめて返す 
        return jsonify({ 
            "result": row['result'], 
            "message": row['message'], 
            "ap_host": my_hostname 
        }) 

    except Exception as e: 

        return jsonify({"error": str(e), "ap_host": socket.gethostname()}), 500 

if __name__ == '__main__': 
    app.run(host='0.0.0.0', port=5000) 

注意
スクリプト上部にあります、host,user,password,databaseはご自身の環境に合わせて変更してください。

hostは、RDS のエンドポイント
userは、RDS のユーザー名 (手順通りに行った場合は、adminのままのため変更不要)
passwordは、ご自身で設定したパスワード
databaseは、RDS で作成したデータベース名 (手順通りに行った場合は、adminのままのため変更不要)

Info
スクリプト貼り付け後は、Esc キークリック後に:qwを入力することで、ファイルを保存して終了できます。

また、cat app.pyで中身を確認することができます。

5. AP サーバーの設定ファイルを編集します。

bash
sudo vi /etc/systemd/system/gunicorn.service 

設定ファイル内

vi エディター
[Unit] 
Description=Gunicorn instance to serve my fortune app 

After=network.target 
  
[Service] 
# 実行するユーザーを指定 
User=ssm-user 
Group=ssm-user 

# app.pyがあるディレクトリを指定 
WorkingDirectory=/home/ssm-user/omikuji-app 

# Gunicornのフルパスを指定して実行 
ExecStart=/home/ssm-user/.local/bin/gunicorn --workers 3 --bind 0.0.0.0:8080 app:app 

[Install] 
WantedBy=multi-user.target 

6. 設定ファイルの内容を反映させます。

bash
sudo systemctl daemon-reload 

7. アプリを起動して待ち受け状態にします。

bash
sudo systemctl start gunicorn 
sudo systemctl enable gunicorn 
sudo systemctl status gunicorn 

サービスを起動した状態で、Web-Server-A にアクセスし、以下のコマンドを実行すると、データベースのデータを取得できることが確認できます。

bash
curl -s http://"APサーバーのプライベートIP":8080/api/fortune | python3 -m json.tool --no-ensure-ascii 

9-3. Web サーバーの構築

SSM で Web サーバーに接続します。

  1. OS アップデートと Nginx をインストールします。
bash
sudo dnf update –y 
sudo dnf install nginx -y 

2. HTML を配置する専用のフォルダを作成します。

bash
sudo mkdir –p /var/www/omikuji 

3. ファイルを作成し、HTML スクリプトを張り付けます。

bash
sudo vi /var/www/omikuji/index.html 
HTML スクリプト
vi エディター
<!DOCTYPE html> 
<html lang="ja"> 
<head> 
    <meta charset="UTF-8"> 
    <title>ポケモン風おみくじ</title> 
    <style> 
        body { 
            background-color: #f0f0f0; 
            font-family: 'Courier New', Courier, monospace; /* ドット絵風フォントの代用 */ 
            display: flex; 
            flex-direction: column; 
            align-items: center; 
            padding-top: 50px; 
        } 
        /* モンスターボール風のヘッダー */ 
        .header { 
            background: linear-gradient(to bottom, #ff0000 50%, #ffffff 50%); 
            border: 8px solid #333; 
            border-radius: 50%; 
            width: 100px; 
            height: 100px; 
            position: relative; 
            margin-bottom: 20px; 
        } 
        .header::after { 
            content: ''; 
            position: absolute; 
            top: 50%; left: 50%; 
            transform: translate(-50%, -50%); 
            width: 30px; height: 30px; 
            background: white; 
            border: 5px solid #333; 
            border-radius: 50%; 
        } 
        /* メッセージウィンドウ風 */ 
        .window { 
            background-color: white; 
            border: 6px double #333; 
            border-radius: 10px; 
            padding: 20px; 
            width: 80%; 
            max-width: 500px; 
            box-shadow: 5px 5px 0px #bbb; 
        } 
        .server-info { 
            font-size: 12px; 
            color: #666; 
            margin-bottom: 10px; 
        } 
        .btn { 
            background-color: #4CAF50; 
            color: white; 
            border: 4px solid #2e7d32; 
            padding: 10px 20px; 
            font-size: 18px; 
            cursor: pointer; 
            width: 100%; 
            margin-top: 20px; 
        } 
        .btn:active { transform: translateY(2px); } 
        .result-box { 
            margin-top: 20px; 
            min-height: 80px; 
            font-weight: bold; 
        } 
        .type-label { 
            display: inline-block; 
            background: #A8A878; 
            color: white; 
            padding: 2px 8px; 
            border-radius: 5px; 
            font-size: 12px; 
        } 
    </style> 
</head> 
<body> 

    <div class="header"></div> 

    <div class="window"> 
        <div class="server-info"> 
            エリア: <strong>MY_HOSTNAME</strong> (Web Layer) 
        </div> 
      
        <div id="display_text"> 
            あ! やせいの おみくじが とびだしてきた! 
        </div> 

        <button class="btn" onclick="getFortune()">おみくじを ひく!</button> 
        <div class="result-box" id="result_area" style="display:none;"> 
            <span class="type-label">RESULT</span> 
            <h2 id="fortune_result" style="margin: 10px 0;"></h2> 
            <p id="fortune_message"></p> 
            <hr> 
            <div class="server-info"> 
                AP サーバー名: <span id="ap_server"></span> (AP Layer) 
            </div> 
        </div> 
    </div> 

    <script> 
        function getFortune() { 
            const btn = document.querySelector('.btn'); 
            btn.disabled = true; 
            btn.innerText = 'つかまえている...'; 
  
            fetch('/api/fortune') 
                .then(response => response.json()) 
                .then(data => {                   document.getElementById('result_area').style.display = 'block'; 
                    document.getElementById('fortune_result').innerText = data.result + ' を つかまえた!'; 
                    document.getElementById('fortune_message').innerText = data.message; 
                    document.getElementById('ap_server').innerText = data.ap_host; 
                                   document.getElementById('display_text').innerText = 'おめでとう! おみくじを ゲットしたぞ!'; 
                    btn.disabled = false; 
                    btn.innerText = 'もういちど ひく!'; 
                }) 
                .catch(err => { 
                    alert("つうしん エラー! ボールが もどってきた!"); 
                    btn.disabled = false; 
                }); 
        } 
    </script> 
</body> 
</html> 

Info
MY_HOSTNAMEの部分を「Web-Server-A」に書き換えることで、動作検証時にどちらの Web サーバーにつながっているかわかりやすくなります。

4. Nginx の設定ファイルを作成します。

bash
sudo vi /etc/nginx/conf.d/omikuji.conf 

以下の内容を貼り付けます。

vi エディター
server { 
    listen 80; 
    server_name _; 

    # 表画面(HTML)の表示 
    location / { 
        root /var/www/omikuji; 
        index index.html; 
    } 

    # おみくじAPIをAPサーバーへ転送(プロキシ設定) 
    location /api/fortune { 
        proxy_pass http://[APサーバーのプライベートIP]:8080; 
        proxy_set_header Host $host; 
        proxy_set_header X-Real-IP $remote_addr; 
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
    } 
} 

5. メインの設定ファイルを編集します。

bash
sudo vi /etc/nginx/nginx.conf 

以下の画像のように、server ブロックの一部を#でコメントアウトします。

編集前
image.png

編集後
image.png

6. サービスの再起動

bash
sudo systemctl restart nginx 

7. 設定にミスがないかチェックします。

bash
sudo nginx –t 

8. Nginxを起動します。

bash
sudo systemctl start nginx 
sudo systemctl enable nginx 

10. ALB の作成

EC2 のダッシュボードの左メニューから [ロードバランシング] > [ターゲットグループ] を選択します。

10-1. ターゲットグループの作成

RDS の時のように先にターゲットグループから作成します。

・ ターゲットの種類 : インスタンス
・ 名前 : web-tg
・ プロトコル/ポート : HTTP/80
・ VPC : omikuji-vpc
・ ヘルスチェック : デフォルト設定
・ ターゲットの登録 : Web-Server-A (保留中として以下を含める)

10-2. ALB 本体の作成

・ ロードバランサータイプ : Application Load Balancer
・ 名前 : web-alb
・ スキーム : インターネット向け
・ IP アドレスタイプ : IPv4
・ セキュリティグループ : ALB-SG

■ ネットワークマッピング
・ VPC : omikuji-vpc
・ サブネット : Pubric-Subunet-A と Pubric-Subnet-C を選択

■ リスナーとルーティング
・ プロトコル : HTTP/ポート : 80
・ デフォルトアクション : web-tg

11. 冗長化前の単一アベイラビリティゾーンの構成が完成

ALB の DNS 名をブラウザに入力することで、アプリの動作を確認できます。

また、アクセスをした Web サーバーと処理をした AP サーバーが表示されています。
image.png

12. AZB に Webサーバー C と AP サーバー C の作成と構築

12-1. AP サーバー C の作成

・ 名前 : AP-Server-C
・ OS (AMI) : Amazon Linux 2023 AMI
・ インスタンスタイプ : t3.micro
・ キーペア : なし
・ IAM インスタンスプロフィール : 「AmazonSSMManagedInstanceCore」 権限を持つロールを選択

ネットワーク設定
・ VPC : omikuji-vpc
・ サブネット : private-subnet-B1
・ パブリック IP : 無効
・ セキュリティグループ : AP-Server-SG

12-2. Webサーバー C の作成

・ 名前 : Web-Server-C
・ OS (AMI) : Amazon Linux 2023 AMI
・ インスタンスタイプ : t3.micro
・ キーペア : なし
・ IAM インスタンスプロフィール : 「AmazonSSMManagedInstanceCore」 権限を持つロールを選択

ネットワーク設定
・ VPC : omikuji-vpc
・ サブネット : private-subnet-B1
・ パブリック IP : 無効
・ セキュリティグループ : Web-Server-SG

HTML のファイル設定までは Web サーバー A と同様です。

Info
HTML 内の MY_HOSTNAME を Web-Server-B へ変更を忘れないようにしてください。

12-3. AP サーバー C の構築手順

AP サーバー A と手順は同様のため、手順 9-2 から再度確認し、構築してください。

Info
AP サーバー A と同様にホスト名を変更しておくことで構築後の動作結果が分かりやすくなります。
sudo hostnamectl set-hostname AP-server-C

hostnameコマンドで変更されたことを確認できます。

12-4. Web サーバー C の構築

SSM で Web サーバーに接続します。

9-3 の手順 3 までは、同様の手順となりますので、再度確認しながら構築をしてください。

※ HTML の作成が完了した後の手順です。

  1. Nginx 設定ファイルを作成します。
bash
sudo vi /etc/nginx/conf.d/omikuji.conf 

以下の内容を貼り付けます。

注意
[AP-Server-ABのプライベートIP] (2 箇所) の部分は、ご自身の環境に合わせて変更してください。

vi エディター
# --- 1. 宛先グループの定義 (ここを書き換える) --- 
upstream my_ap { 
    # AP-Server-AのプライベートIPを記入 
    server [10.0.10.xx]:8080 max_fails=3 fail_timeout=30s; 
     
    # AP-Server-CのプライベートIPを記入 
    server [10.0.11.yy]:8080 max_fails=3 fail_timeout=30s; 
} 

# --- 2. サーバーの設定 --- 
server { 
    listen 80; 
    server_name _; 

    # HTMLの場所 
    location / { 
        root /var/www/omikuji; 
        index index.html; 
    }  

    # APIの転送設定 (宛先にグループ名「my_ap」を指定) 
    location /api/fortune { 
        proxy_pass http://my_ap; 
      
        proxy_set_header Host $host; 
        proxy_set_header X-Real-IP $remote_addr; 
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
    } 
} 

以下は、Web サーバー A の時と重複しますが、記載しておきます。

2. メインの設定ファイルを編集

bash
sudo vi /etc/nginx/nginx.conf 

編集前
image.png

編集後
image.png

3. サービスの再起動

bash
sudo systemctl restart nginx 

4. 設定にミスがないかチェックします。

bash
sudo nginx –t 

5. Nginxを起動します。

bash
sudo systemctl start nginx 
sudo systemctl enable nginx 

12-5. Web サーバー A の設定ファイルを再編集

最初の設定ファイルの内容では、Web サーバー A からは、AP サーバー A にしか通信されません。

冗長性のために、Web サーバー A から AP サーバー C にも通信されるように書き換える必要があります。

設定ファイルの内容は、Web サーバー C の内容と同じです。

  1. 設定ファイルを開きます。
bash
sudo vi /etc/nginx/conf.d/omikuji.conf 

2. 内容を編集します。

vi エディター
# --- 1. 宛先グループの定義 (ここを書き換える) --- 
upstream my_ap { 
    # AP-Server-AのプライベートIPを記入 
    server [10.0.10.xx]:8080 max_fails=3 fail_timeout=30s; 
     
    # AP-Server-CのプライベートIPを記入 
    server [10.0.11.yy]:8080 max_fails=3 fail_timeout=30s; 
} 

# --- 2. サーバーの設定 --- 
server { 
    listen 80; 
    server_name _;   

    # HTMLの場所 
    location / { 
        root /var/www/omikuji; 
        index index.html; 
    } 

    # APIの転送設定 (宛先にグループ名「my_ap」を指定) 
    location /api/fortune { 
        proxy_pass http://my_ap;        

        proxy_set_header Host $host; 
        proxy_set_header X-Real-IP $remote_addr; 
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
    } 
} 

注意
[AP-Server-ACのプライベートIP] (2 箇所) の部分は、ご自身の環境に合わせて変更してください。

3. 構文チェックと設定の再読み込みをします。

bash
sudo nginx -t  
sudo systemctl reload nginx 

13. ALB のターゲットグループに Webサーバー C を追加

AWS マネジメントコンソールの EC2 ダッシュボードから操作します。

  1. 左メニューの [ロードバランシング] にある [ターゲットグループ] をクリックします。
  2. 今回作成した 「web-tg」(Web サーバー用のグループ) を選択します。
  3. [ターゲット] タブ > [ターゲットの登録] をクリックします。
  4. 「Web-Server-B」 にチェックを入れ、[保留中として以下に含める] をクリックし、[ターゲットを登録] で確定します。
  5. ターゲット一覧画面でステータスが 「initial」 になり、1 分ほど待ちステータスが 「healthy」 に変われば成功です。

14. RDS の設定を 「マルチ AZ」 に変更

注意
AWS 無料アカウントの場合、マルチ AZ は対象外のため、実施できません。

  1. AWS コンソールの RDS ダッシュボードから [データベース] をクリックします。
  2. 対象の RDS インスタンス (omikuji-db) を選択し、右上の [変更] をクリックします。
  3. [可用性と耐久性] の項目から [マルチ AZ DB インスタンスを作成する] を選択します。
  4. 画面下までスクロールし、[続行] > [変更のスケジューリング] > [すぐに適用] を選択し、[DB インスタンスを変更] をクリックします。
  5. 設定変更後、RDS の詳細画面で 「マルチ AZ : あり」 になっていることを確認します。

構築完了

簡単にですが、Web アプリの画面とおみくじの出力結果のスクショを貼っておきます。

ブラウザ A
image.png

ブラウザ B
image.png

「もういちど ひく!」をクリックすると、AP サーバー名が変わることが確認できます。
また、異なるブラウザでアクセスすることで、Web サーバー名が変わることも確認できます。

まとめ

初めての 3 層構成はなかなか苦戦しました。

また、コード自体は AI で作成しましたが、Python をサーバー内でインストールしたり、ファイル設定を行うことは初めてだったので、とても勉強になりました。

特に手順についてはかなり考えました。

手順を記載している中で、先に EC2 を立てたほうがいいのか、SG を先に作成したほうがいいのかなど、、、

上流工程といわれる要件定義とか設計はとても大事なんだと実感しましたね。
設計が変わってしまうとそのあとの手順などすべてに影響してきますからね笑

初めにも記載しましたが、構築ポイントについてもまとめています。
以下の URL からご覧ください!

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?