🍔

【AWS】VPCで3層アーキテクチャのWebシステム作ってみる(React+Express+Nginx使用)

2023/07/30に公開

概要

会社で AWS を触ることになり、基本から学んでいこうと思ったため備忘録として記事を書き始めました。
今回は有名な Web3 層アーキテクチャに関する説明の後、3 層アーキテクチャでの Web システムを AWS の VPC 上で作成してみようと思います。
AWS の VPC については以下記事に先日詳細を記載したので、良かったら読んでみてください。

https://zenn.dev/alichan/articles/941cfbd68908fc

もし理解が違うよというところ等ありましたら優しく教えて頂けると幸いです 🙇‍♀️

Web3 層アーキテクチャ とは

昔から Web システムを組む際に使用されてきた Web サーバ、アプリケーションサーバ、データベースサーバの三つのサーバを使用して組まれる Web システムの構造です。
例えば以下図の様にサーバが配置され、自分の PC と各サーバがやり取りを行うことで Web システムを構成しています。

各サーバはそれぞれ以下の様な役割を担っています。

  • Web サーバ:Web システムの入り口としての役割を担っており、ユーザーからのリクエストを受け取りそれに対応した処理を行っています。
    具体的には静的サイトを返したり、後続のアプリケーションサーバーにリクエストを送信したり等。

  • アプリケーションサーバ:Web システムのメイン処理を行なっています。
    具体的には重い計算処理を行ったり、後続の データベースサーバ上の データベースに接続し、データの登録や参照を行なっています。

  • データベース(DB)サーバ:Web システムのデータを保存する役割を担っています。
    具体的にはデータベースが格納され、アプリケーションサーバからの要求に応じてデータを登録したり返したりします。

VPC を使用して 3 層アーキテクチャの Web システムを作成してみよう

では、上記で説明した 3 層アーキテクチャで Web システムを作成してみましょう。
一緒にやってみてもらえると嬉しいです 😌
ここでは、以下の様な構成の Web システムを作成してみます。

上記数字の流れは以下に対応します。

  1. Web サーバに対して React で作成された画面を返すようにリクエストする
  2. 画面が返される
  3. Web サーバを経由して API サーバに DB からデータを取得する API をリクエストする
  4. API サーバ[1]から DB からデータを取得する SQL が発行される
  5. DB からデータを返す
  6. DB から取得したデータを NAT ゲートウェイを経由して API のレスポンスとして返す
  1. VPC の作成

ではまず、VPC を作成します。
マネジメントコンソールで VPC 画面を表示してください。
VPC を作成ボタンを押下して、VPC を作成画面に遷移します。

VPC を作成画面で以下の様に入力項目に値を設定してください。
指定した項目以外は以降もデフォルトの値を入力してください。

項目名
名前タグ - オプション web3-vpc
IPv4 CIDR 10.0.0.0/23

最後に、VPC を作成ボタンを押下して VPC を作成してください。

  1. サブネットの作成

次に、サブネットを作成します。
サブネット画面に遷移してサブネットを作成ボタンを押下してください。

サブネットを作成画面で以下項目を入力してください。

項目名
VPC ID vpc-xxx...(web3-vpc)
サブネット 1 - サブネット名 public-web3-subnet
サブネット 1 - アベイラビリティーゾーン アジアパシフィック(東京)/ ap-northeast-1a
サブネット 1 - IPv4 CIDR 10.0.0.0/24
サブネット 2 - サブネット名 private-web3-subnet
サブネット 2 - アベイラビリティーゾーン アジアパシフィック(東京)/ ap-northeast-1a
サブネット 2 - IPv4 CIDR 10.0.1.0/24

最後に、サブネットを作成ボタンを押下してサブネットを作成してください。

  1. インターネットゲートウェイを作成する

次に、インターネットゲートウェイを作成します。
インターネットゲートウェイ画面に遷移してインターネットゲートウェイの作成ボタンを押下してください。

インターネットゲートウェイの作成画面で以下項目を入力してください。

項目名
名前タグ web3-internet-gateway

インターネットゲートウェイの作成ボタンを押下してインターネットゲートウェイを作成してください。
次に、インターネットゲートウェイを先ほど作成した VPC に付与します。
インターネットゲートウェイ一覧に戻って web3-internet-gateway のインターネットゲートウェイ ID を押下し、web3-internet-gateway の詳細画面に遷移してください。

アクション > VPC にアタッチを押下し、VPC にアタッチ画面に遷移してください。

VPC にアタッチ画面で以下項目を入力してください。

項目名
使用可能な VPC web3-vpc

最後に、インターネットゲートウェイのアタッチボタンを押下してインターネットゲートウェイを VPC にアタッチします。

  1. NAT ゲートウェイを作成する

