はじめに
今回は、EC2で公開しているSpring BootのWebアプリに、Amazon RDS for MySQLを接続する手順をまとめます。
これまではH2を使ってデータベースを利用してSpring Bootアプリを作成することは多いようです。本番環境ではRDS MySQLを使用し、アプリとは別にデータを管理できる構成にしていくのが一般的なようなのでやり方を学ぶことにしました。
この記事では、以下の状態を前提としています。
- ローカル環境で、H2を使ったSpring Bootアプリが動作している
- EC2でSpring Bootアプリを公開している
- EC2のOSはUbuntuを使用している
- Nginxを経由してWebアプリにアクセスできる
- systemdでSpring Bootの起動・停止を管理している
上記の構成を作成する手順はこちらの記事を参照してみてください。
⇒Spring Bootで作成したWebアプリをAWS EC2で公開する手順(パート1)
⇒Spring Bootで作成したWebアプリをAWS EC2で公開する手順(パート2)
⇒Spring Bootで作成したWebアプリをAWS EC2で公開する手順(パート3)
⇒Spring Bootで作成したWebアプリをAWS EC2で公開する手順(パート4)
⇒EC2にデプロイしたSpringBoot WebアプリをNginxを使って独自ドメインへのアクセスに切りかえる
作業後は、ローカル開発ではH2、本番環境のEC2ではRDS MySQLを使い分けられるようにします。
私自身、データベースやAWSを学びながら進めたので、設定項目や接続方法でつまずくことがありました。この記事では、接続確認の方法も含めて順番に説明します。
1. 現在のH2版アプリがローカル環境で正常に動作することを確認
RDSの設定を始める前に、現在のアプリがH2を使用して正常に動作することを確認します。
先に確認しておくことで、RDSへの切り替え後にエラーが出た場合、もともとのアプリの問題なのか、接続先を変更したことによる問題なのかを切り分けやすくなります。
2. RDS for MySQLを作成
ここが個人的には難関でした。EC2のインスタンスを作成するのは割と直感的でしたが、データベースに関する知識がない私からすると「わけがわからないよ」、状態でしたが何とかなりましたので皆さんもやり遂げられると思います。
今回は 「現在EC2でSpring Bootを動かしており、本番DBとしてAmazon RDS for MySQLを追加する」 という前提で説明します。
最終的には
インターネット
│
↓
Nginx
│
│ :8080
↓
Spring Boot
│
│ :3306
↓
┌────────────────┐
│ Amazon RDS │
│ MySQL │
└────────────────┘
という構成になります。
なお、最終的には
EC2
│
│ TCP 3306
│
↓
RDS
のみのアクセスを許可しRDSの3306番ポートを、0.0.0.0/0を避けます。
2-1. AWSコンソールからRDSを開く
AWSマネジメントコンソールにログインします。
サービス検索で、
RDS
を検索すると
Aurora and RDS
というのが表示されるのでこれをクリックします。
その後データベースの作成というボタンをクリックします。
いくつか作成方法が表示されるので、「フル設定」を選択します。
詳細な設定画面が出ますので、この後設定していきます。
2-2. エンジンをMySQLにする
エンジンのオプションという項目があるので、
MySQLを選択します。
2-3. データベース作成方法を選択
データベース作成方法を選択という項目はフル設定を選択します。
2-4. テンプレート設定
テンプレートは無料利用枠を選択しておきます。
2-5.可用性と耐久性設定
可用性と耐久性は、今回はとりあえず実装するのが目的なのでデフォルトの シングル AZ DB インスタンスデプロイ (1 インスタンス)のままで良いです。
2-5. 設定
エンジンバージョン
MySQL 8.x
等のように8系のバージョンであれば良いです。
DBインスタンス識別子
これはAWS上でRDSを識別するための名前です。
今回は、
myspringboot-db
にしておきます。
マスターユーザー名
好きな文字列を入れてください。
認証情報管理
セルフマネージドのままで良いです。
マスターパスワード
好きな文字列を入力してください。
2-6. インスタンスの設定
インスタンスタイプは
db.t4g.micro
のままで良いです。
2-7. ストレージ
デフォルトの最小サイズのままで良いです。
2-8. 接続
コンピューティングリソース
EC2 コンピューティングリソースに接続
を選択します。
EC2 インスタンス
EC2で作成したSpring Boot用のインスタンスのIDを選択します。
DB サブネットグループ
自動セットアップ
を選択します。
パブリックアクセス
デフォルトのなしのままで良いです。
VPC セキュリティグループ (ファイアウォール)
新規作成を選択します。
### 新しい VPC セキュリティグループ名
今回は、
```text
rds-mysql-sg
としておきます。
追加設定
データベースポートは3306に設定しておきます。
2-9. モニタリング
何もせずデフォルトのままで良いです。
2.10
ここまで出来たらいったんデータベースの作成をクリックして登録します。
3. RDSのセキュリティーグループの設定
データベースの作成をした後、
データベース
↓
作成したデータベース名
↓
接続とセキュリティ
↓
接続されたコンピューティングリソース
↓
表示されているセキュリティグループ
↓
インバウンドルール
↓
インバウンドルールを編集
を選択していきます。
編集画面で、
タイプ:MySQL/Aurora
ポート:3306
ソース:カスタム
ソース:EC2のセキュリティグループ
をそれぞれ選択・入力します。
EC2のセキュリティグループは
EC2
↓
インスタンス
↓
作成しているインスタンス
↓
セキュリティ
↓
セキュリティーグループ
に記載されている
sg-xxxxxxxxxxxxxxxxx
のような文字列です。
設定ができたらルールの保存をクリックします。
うまくできているか確認
EC2では、
EC2 → インスタンス → 対象EC2 → ネットワーキング → VPC ID
RDSでは、
RDS → データベース → 対象RDS → 接続とセキュリティ → VPC
をそれぞれ確認します。
例えば両方とも、
vpc-0123456789abcdef
となっていればOKです。
4. EC2へMySQLクライアントを実装する
EC2にSSH接続して、MySQLクライアントからRDSへログインできるか確認します。
4-1. MySQLクライアントをインストールする
ローカルPCでEC2にSSH接続します。
ssh -i springboot-key.pem ubuntu@<EC2のパブリックIP>
まずパッケージ情報を更新します。(Ubuntuの場合)
sudo apt update
その後、MySQLクライアントをインストールします。
sudo apt install mysql-client
その後、
mysql --version
でインストールできているか念のため確認します。
4-2. RDSのエンドポイントを確認する
AWSコンソールで、
Aurora and RDS → データベース → 対象RDS → 接続とセキュリティ → エンドポイント
を開き、エンドポイントを確認します。
myspringboot-db.xxxxxxxxx.ap-northeast-1.rds.amazonaws.com
のようなエンドポイントの値があるので、これを控えておきます。
4-3. EC2からRDSへ接続する
EC2上で次のコマンドを実行します。
mysql -h <RDSのエンドポイント> -P 3306 -u <マスターユーザー名> -p
例えば、
mysql -h myspringboot-db.xxxxxxxxx.ap-northeast-1.rds.amazonaws.com -P 3306 -u admin -p
のような記述をします。
実行途中Enter password:などが表示されるのでRDS作成時のパスワードを入力します。
パスワードは画面には表示されませんが、そのまま入力してEnterを押してください。
成功すると、次のような表示になります。
mysql>
この状態になれば、
EC2
↓
RDS MySQL
のネットワーク接続が正常にできています。
もしすでにデータベースを作成している場合は、
SHOW DATABASES;
を実行するとデータベース一覧が表示されます。
終了する場合は、
exit;
を実行します。
5. MySQLにデータベース・テーブルを作成
ここでは、Spring Bootが使用するデータベースとテーブルを作成します。
5-1. EC2からRDSへ接続する
EC2へSSH接続した後、RDSのMySQLへ接続します。
mysql -h <RDSのエンドポイント> -P 3306 -u <マスターユーザー名> -p
具体的なやり方は4章を確認してください。
5-2. 現在のデータベースを確認する
SHOW DATABASES;
を実行すると
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
のような表示があります。
5-3. Spring Boot用のデータベースを作成する
SQLクライアント上で以下を実行します。
CREATE DATABASE myspringboot
CHARACTER SET utf8mb4
COLLATE utf8mb4_0900_ai_ci;
utf8mb4は、MySQLなどのデータベースで利用される最大4バイトのUTF-8文字コードセットで、絵文字や一部の特殊な漢字などを正確に保存できます。
utf8mb4_0900_ai_ciは、MySQL 8.0以降で標準採用されている、大文字・小文字やアクセント記号を区別しない照合順序(文字の比較・並び替えルール)です。
また、myspringbootが実装用データベース名です。
再び
SHOW DATABASES;
を実行して
myspringboot
が表示されればOKです。
5-4. 使用するデータベースを選択する
次に、
USE myspringboot;
を実行すると、
Database changed
と表示されます。
以降のSQLコマンドはmyspringbootに対して実行されます。
5-5. H2のテーブル構造を確認する
H2に存在するテーブルと同じ構造をMySQL側にも用意する必要があります。例えば現在のSpring Bootプロジェクトに、
src/main/resources/schema.sql
があり、
CREATE TABLE sample (
id VARCHAR(50) PRIMARY KEY,
str VARCHAR(100),
);
となっているのであれば、これを基準にRDSのMySQL側のテーブルを作ります。
5-6. MySQLにテーブルを作成する
先ほどの例の場合、
CREATE TABLE sample (
id VARCHAR(50) PRIMARY KEY,
str VARCHAR(100),
);
を実行して作成をします。成功すると、
Query OK
と表示されます。
5-7. テーブルが作成されたことを確認する
SHOW TABLES;
を実行して、
+------------------------+
| Tables_in_myspringboot |
+------------------------+
| sample |
+------------------------+
と表示されれば成功です。また、
DESCRIBE sample;
を実行すると、
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | varchar(50) | NO | PRI | NULL | |
| str | varchar(50) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
のように、テーブルの構造を確認できます。
5-8. 必要であれば初期データを登録する
H2でdata.sqlなどを使用して初期データを入れている場合は、MySQLにも必要なデータを用意します。
例えば
INSERT INTO sample (id, str)
VALUES('1', 'こんにちは');
等を実行し登録します。その後、
SELECT * FROM sample;
で確認します。
現在の構造は
RDS MySQL
│
└── myspringboot
├── sample
├── sample2
└── sample3
のようになっています。
6. Spring BootにMySQL JDBCドライバを追加
Spring BootからRDSのMySQLへ接続できるように、MySQL JDBCドライバをMavenの依存関係に追加します。
6-1. pom.xmlを編集する
pom.xml
を開きます。
<dependencies> の中に次を追加します。
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
H2の<dependency>は削除しなくて問題ないです。
6-2. Mavenの依存関係を更新する
ターミナルから、
mvnw clean package
を実行します。もし、
BUILD SUCCESS
という表示があれば成功です。これでSpring Bootアプリ内に、
Spring Boot
│
↓
MySQL JDBC Driver
│
↓
MySQL
という接続に必要なドライバを組み込める状態になりました。
7. Spring Bootの本番用設定を作成
ローカル開発ではH2、本番のEC2ではRDS MySQL を使い分けられるようにします。
7-1. application.ymlを作成・編集する
まず、src/main/resources配下を次のようにします。
src/main/resources
├── application.yml
└── application-prod.yml
application.yml は開発用、application-prod.yml は本番用として使います。
application.ymlはすでに環境に合わせて作成していると思いますので、そのまま編集する必要はありません。
作成したapplication-prod.yml に以下の本番用MySQL設定を書きます。
spring:
datasource:
url: jdbc:mysql://<RDSのエンドポイント>:3306/myspringboot
username: <MySQLのユーザー名>
password: <MySQLのパスワード>
driver-class-name: com.mysql.cj.jdbc.Driver
ただし、この状態ではGitHubなどにPushした場合パスワードなども公開されてしまいます。
そのため、
spring:
datasource:
url: jdbc:mysql://${DB_HOST}:3306/${DB_NAME}
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
driver-class-name: com.mysql.cj.jdbc.Driver
のように記述します。このようにすることで、Spring Bootは
DB_HOST
DB_NAME
DB_USERNAME
DB_PASSWORD
というLinuxに保存した環境変数ファイルから値を取得するようになります。
Spring Bootが正しく環境編集を取得・代入をするための設定は後述します。
7-2. EC2で本番Profileを指定する
application-prod.yml は、普通に起動しただけでは使用されません。
EC2上で以下を実行します。
sudo nano /etc/systemd/system/myspringboot.service
ExecStarを以下のように変更します。
java -jar MySpringBoot-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod
後半の部分でprod Profileを指定して起動するようにしています。
8. DB接続情報を、EC2側に環境変数として保存し、systemd経由でSpring Bootへ渡す
今回は、myspringboot.service にパスワードを直接書くのではなく、環境変数用のファイルを分離する方法を用います。
8-1. 環境変数を保存するディレクトリを作る
EC2上で以下を実行します。
sudo mkdir -p /etc/myspringboot
続いて環境変数ファイルを作ります。
sudo nano /etc/myspringboot/myspringboot.env
8-2. DB接続情報を記述する
次のように記述します。
DB_HOST=<RDSのエンドポイント>
DB_NAME=myspringboot
DB_USERNAME=<DBユーザー名>
DB_PASSWORD=<実際のRDSのパスワード>
記述した内容を確認する場合は以下を実行します。
sudo cat /etc/myspringboot/myspringboot.env
入力したら
Ctrl + O
↓
Enter
↓
Ctrl + X
の順にコマンドを実行して保存します。
8-3. ファイルの権限を制限する
このファイルはパスワードが平文で入っているので誰でも読める状態にはしません。
所有者を設定します。
sudo chown root:ubuntu /etc/myspringboot/myspringboot.env
root:ubuntu: ユーザー:グループ の形式で指定しています。
ユーザー名はsystemedのサービスファイルで指定しているUser名で良いです。
続いて、
sudo chmod 640 /etc/myspringboot/myspringboot.env
を実行します。こうすることで、
root ユーザー : 読み書き可能
ubuntu グループ: 読み取りのみ可能
その他のユーザー: アクセス不可
となります。
8-4. systemdのサービスファイルを編集
/etc/systemd/system/myspringboot.service
を編集します。
sudo nano /etc/systemd/system/myspringboot.service
を実行し、サービスファイルを以下のようにします。
[Unit]
Description=My Spring Boot Application
After=network.target
[Service]
User=ubuntu
WorkingDirectory=/home/ubuntu
EnvironmentFile=/etc/myspringboot/myspringboot.env
ExecStart=/usr/bin/java -jar /home/ubuntu/MySpringBoot-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod
Restart=always
[Install]
WantedBy=multi-user.target
重要なのは、
EnvironmentFile=/etc/myspringboot/myspringboot.env
です。これによってsystemdが、
myspringboot.env
↓
環境変数を読み込む
↓
Spring Bootを起動して変数を代入
という処理をしてくれます。例えば、
${DB_HOST}
↓
myspringboot-db.xxxxx.ap-northeast-1.rds.amazonaws.com
のようにSpring Bootが${DB_HOST}などを環境変数に置き換えます。
8-5. systemdに変更内容を読み込ませる
serviceファイルを変更したので、
sudo systemctl daemon-reload
を実行します。
9 新しいJARを作成・EC2へ転送する
JARの更新手順は以下のリンクを参照してください。
⇒EC2で公開したSpringBoot Webアプリを更新する方法
EC2にJARを転送出来たら次章へ進みます。
10. RDS MySQLへの接続をテストする
最終ステップです。実際にSpring Boot を起動して動作テストをおこないます。
10-1. Spring Bootを起動する
sudo systemctl start myspringboot
または
sudo systemctl restart myspringboot
を実行します。実行したら、
sudo systemctl status myspringboot
で確認します。
10-2. prod Profile が有効になっているか確認する
ログを確認します。
sudo journalctl -u myspringboot -n 100
Spring Boot の起動ログに、
The following 1 profile is active: "prod"
のような記載があれば prod Profileが有効になっています。
つまり、application-prod.yml が使われています。
ログが非常に長いですが、(おそらく)最後に記載されているSpring Bootの起動ログのみ見ればよいです。
10-3. ブラウザからWebアプリを確認する
最後にWebアプリのURLへアクセスしてみます。
DBを利用する機能を確認します。
CRUDを試して問題がなければ作業完了です。
10-4. RDS側でもデータを確認する
念入りに成功しているか確認したい場合は、RDS側でもデータが更新などできているか確認するのが良いです。
EC2からMySQLへ接続します。
mysql -h <RDSエンドポイント> -P 3306 -u <ユーザー名> -p
ログイン後、
USE myspringboot;
SHOW TABLES;
SELECT * FROM sample;
等を実行します。
Webアプリから登録したデータがRDS側にも存在すれば、H2ではなくRDS MySQLを実際に使用していることが確認できます。