はじめに
概要
DBを利用するWebアプリケーションにおいて、AWSを使用した本番環境の構築・アプリケーションのデプロイ方法について取り上げます。
前提条件
- Java/Spring Boot環境構築済み
- MySQL環境構築済み
- AWSアカウント作成済み
リポジトリ
動作環境
- Windows 11 Home(24H2)
- Java 21
- Maven 3.9.10
- Spring Boot 3.5.3
- MySQL 8.4.5
本手順
前編では、アプリケーションの開発と開発用DBの構築まで完了しました。
後編では、AWS上で本番環境を構築し、アプリケーションをデプロイする方法をまとめていきます。
DB構成
以降の手順では、DB構成は以下の通り進めます。
開発用DB
| 項目 | 内容 |
|---|---|
| サーバ | ローカルマシン |
| データベース名 | qiita_spring_dev |
| ユーザ名 | qiita_spring_dev_user |
| パスワード | devpassword |
本番用DB
| 項目 | 内容 |
|---|---|
| サーバ | DBサーバ(RDS) |
| データベース名 | qiita_spring_prod |
| ユーザ名 | qiita_spring_prod_user |
| パスワード | prodpassword |
1. ネットワークの構築(VPC)
2つのAZにまたがるネットワークを構築します。
パブリックサブネットは2つ、プライベートサブネットは4つ用意します。
CIDR設計は以下の通りです。
| ネットワーク | IPv4アドレス | CIDRブロック |
|---|---|---|
| VPC | 10.0.0.0/16 | 00001010.00000000.00000000.00000000 |
| public subnet 1 (1a) | 10.0.0.0/20 | 00001010.00000000.00000000.00000000 |
| public subnet 2 (1c) | 10.0.16.0/20 | 00001010.00000000.00010000.00000000 |
| private subnet 1 (1a) | 10.0.128.0/20 | 00001010.00000000.10000000.00000000 |
| private subnet 2 (1c) | 10.0.144.0/20 | 00001010.00000000.10010000.00000000 |
| private subnet 3 (1a) | 10.0.160.0/20 | 00001010.00000000.10100000.00000000 |
| private subnet 4 (1c) | 10.0.176.0/20 | 00001010.00000000.10110000.00000000 |
AWSコンソールにログインし、以下の通りVPCを作成します。
| 項目 | 内容 |
|---|---|
| 作成するリソース | VPCなど |
| 名前 | qiita-spring-ec2-rds(自動生成オン) |
| AZの数 | 2 |
| パブリックサブネットの数 | 2 |
| プライベートサブネットの数 | 4 |
| NATゲートウェイ | なし |
2. セキュリティグループの作成
以下の通り作成します。
1) 踏み台サーバ用
| 項目 | 内容 |
|---|---|
| 名前 | qiita-spring-ec2-rds-sg-bastion |
| インバウンドルール | 下表の通り |
| タイプ | ポート範囲 | ソース |
|---|---|---|
| SSH | 22 | 0.0.0.0/0 |
2) ロードバランサー用
| 項目 | 内容 |
|---|---|
| 名前 | qiita-spring-ec2-rds-sg-elb |
| インバウンドルール | 下表の通り |
| タイプ | ポート範囲 | ソース |
|---|---|---|
| HTTP | 80 | 0.0.0.0/0 |
3) Webサーバ用
| 項目 | 内容 |
|---|---|
| 名前 | qiita-spring-ec2-rds-sg-web |
| インバウンドルール | 下表の通り |
| タイプ | ポート範囲 | ソース |
|---|---|---|
| SSH | 22 | qiita-spring-ec2-rds-sg-bastion |
| カスタムTCP | 8080 | qiita-spring-ec2-rds-sg-elb |
4) DBサーバ用
| 項目 | 内容 |
|---|---|
| 名前 | qiita-spring-ec2-rds-sg-db |
| インバウンドルール | 下表の通り |
| タイプ | ポート範囲 | ソース |
|---|---|---|
| MYSQL/Aurora | 3306 | qiita-spring-ec2-rds-sg-web |
3. 踏み台サーバの構築(EC2)
1) キーペアの作成
SSH接続で使用するキーペアを以下の通り作成します。
| 項目 | 内容 |
|---|---|
| 名前 | qiita-spring-ec2-rds-key |
| キーペアのタイプ | RSA |
| プライベートファイルキー | .pem |
秘密鍵がダウンロードされます。
2) EC2インスタンスの作成
以下の通り作成します。
| 項目 | 内容 |
|---|---|
| 名前 | qiita-spring-ec2-rds-bastion |
| OS | Ubuntu |
| AMI | Ubuntu Server 24.04 LTS (HVM), SSD Volume Type |
| キーペア | qiita-spring-ec2-rds-key |
| VPC | qiita-spring-ec2-rds-vpc |
| サブネット | public subnet 1 (1a) |
| パブリックIPの自動割り当て | 有効 |
| セキュリティグループ | qiita-spring-ec2-rds-sg-bastion |
4. Webサーバ構築用AMIの作成
続いてWebサーバを構築していきます。
今回構築する各Webサーバはプライベートサブネットに配置し、特にNATゲートウェイなどは設けないので、Webサーバからインターネットには接続できない想定です。
よって、単純に構築すると、JDKやMySQLクライアントといった必要なコンポーネントをインストールできないため、以下手順を踏むことにします。
- 一度AMI作成用サーバをパブリックサブネットに構築
- 構築したサーバに接続し、JDK・MySQLクライアントをインストール
- 上記サーバにおけるAMIを作成
- 作成したAMIをもとにWebサーバを構築
- AMI作成用サーバを削除
Webサーバが継続的にインターネットへ接続する場合はNATゲートウェイを設ける必要があると思うのですが、今回は初回のJDKインストール時のみ必要なので上記方法で実施します。(NATゲートウェイを設けないことでコストを抑えます)
1) EC2インスタンスの作成
名前以外は、踏み台サーバ同様作成していきます。
| 項目 | 内容 |
|---|---|
| 名前 | qiita-spring-ec2-rds-ami-builder |
| OS | Ubuntu |
| AMI | Ubuntu Server 24.04 LTS (HVM), SSD Volume Type |
| キーペア | qiita-spring-ec2-rds-key |
| VPC | qiita-spring-ec2-rds-vpc |
| サブネット | public subnet 1 (1a) |
| パブリックIPの自動割り当て | 有効 |
| セキュリティグループ | qiita-spring-ec2-rds-sg-bastion |
2) JDKのインストール
キーペア作成時にローカルマシンにダウンロードされたqiita-spring-ec2-rds-key.pemファイルを~/.sshフォルダに配置します。
以下コマンドでAMI作成用サーバに接続します。
ssh -i ~/.ssh/qiita-spring-ec2-rds-key.pem ubuntu@<AMI作成用サーバのパブリックIPアドレス>
接続後、JDKをインストールします。
今回はJDKのディストリビューションとして、「Amazon Corretto 21」を使用します。
# AMI作成用サーバ
# 依存パッケージのインストール
sudo apt update
sudo apt install -y wget software-properties-common
# 署名キーの追加
wget -O- https://apt.corretto.aws/corretto.key | sudo apt-key add -
# リポジトリの追加
sudo add-apt-repository 'deb https://apt.corretto.aws stable main'
sudo apt update
# Amazon Corretto 21のインストール
sudo apt install -y java-21-amazon-corretto-jdk
バージョン確認を行い、正常にインストールされていることを確認します。
# AMI作成用サーバ
java --version
> openjdk 21.0.7 2025-04-15 LTS
> OpenJDK Runtime Environment Corretto-21.0.7.6.1 (build 21.0.7+6-LTS)
> OpenJDK 64-Bit Server VM Corretto-21.0.7.6.1 (build 21.0.7+6-LTS, mixed mode, sharing)
3) MySQLクライアントのインストール
引き続き、AMI作成用サーバ上でMySQLクライアントをインストールします。
# AMI作成用サーバ
# MySQLクライアントのインストール
sudo apt install -y mysql-client
バージョン確認を行い、正常にインストールされていることを確認します。
# AMI作成用サーバ
mysql --version
> mysql Ver 8.0.42-0ubuntu0.24.04.1 for Linux on x86_64 ((Ubuntu))
4) AMIの作成
AWSコンソールから、AMI作成用サーバを選択してイメージを作成します。
| 項目 | 内容 |
|---|---|
| 名前 | qiita-spring-ec2-rds-ami-web |
AMIが作成され、ステータスが「利用可能」となっていることを確認します。(5~10分ほどかかります)
ここまで完了すれば、AMI作成用サーバは停止/削除してしまって問題ありません。
5. Webサーバの構築(EC2)
ここではひとまず「Webサーバ1」のみ構築します。
作成したAMIを選択し、以下の通りインスタンスを起動します。
| 項目 | 内容 |
|---|---|
| 名前 | qiita-spring-ec2-rds-web1 |
| AMI | qiita-spring-ec2-rds-ami-web |
| キーペア | qiita-spring-ec2-rds-key |
| VPC | qiita-spring-ec2-rds-vpc |
| サブネット | private subnet 1 (1a) |
| パブリックIPの自動割り当て | 無効 |
| セキュリティグループ | qiita-spring-ec2-rds-sg-web |
6. 本番用DBの作成(RDS)
1) オプショングループ作成
以下の通り作成します。
| 項目 | 内容 |
|---|---|
| 名前 | qiita-spring-option-group |
| エンジン | mysql |
| メジャーエンジンバージョン | 8.4 |
2) パラメータグループ作成
以下の通り作成します。
| 項目 | 内容 |
|---|---|
| 名前 | qiita-spring-parameter-group |
| エンジンのタイプ | MySQL Community |
| パラメータグループファミリー | mysql8.4 |
3) サブネットグループ作成
以下の通り作成します。
| 項目 | 内容 |
|---|---|
| 名前 | qiita-spring-subnet-group |
| VPC | qiita-spring-ec2-rds-vpc |
| アベイラビリティーゾーン | ap-northeast-1a, ap-northeast-1c |
| サブネット | private subnet 3 (1a), private subnet 4 (1c) |
4) データベース作成
以下の通り作成します。
| 項目 | 内容 |
|---|---|
| 作成方法 | 標準作成 |
| エンジンのタイプ | MySQL |
| エンジンバージョン | MySQL 8.4.5 |
| テンプレート | 本番稼働用 |
| 可用性と耐久性 | マルチAZ(2インスタンス) |
| DBインスタンス識別子 | qiita-spring-prod-db |
| マスターユーザ名 | admin |
| 認証情報管理 | セルフマネージド(パスワードを自動生成:オン) |
| VPC | qiita-spring-ec2-rds-vpc |
| DBサブネットグループ | qiita-spring-subnet-group |
| パブリックアクセス | なし |
| セキュリティグループ | qiita-spring-ec2-rds-sg-db |
| データベース認証 | パスワード認証 |
| 最初のデータベース名 | qiita_spring_prod |
| DBパラメータグループ | qiita-spring-parameter-group |
| オプショングループ | qiita-spring-option-group |