次に、NAT ゲートウェイを作成します。
NAT ゲートウェイ画面に遷移して NAT ゲートウェイを作成ボタンを押下してください。

NAT ゲートウェイを作成画面で以下項目を入力してください。

項目名
名前 - オプション web3-nat-gateway
サブネット public-web3-subnet
接続タイプ パブリック
Elastic IP 割り当て ID Elastic IP を割り当てボタンを押下して割り当てる

最後に、NAT ゲートウェイを作成ボタンを押下して NAT ゲートウェイを作成してください。

  1. ルートテーブルを作成する

次に、ルートテーブルを作成して各サブネットに紐付けます。
まず、パブリックサブネットに紐づけるルートテーブルを作成します。
ルートテーブル画面に遷移して ルートテーブルを作成ボタンを押下してください。

ルートテーブルを作成画面で以下項目を入力してください。

*1

項目名
名前 - オプション public-web3-route-table
VPC web3-vpc

ルートテーブルを作成ボタンを押下して ルートテーブルを作成してください。
次に、パブリックサブネットに上記ルートテーブルを紐付けます。
ルートテーブル一覧に戻って public-web3-route-table のルートテーブル ID を押下し、public-web3-route-table の詳細画面に遷移してください。

ルートタブ > ルートを編集ボタンからルートを編集画面に遷移し、以下項目をルートを追加ボタンを押下してから入力してください。

*2

項目名
送信先 0.0.0.0/0
ターゲット インターネットゲートウェイ > web3-internet-gateway

変更を保存ボタンを押下して変更を保存してください。
次に、ルートテーブルの詳細画面でサブネットの関連付けタブを開き、サブネットの関連付けを編集ボタンを押下してください。
サブネットの関連付けを編集画面で*3public-web3-sunet を選択して、関連付けを保存ボタンを押下してください。

次に、プライベートサブネットに紐づけるルートテーブルを作成します。
上記手順をプライベートサブネットに紐づけるルートテーブルを作成すると読み替えて実施してみてください。
プライベートサブネット用ルートテーブルで設定する各入力項目の値一覧はこちらです。
上記文章の中で米印がついた数字の箇所を各々下の対応する数字の入力項目と読み替えてください。

*1

項目名
名前 - オプション private-web3-route-table
VPC web3-vpc

*2

項目名
送信先 0.0.0.0/0
ターゲット NAT ゲートウェイ > web3-nat-gateway

*3 private-web3-subnet

  1. EC2 インスタンスを立ち上げる

次に、Web サーバ用の EC2 インスタンスを立ち上げます。
インスタンス一覧画面に遷移してインスタンスを起動ボタンを押下してください。

インスタンスを起動画面で以下項目を入力してください。

*1

項目名
名前とタグ web3-webserver
キーペア名 新しいキーペアの作成ボタンを押下して web3-webserver-key というキーペアを作成し、キーをダウンロードする
ネットワーク設定 ネットワーク設定の横にある編集ボタンを押下して編集する
VPC:web3-vpc
サブネット:public-web3-subnet
パブリック IP の自動割り当て:有効化
を設定する
ネットワーク設定 > ファイアウォール(セキュリティグループ) セキュリティグループを作成する
セキュリティグループ名:web3-webserver-sg
説明:web3-webserver-sg
ネットワーク設定 > セキュリティグループルール 1 タイプ:ssh
ソースタイプ:自分の IP
ネットワーク設定 > セキュリティグループルール 2 タイプ:HTTP
ソースタイプ:自分の IP

最後に、インスタンスを起動ボタンを押下して インスタンスを作成してください。

次に、WebAPI サーバ用の EC2 インスタンスと データベースサーバ 用の EC2 インスタンスを作成します。
上記手順を WebAPI サーバ用の EC2 インスタンスと データベース用の EC2 インスタンスを各々作成すると読み替えて実施してみてください。
WebAPI サーバ用の EC2 インスタンスと データベースサーバ 用の EC2 インスタンスで設定する各入力項目の値一覧はこちらです。
上記文章の中で米印がついた数字の箇所を各々下の対応する数字の入力項目と読み替えてください。

  • WebAPI サーバ用 EC2 インスタンス

*1

項目名
名前とタグ web3-apiserver
キーペア名 新しいキーペアの作成ボタンを押下して web3-apiserver-key というキーペアを作成し、キーをダウンロードする
ネットワーク設定 VPC:web3-vpc
サブネット:private-web3-subnet
プライベート IP の自動割り当て:無効化
を設定する
ネットワーク設定 > ファイアウォール(セキュリティグループ) セキュリティグループを作成する
セキュリティグループ名:web3-apiserver-sg
説明:web3-apiserver-sg
ネットワーク設定 > セキュリティグループルール 1 タイプ:ssh
ソースタイプ:カスタム
ソース:web3-webserver のプライベート IPv4 アドレス
ネットワーク設定 > セキュリティグループルール 2 タイプ:カスタム TCP
ポート:8000
ソースタイプ:カスタム
ソース:web3-webserver のプライベート IPv4 アドレス[2]
  • データベース用 EC2 インスタンス

