プログラミング

React×SpringBoot×MySQLをAWSにデプロイ

この記事は約16分で読めます。

こんにちは。じゅんです。

今回はReact×Spring Boot×MySQLAWSにデプロイします。

VPCの作成から動作確認までこの記事でカバーしています。


これまでの作業内容については以下の記事にまとめています。

全体像

VPCの作成

EC2やRDSを配置する仮想ネットワークを用意するためVPCを作成します。

VPCとは広範囲のIPアドレスを持つIPアドレス空間のことです。

IPアドレスは住所に例えられることがあります。
その例えに従うとVPCは複数の住所を持つ都道府県のようなイメージです。

以下の設定で作成します。

項目備考
VPCの設定 > 作成するリソースVPCのみ「VPCなど」を選択すると同時にサブネットやNATゲートウェイを作成できます。
サブネットは別で作成するため「VPCのみ」を選択します。
名前タグsimple-memo-vpc(任意)VPCの名前
IPv4 CIDRブロックIPv4 CIDRの手動入力
IPv4 CIDR10.0.0.0/16VPCのIPアドレス範囲を10.0.0.0~10.0.255.255とします。
その他はデフォルト

サブネットの作成

VPC内でさらにIPアドレス範囲を分割したサブネットを作成します。

サブネットはVPC(都道府県)の中の具体的なエリアを示す市区町村のようなイメージです。

市区町村ごとに外部からのアクセスに対して異なる対応をするためにサブネットを作成します。

パブリックサブネット

ReactSpring Bootを起動したWebサーバーを配置するパブリックサブネットを作成します。

パブリックサブネットは外部からのアクセスを許可します。

パブリックサブネットは外部の人々が訪れることができる観光地や商業地のようなイメージです。

以下の設定で作成します。

項目備考
VPC > VPC IDsimple-memo-vpc作成してVPCを選択します。
サブネットの設定 > サブネット名simple-memo-public-subnet(任意)パブリックサブネットの名前
サブネットの設定 > アベイラビリティーゾーンアジアパシフィック(東京)/ ap-northeast-1a現実世界のどこのエリアのハードウェアを使用するかを表す。
サブネットの設定 > IPv4 サブネット CIDR ブロック10.0.0.0/24VPCに割り当てられたIPアドレス空間の中で、パブリックサブネットに割り当てるIPアドレスの範囲を定義。
IPアドレス範囲を10.0.0.0~10.0.0.255とします。
その他はデフォルト

作成直後はパブリック IPv4 アドレスを自動割り当ていいえとなっており、このサブネット内で起動したEC2インスタンスにパブリックIPアドレスが自動的に付与されません。そのため作成後に設定を編集する必要があります。

アクション > サブネットの設定を編集から変更します。

プライベートサブネット

RDSを起動したDBサーバーを配置するプライベートサブネットを作成します。

RDSを利用する際には、マルチAZ配置にして可用性を高めるために異なるAZに属するサブネットを2つ用意する必要があります。

プライベートサブネットは外部の人々が直接アクセスできない住宅地や工業地帯のようなイメージです。

プライベートサブネットは外部からのアクセスを拒否して、パブリックサブネットからのアクセスのみ許可します。

以下の設定で作成します。

項目備考
VPC > VPC IDsimple-memo-vpc作成してVPCを選択します。
サブネットの設定 > サブネット名01: simple-memo-private-subnet-01
02: simple-memo-private-subnet-02(任意)
プライベートサブネットの名前
サブネットの設定 > アベイラビリティーゾーン01: アジアパシフィック(東京)/ ap-northeast-1a
02: アジアパシフィック(東京)/ ap-northeast-1c
現実世界のどこのエリアのハードウェアを使用するかを表す。
可用性向上のため異なるAZを使用する
サブネットの設定 > IPv4 サブネット CIDR ブロック01: 10.0.1.0/24
02: 10.0.2.0/24
VPCに割り当てられたIPアドレス空間の中で、プライベートサブネットに割り当てるIPアドレスの範囲を定義。
1つ目はIPアドレス範囲を10.0.1.0~10.0.1.255とします。
2つ目はIPアドレス範囲を10.0.2.0~10.0.2.255とします。
その他はデフォルト
サブネット作成時点ではパブリックとプライベートの違いは対象のCIDRブロックのみです。
この後作成するセキュリティグループでアクセス制御を行います。