作成が完了すると、上記メッセージが表示されます。
自動生成としたパスワードですが、上記メッセージの「接続の詳細の表示」から確認できます。
パスワードを確認できるのはこの時だけのようなので、忘れずに控えておきます。
5) ユーザ作成
本番環境での実行時にアプリケーションが使用するユーザを作成します。

手順としては、まず踏み台サーバ経由でWebサーバ1にSSH接続し、そこからDBサーバにログインしてユーザを作成していきます。
はじめに、SSH接続を行うための設定を行います。
ローカルマシンの~/.sshフォルダに、configファイルを作成します。
Host bastion
HostName <踏み台サーバのパブリックIPアドレス>
User ubuntu
IdentityFile ~/.ssh/qiita-spring-ec2-rds-key.pem
Host web1
HostName <Webサーバ1のプライベートIPアドレス>
User ubuntu
IdentityFile ~/.ssh/qiita-spring-ec2-rds-key.pem
ProxyCommand ssh -W %h:%p bastion
| 項目 | 内容 |
|---|---|
| Host | サーバに割り当てるエイリアス |
| HostName | IPアドレス/ホスト名(一つ前のマシンから見た情報なので、WebサーバはプライベートIPアドレスでOK) |
| User | ログインに使用するユーザ名(EC2インスタンス(OS:Ubuntu)のデフォルトユーザは「ubuntu」) |
| IdentityFile | 秘密鍵のパス(HostNameと異なり、ローカルマシンにおける情報を記述) |
| ProxyCommand | 踏み台サーバのエイリアスを記述 |
続いて、以下コマンドでWebサーバ1にSSH接続します。
ssh web1
無事接続できたら、DBサーバ上のMySQLにログインします。
# Webサーバ1
mysql -u admin -h <作成したデータベースのエンドポイント> -p
パスワードの入力が求められるので、先ほど控えたパスワードを入力します。
ログインできたら、以下コマンドでユーザの作成を行います。
# Webサーバ1
CREATE USER 'qiita_spring_prod_user'@'10.0.%' IDENTIFIED BY 'prodpassword';
ホスト名については、2つのWebサーバから使用するユーザになるので、それらのアドレスを集約しています。
続いて、本番用のデータベース内に作成する全てのテーブルに対する全ての権限をこのユーザに付与します。
# Webサーバ1
GRANT ALL ON qiita_spring_prod.* TO 'qiita_spring_prod_user'@'10.0.%';
本来であれば、本番用のユーザには最小限の権限を付与するべきかと思います。
7. サンプルアプリケーションの更新
1) 本番用DB接続情報の追加
本番環境で動くアプリケーションから本番用DBへのアクセス用に、prodプロファイルを用意します。
spring.datasource.url=${PROD_DB_URL}
spring.datasource.username=${PROD_DB_USERNAME}
spring.datasource.password=${PROD_DB_PASSWORD}
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=validate
8. アプリケーションのデプロイ
1) デプロイ用ディレクトリの作成
Webサーバ1に接続し、以下の通りアプリケーションのデプロイ先となるディレクトリを作成します。
# Webサーバ1
mkdir -p ~/app
2) 成果物のデプロイ
ローカルマシンに戻り、アプリケーションをビルドします。
./mvnw clean package
ビルド成果物であるJARファイルを、Webサーバ1のデプロイ用ディレクトリに転送します。
scp target/demo-0.0.1-SNAPSHOT.jar web1:~/app/app.jar
3) 環境変数ファイルの作成
再度Webサーバ1に接続し、~/appフォルダに、以下の通り.envファイルを作成します。
PROD_DB_URL=jdbc:mysql://<作成したデータベースのエンドポイント>:3306/qiita_spring_prod
PROD_DB_USERNAME=qiita_spring_prod_user
PROD_DB_PASSWORD=prodpassword
4) systemdサービスの設定
/etc/systemd/systemフォルダに、以下の通りqiita-spring-ec2-rds-app.serviceファイルを作成します。
※同フォルダでのファイル作成は管理者権限が必要です。
[Unit]
Description=Qiita Spring EC2 RDS Application
After=syslog.target network.target
[Service]
User=ubuntu
WorkingDirectory=/home/ubuntu/app
ExecStart=java -jar app.jar --spring.profiles.active=prod
EnvironmentFile=/home/ubuntu/app/.env
SuccessExitStatus=143
Restart=always
RestartSec=30
[Install]
WantedBy=multi-user.target
実行するjavaコマンドの引数にspring.profiles.active=prodを付与することで、プロファイルをprodとしてアプリケーションを実行しています。
また、EnvironmentFileとして環境変数ファイルのパスを指定しています。
サービスを有効化します。
# Webサーバ1
sudo systemctl enable qiita-spring-ec2-rds-app
9. 本番用テーブルの作成
1) マイグレーション実行
アプリケーションを実行することで、開発環境同様、Flywayによりマイグレーションが行われテーブルが作成されます。
ひとまずWebサーバ1に接続します。
アプリケーションは先ほどsystemdサービスとして登録したので、サービス起動により実行します。
# Webサーバ1
sudo systemctl start qiita-spring-ec2-rds-app
正常に起動していることを確認します。
# Webサーバ1
sudo systemctl status qiita-spring-ec2-rds-app
> Loaded: loaded (/etc/systemd/system/qiita-spring-ec2-rds-app.service; enabled; preset: enabled)
> Active: active (running) since …
先ほど同様、Webサーバ1からMySQLにログインしてテーブルを確認します。
# Webサーバ1
show tables;
+-----------------------------+
| Tables_in_qiita_spring_prod |
+-----------------------------+
| flyway_schema_history |
| users |
+-----------------------------+
2 rows in set (0.00 sec)
正常に作成されていることが分かります。
2) 初期データ登録
後ほど行う動作確認で使用するため、データを登録しておきます。
INSERT INTO users (
name,
age
)
VALUES
('本番太郎', 70),
('本番花子', 80),
('本番一郎', 90);
10. Webサーバのコピー
ここまでの状態で、AWSコンソールからWebサーバ1を選択してイメージを作成します。
| 項目 | 内容 |
|---|---|
| 名前 | qiita-spring-ec2-rds-ami-web-deployed |
作成したAMIを選択し、以下の通りインスタンスを起動します。
| 項目 | 内容 |
|---|---|
| 名前 | qiita-spring-ec2-rds-web2 |
| AMI | qiita-spring-ec2-rds-ami-web-deployed |
| キーペア | qiita-spring-ec2-rds-key |
| VPC | qiita-spring-ec2-rds-vpc |
| サブネット | private subnet 2 (1c) |
| パブリックIPの自動割り当て | 無効 |
| セキュリティグループ | qiita-spring-ec2-rds-sg-web |
11. ロードバランサーの作成(ELB)
はじめに以下の通りターゲットグループを作成します。
| 項目 | 内容 |
|---|---|
| ターゲットタイプ | インスタンス |
| 名前 | qiita-spring-ec2-rds-tg |
| プロトコル/ポート | HTTP/8080 |
| VPC | qiita-spring-ec2-rds-vpc |
| ヘルスチェックプロトコル | HTTP |
| ヘルスチェックパス | /users |
ターゲットには、Webサーバ1とWebサーバ2の2つを登録します。
続いて以下の通りロードバランサーを作成します。
| 項目 | 内容 |
|---|---|
| ロードバランサータイプ | Application Load Balancer |
| 名前 | qiita-spring-ec2-rds-elb |
| スキーム | インターネット向け |
| VPC | qiita-spring-ec2-rds-vpc |
| サブネット | public subnet 1 (1a), public subnet 2 (1c) |
| セキュリティグループ | qiita-spring-ec2-rds-sg-elb |
| プロトコル/ポート/デフォルトアクション | HTTP/80/qiita-spring-ec2-rds-tg |
ロードバランサーのステータスが「アクティブ」、ターゲットグループに含まれる各ターゲットのヘルスステータスが「Healthy」となっていることを確認します。(5分ほどかかります)
12. 動作確認
以下URLにアクセスします。
http://<ロードバランサーのDNS名>/users

続いて、DBのレプリケーションが行われていることを確認するため、手動でフェイルオーバーを実行します。

少し待つと、再びアクセスできるようになりました。
アプリケーションが表示している情報から、データが正常にレプリケーションされていることが分かります。
後片付け
本手順において、AWSサービスに対する必要以上の課金を防ぐ必要がある場合、最低限行う対応は以下の通りです。
- ロードバランサーの削除
- EC2インスタンスの停止
- RDSデータベースの削除
おわりに
以上で、DBを利用したWebアプリケーションにおける、AWSを使用した本番環境の構築・アプリケーションのデプロイが完了しました。
サーバは三層構成とし、WebサーバとDBサーバはプライベートサブネットに配置することで外部から隠蔽しています。
また、両サーバはマルチAZ構成でサーバを冗長化し、ロードバランサーによるトラフィックの分散、およびDBのレプリケーションを実現しました。
最後に、他にも基礎的なAWSインフラ構築関連の記事を書いているので、よければご参照ください。