*1

項目名
名前とタグ web3-dbserver
キーペア名 新しいキーペアの作成ボタンを押下して web3-dbserver-key というキーペアを作成し、キーをダウンロードする
ネットワーク設定 VPC:web3-vpc
サブネット:private-web3-subnet
プライベート IP の自動割り当て:無効化
を設定する
ネットワーク設定 > ファイアウォール(セキュリティグループ) セキュリティグループを作成する
セキュリティグループ名:web3-dbserver-sg
説明:web3-dbserver-sg
ネットワーク設定 > セキュリティグループルール 1 タイプ:ssh
ソース:web3-apiserver のプライベート IPv4 アドレス
ネットワーク設定 > セキュリティグループルール 2 タイプ:カスタム TCP
ポート範囲:3306
ソースタイプ:カスタム
ソース:web3-apiserver のプライベート IPv4 アドレス
  1. Web サーバを立ち上げて、React アプリケーションを載せる

自分の PC 上でターミナルを立ち上げて、以下コマンドを入力し web3-webserver に SSH 接続してください。

$ chmod 600 [web3-webserver-keyを保存したパス]
$ ssh -i "[web3-webserver-keyを保存したパス]" ec2-user@[web3-webserverのパブリックIPv4アドレス]

以下コマンドを入力し web3-webserver に nginx を入れて立ち上げてください。

$ sudo yum install -y nginx
$ sudo systemctl start nginx

以下コマンドを入力し nodejs と npm をインストール後、 React アプリケーションを作成してアプリケーション内で使用するライブラリをインストールしてください。

$ sudo yum install -y nodejs npm
$ npx -y create-react-app sample-app
$ cd sample-app
$ npm install axios

以下コマンドを入力し、作成した React アプリケーションに移動してアプリケーションの内容を vi で書き換えてください。
書き換える内容は以下です。

$ sudo vi src/App.js
import { useState } from "react";
import axios from "axios";

const App = () => {
  const [message, setMessage] = useState(null);

  const getData = async () => {
    const response = await axios.get("api");
    setMessage(response.data.message);
  };

  return (
    <div>
      <h1>取得データ</h1>
      <button onClick={getData}>データを取得</button>
      <div>{message}</div>
    </div>
  );
};

export default App;

以下コマンドを入力して React アプリケーションをビルドして、nginx のサイト公開用ディレクトリにビルドされた React アプリケーションを配置してください。