インターネットゲートウェイの作成

VPCと外部のインターネットの出入口となるインターネットゲートウェイを作成します。

VPC(都道府県)とインターネットの外部(国外)をつなぐ空港のようなイメージです。

以下の設定で作成します。(VPCとの紐付けは作成後に行います)

項目備考
名前タグsimple-memo-igwインターネットゲートウェイの名前

作成後、アクション > VPCにアタッチ からVPCと紐づける設定を行います。

ルートテーブルの設定

VPC内の通信を振り分けるためのルートテーブルを設定します。

都道府県(VPC)内の交通(通信)を適切に誘導するための地図や交通標識のようなイメージです。

ルートテーブルはこれまでの操作の過程で既に作成されています。

この設定は、送信先が10.0.0.0/16 に該当するIPアドレス、つまりVPC内部での通信に関する設定を表しています。
ターゲットがlocalとあるため、同じVPC内のリソースに接続されるルールが設定されています。

このままではWebサーバーがインターネットへレスポンスを返す際にVPCから出られません。

外部への通信を行えるようにするために、送信先が0.0.0.0/0でターゲットが作成したインターネットゲートウェイであるルートを追加します。

また、追加したルートに関連づけるためにパブリックサブネットを関連付けます。

これでWebサーバーからのレスポンスがインターネットに返るようになりました。

セキュリティグループの作成

Webサーバー用

ルートテーブルの設定では、Webサーバーがインターネットにレスポンスを返すための設定を行いました。

Webサーバー用のセキュリティグループではインターネットからのリクエストを許可する設定を行います。

以下の設定で作成します。

項目名意味
セキュリティグループ名simple-memo
-web-sg(任意)
説明SSH & HTTP(任意)
VPCsimple-memo-vpc
セキュリティグループルール 1タイプ:ssh
ソース:3.112.23.0/29
インスタンスを操作するための接続(ssh)をEC2 Instance Connectのみに制限
セキュリティグループルール 2タイプ:ssh
ソースタイプ:マイIP
jarファイル転送時にscpコマンドでssh接続するため使用しているPCのみ許可
セキュリティグループルール 3タイプ:HTTP
ソースタイプ:0.0.0.0/0
Nginxへのアクセスを解放
他の項目はデフォルトのままです。

DBサーバー用

ルートテーブルでは、DBサーバーを起動するプライベートサブネットへの外部からのアクセスは許可していません。

DBサーバー用のセキュリティグループには、Webサーバーからのリクエストを許可するように設定する必要があります。

以下の設定で作成します。

項目名意味
セキュリティグループ名simple-memo
-db-sg(任意)
説明For RDS(任意)
VPCsimple-memo-vpc
セキュリティグループルールタイプ:MYSQL/Aurora
ソース:0.0.0.0/0
任意のIPアドレスからの通信を許可します。
他の項目はデフォルトのままです。
任意のIPアドレスからの通信を許可するのは、Webサーバー用のインスタンスのパブリックIPアドレスは起動ごとに変更されるためです。
ルートテーブルの設定でインターネットからプライベートサブネットへの通信は拒否されるためセキュリティグループで任意のIPアドレスからの通信を許可してもインターネットからRDSへは到達しません。
(セキュリティ的には最適とは言えません...)

DBサブネットグループの作成

RDSのマルチAZ化のためにDBサブネットグループを作成します。

RDS > サブネットグループ から以下の設定で作成します。