npm run build
sudo cp -r /home/ec2-user/sample-app/build/* /usr/share/nginx/html/

上記までの手順をこなすとこの段階で web3-webserver のパブリック IPv4 アドレスにアクセスすれば下記画面が表示されるはずです。

最後に、この後作成する API サーバに対して 現在作成している Web サーバからリクエストを投げられるように プロキシパスの設定をします。
以下コマンドを入力し、nginx の設定ファイルを vi で書き換えてください。
書き換える内容は以下です。
設定ファイルを書き換えた後は下記コマンドを入力して nginx を再起動してください。
下記内容に設定ファイルを書き換えることで、[Web サーバのパブリック IP アドレス]/api にリクエストを送信すると、Web サーバを経由して API サーバにリクエストが送られるようになります。

$ sudo vi /etc/nginx/nginx.conf
$ sudo nginx -s reload
...
http {
    ...
    server {
        ...
        location /api/ {
            proxy_pass [web3-apiserverのプライベートIPv4アドレス]:8000/;
        }
        ...
    }
    ...
}
...
  1. データベースサーバを立ち上げて、データベースを載せる

上記 web3-webserver 内で以下コマンドを入力し web3-apiserver-key.pm ファイルを作成して自分の PC にダウンロードした web3-apiserver-key.pem の内容を web3-webserver 内の web3-apiserver-key.pem に vi でコピーしてください。
以下コピー内容の例です。

$ touch ~/web3-apiserver-key.pem
$ sudo vi ~/web3-apiserver-key.pem
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----

以下コマンドを入力して web3-apiserver に SSH 接続してください。

$ sudo chmod 600 ~/web3-apiserver-key.pem
$ ssh -i ~/web3-apiserver-key.pem ec2-user@[web3-apiserverのプライベートIPv4アドレス]

上記 web3-apiserver 内で以下コマンドを入力し web3-dbserver-key.pm ファイルを作成して自分の PC にダウンロードした web3-dbserver-key.pem の内容を web3-apiserver 内の web3-dbserver-key.pem に vi でコピーしてください。
以下コピー内容の例です。

$ touch ~/web3-dbserver-key.pem
$ sudo vi ~/web3-dbserver-key.pem
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----

以下コマンドを入力して web3-dbserver に SSH 接続してください。

$ sudo chmod 600 ~/web3-dbserver-key.pem
$ ssh -i ~/web3-dbserver-key.pem ec2-user@[web3-dbserverのプライベートIPv4アドレス]

以下コマンドを入力し web3-dbserver 内で mysql をインストールして立ち上げてください。

$ sudo yum install -y https://dev.mysql.com/get/mysql80-community-release-el9-3.noarch.rpm
$ sudo yum install -y mysql-community-server
$ sudo systemctl start mysqld

mysql 起動後、初回ログイン用のパスワードが mysql のログに出力されているので、以下コマンドで検索をかけて確認してください。
以下のような表示がされるはずです。

$ sudo grep 'temporary password' /var/log/mysqld.log
... A temporary password is generated for root@localhost: [初回ログイン用パスワード]

以下コマンドを入力して mysql に root ユーザーでログイン後、root ユーザーのパスワードを変更してください。

$ mysql -uroot -p
Enter password: [初回ログイン用パスワード]
mysql> alter user 'root'@'localhost' identified by 'Root@1234';

以下コマンドを入力して web3db を作成後、web3db の中に messages テーブルを作成してデータを一つだけ挿入してください。

mysql> create database web3db;
mysql> use web3db;
mysql> create table messages (id int primary key auto_increment, message varchar(100));
mysql> insert into messages (message) value ('こんにちは');

以下コマンドを入力して WebAPI サーバ内で作成された API 内部で使用される web3_user を作成してログイン用パスワードを設定し、web3db データベースを操作する権限を与えてください。

mysql> create user 'web3_user'@'[web3-apiserverのプライベートIPv4アドレス]' identified by 'Web3@1234';
mysql> grant all on web3db.* TO 'web3_user'@'[web3-apiserverのプライベートIPv4アドレス]';

これで データベースサーバにデータを格納することができました。

  1. API サーバを立ち上げて、WebAPI を載せる

以下コマンドを入力して web3-dbserver からログアウトし、web3-apiserver にもどってください。

$ exit

以下コマンドを入力し web3-apiserver 内で nodejs と npm をインストール後、WebAPI 用のアプリケーション sample-api を作成し、その中で express と mysql への接続に用いるライブラリ をインストールしてください。

$ sudo yum install -y nodejs npm
$ mkdir sample-api
$ cd sample-api
$ npm init
$ npm install express mysql2

以下コマンドを入力し sample-api 内で app.js ファイルを作成し、vi で内容を書き換えてエンドポイントが/の API を一本作成してください。
書き換える内容は以下です。

$ sudo vi app.js
const express = require("express");
const mysql = require("mysql2");

const app = express();
const port = 8000;

const con = mysql.createConnection({
  host: "[web3-dbserverのプライベートIPアドレス]",
  user: "web3_user",
  password: "Web3@1234",
  database: "web3db",
});

const sql = "select * from messages;";

app.get("/", (req, res) => {
  con.query(sql, (err, result) => {
    const message = result[0].message;
    res.json({
      message,
    });
  });
});

app.listen(port, () => {
  console.log(`listening on port: ${port}`);
});

最後に、以下コマンドで API サーバをたちあげてください。

$ node app.js

これで WebAPI を使用できるようになりました。

  1. Web システムの挙動を確認する

これで Web システムが完成したので、挙動を確認してみます。
web3-webserver のパブリック IPv4 アドレスにアクセスすると下の様な画面が開くので、データを取得ボタンを押下します。
こんにちはというメッセージが表示されれば、無事データベースからデータが取得できています。

終わりに

ハンズオンお疲れ様でした。
大分ボリューミーな記事になってしまったので、ここまで読んで頂いた方には本当に感謝しかありません。
もう少し簡単なシステムを VPC で作成する記事も出しているので、よければこちらも読んでみてください。
https://zenn.dev/alichan/articles/941cfbd68908fc
今回は画面部分を EC2+nginx+React で作成しましたが、そちらについての詳細な記事も出しているので、よければこちらも読んでみてください。
https://zenn.dev/alichan/articles/c40b793253f5db

ここまで読んでいただき本当にありがとうございます 🙇‍♀️

参照

https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/configure-your-vpc.html

脚注
  1. 最近の開発だとバックエンドとして WebAPI が使用されることが多いため、アプリケーションサーバに対応する物としてここでは WebAPI を実装する API サーバを用意しています。 ↩︎

  2. インスタンス一覧画面からインスタンス ID を押下して遷移できるインスタンス概要画面で確認できます。 ↩︎

Discussion