項目名意味
セキュリティグループ名simple-memo
-db-subnet-group(任意)
説明For RDS subnet group(任意)
VPCsimple-memo-vpc
アベイラビリティゾーンap-northeast-1a
ap-northeast-1c
作成した2つのプライベートサブネットのアベイラビリティゾーンを選択します
サブネット(作成した2つのプライベートサブネット)

EC2インスタンスの作成

WebサーバーとしてのEC2インスタンスを作成します。

以下の設定で作成します。

項目名備考
名前とタグ > 名前simple-memo
-web-server(任意)
キーペア (ログイン) > キーペア名 > 新しいキーペアを作成simple-memo
ネットワーク設定 > 右上編集ボタン > VPCsimple-memo-vpc作成したVPC
ネットワーク設定 > 右上編集ボタン > サブネットsimple-memo-public-subnet作成したパブリックサブネット
ネットワーク設定 > 右上編集ボタン > サブネットsimple-memo-web-sg作成したセキュリティグループ
他の項目はデフォルトのままです。(マシンイメージは無料枠を利用)

RDSインスタンスの作成

DBサーバーとしてのRDSインスタンスを作成します。

以下の設定で作成します。

項目名備考
データベース作成方法標準作成
エンジンのタイプMySQL
テンプレート無料利用枠
DB インスタンス識別子simple-memo-dbDBインスタンスの名前
認証情報の設定 > マスターユーザー名adminMySQLのユーザー名
認証情報の設定 > 認証情報の管理セルフマネージドMySQLの認証情報を自分で管理します
接続 > コンピューティングリソースEC2コンピューティングリソースに接続しないVPCやインターネットゲートウェイなど手動で設定しているため不要です
接続 > VPCsimple-memo-vpc作成したVPC
接続 > DB サブネットグループsimple-memo-db-subnet-group作成したDBサブネットグループ
接続 > アベイラビリティーゾーンap-northeast-1aマルチAZの主となるAZを選択します
他の項目はデフォルトのままです。(マシンイメージは無料枠を利用)

セットアップ・動作確認

ここからはWebサーバー役のEC2インスタンス上で作業を行います。
EC2 Instance Connectを使用します。

今回、ReactとSpring BootをWebサーバーに起動する上で、Nginxをリバースプロキシとして使用します。

Webサーバーのデプロイに関する以下の操作はこちらの記事で詳しく解説しています。

Nginx

EC2 Instance Connectを使用して、以下の設定でNginxを起動します。
Nginxのセットアップについてはこちらで詳しく解説しています。

/etc/nginx/nginx.conf
server {
    listen       80;
    server_name  localhost;

    # 外部 → Nginx → React
    location / {
        proxy_pass http://localhost:3000;
    }

    # React → Nginx → Spring Boot
    location /api {
        proxy_pass http://localhost:8080/api;
    }
}

実行コマンド

Zsh
sudo systemctl start nginx

React

ReactプロジェクトについてはGitからクローンしてきます。
Reactのデプロイについてもこちらで詳しく解説しています。

なお、API接続先は以下の通りです。

src/App.tsx
const response = await fetch(`http://(WebサーバーのパブリックIPアドレス)/api/memos`);

実行コマンド

Zsh
cd simple-memo-frontend/   # 作業ディレクトリに移動
npm install                # package.jsonに記載されたパッケージをインストール
npm run build
npm install -g serve  # 軽量サーバーを提供するパッケージ
serve -s build             # ビルドされた静的ファイルを軽量サーバーで実行
npm run buildがEC2上で終わらなかったのでビルドファイルをscp転送しました。

Spring Boot

Spring Bootは開発環境からjarファイルをscp転送します。
Spring Bootのデプロイについてはこちらで詳しく解説しています。

なお、MySQLの接続先情報は以下の通りです。

src/main/resources/application.properties
spring.datasource.url=jdbc:mysql://(RDSのエンドポイント):3306/simple_memo
spring.datasource.username=admin
spring.datasource.password=xxxxxxxx

また、CORS対策としてWebサーバーのパブリックIPアドレスを許可しておきます。
@Value("${api.endpoint}")application.propertiesで設定したapi.endpointが取得できます。

src/main/java/com/example/simplememo/config/WebConfig.java
package com.example.simplememo.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

  private static final Logger logger = LoggerFactory.getLogger(WebConfig.class);

  @Value("${api.endpoint}")
  private String apiEndpoint;

  @Override
  public void addCorsMappings(CorsRegistry registry) {
    // apiEndpointの値をログに出力して確認
    logger.info("Configured API Endpoint for CORS: {}", apiEndpoint);

    registry.addMapping("/api/**")
            .allowedOrigins(apiEndpoint)
            .allowedMethods("GET", "POST", "PUT", "DELETE")
            .allowedHeaders("*")
            .allowCredentials(true);
  }
}
src/main/resources/application.properties
# 上述したMySQL接続情報
spring.datasource.url=jdbc:mysql://(RDSのエンドポイント):3306/simple_memo
spring.datasource.username=admin
spring.datasource.password=xxxxxxxx

# CORS対策: リクエスト元を指定
api.endpoint=http://54.249.13.31
前回(こちらの記事の時)はNginxでリバースプロキシすることでCORSを回避できたのですが、今回は上手く動きませんでした。
理由は分かりませんが許可するとAPI通信が正常に実行できました。

実行コマンド

Zsh
java -jar ~/simple-memo-0.0.1-SNAPSHOT.jar

MySQL

EC2 Instance Connect上からMySQLに接続します。

Zsh
mysql -h (RDSのエンドポイント) -u admin -p

MySQLのセットアップはこちらの通りに「simple_memo」データベースを作成し、memosテーブルを作成します。

以下のコマンド実行結果が得られればセットアップ完了です。

上記4サービスをセットアップすることで、WebサーバーのパブリックIPアドレスにアクセスすると以下のようにアプリケーションが表示されるはずです。

まとめ

今回はReact×SpringBoot×MySQLをAWSにデプロイしてみました。

Reactだけ」「SpringBootだけ」「React×SpringBoot」と段階的にデプロイしてきましたが、初めよりだいぶ本番環境の理解が進んだと思います。

ReactのHello Worldから記事にしているので順番にやっていけば同じようにできるはずです!

次回からはフロントエンドの学習トピックに注力していきたいと思います。


なお、今回はポートフォリオを公開するのに必要最低限のアーキテクチャを選択しています。
フロントエンドをS3とCloudFrontに、SpringBootをECSにデプロイすることでよりパフォーマンスとスケーラビリティを向上することができます。
また機会を設けてインフラの勉強を続けたいと思います。

参考文献

EC2 + RDSを構築して、SpringBootとReactを載せてアプリを起動している【前編】 | オカログ
現在、絶賛バックエンドの学習をしているのですがアプリをデプロイする先をせっかくならAWSにやってみようということでAWS環境にEC2とRDSを構築してSpringBoot(バックエンド)とReact(フロントエンド)が起動するところまでなん
EC2 + RDSを構築して、SpringBootとReactを載せてアプリを起動している【後編】 | オカログ
前編では、EC2・RDSの構築をしてEC2からRDSへの接続までを確認しました。 後編では下記を行っていきます。 前編での内容 VPCの設定 EC2の設定 RDSの設定 EC2からRDSへの接続を確認する 後編での内容(今回の記事) Git
超初心者がDB接続するSpringBootアプリをAWSにデプロイする【前編】 - Qiita
はじめに駆け出しJavaエンジニアでインフラの知識もデプロイ経験もほぼ無い筆者が、Springで作成したアプリケーションをAWSにデプロイすることに成功した手順を、遭遇したエラーも交えながら記して…
AWSで基本的なサーバー環境を構築してみました。 - Qiita
#はじめにAWSを使用してEC2とRDSを構築し、EC2のSSH接続とRDSへの接続確認まで行ってみました。その手順の流れを備忘録として残します。※AWSコンソール画面のスククショは、2020年…
AWSでMySQLを使う

コメント