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?

【ECS + RDS】コンテナ化Spring Boot/MySQLアプリの本番環境を構築 [後編] - AWSインフラ構築とデプロイ

Last updated at Posted at 2025-08-12

はじめに

概要

DBを利用するWebアプリケーションにおいて、AWSを使用した本番環境の構築・コンテナ化アプリのデプロイ方法について取り上げます。

image.png

前提条件

  • Java/Spring Boot環境構築済み
  • Docker環境構築済み
  • AWSアカウント作成済み

リポジトリ

動作環境

  • Windows 11 Home(24H2)
  • Java 21
  • Maven 3.9.11
  • Spring Boot 3.5.4
  • MySQL 8.4.5
  • Docker 27.3.1
  • Docker Desktop 4.36.0

本手順

前編では、開発環境の構築まで完了しました。

後編では、AWS上で本番環境を構築し、アプリケーションをデプロイする方法をまとめていきます。

DB構成

以降の手順では、DB構成は以下の通り進めます。

開発用DB

項目 内容
サーバ ローカルマシン(Dockerコンテナ)
データベース名 qiita_spring_ecs_dev
ユーザ名 qiita_spring_ecs_dev_user
パスワード devpassword

本番用DB

項目 内容
サーバ DBサーバ(RDS)
データベース名 qiita_spring_ecs_prod
ユーザ名 qiita_spring_ecs_prod_user
パスワード prodpassword

環境全体像

開発環境・本番環境の大まかな全体像は以下の通りです。
image.png

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-ecs-rds(自動生成オン)
AZの数 2
パブリックサブネットの数 2
プライベートサブネットの数 4
NATゲートウェイ なし
VPCエンドポイント S3ゲートウェイ

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

以下の通り作成します。

1) ロードバランサー用

項目 内容
名前 qiita-spring-ecs-rds-sg-elb
インバウンドルール 下表の通り

タイプ ポート範囲 ソース
HTTP 80 0.0.0.0/0

2) ECSサービス用

項目 内容
名前 qiita-spring-ecs-rds-sg-service
インバウンドルール 下表の通り

タイプ ポート範囲 ソース
カスタムTCP 8080 qiita-spring-ecs-rds-sg-elb

3) VPCエンドポイント用

項目 内容
名前 qiita-spring-ecs-rds-sg-vpce
インバウンドルール 下表の通り

タイプ ポート範囲 ソース
HTTPS 443 qiita-spring-ecs-rds-sg-service

4) DBサーバ用

項目 内容
名前 qiita-spring-ecs-rds-sg-db
インバウンドルール 下表の通り

タイプ ポート範囲 ソース
MYSQL/Aurora 3306 qiita-spring-ecs-rds-sg-service

3. 本番用DBの作成(RDS)

1) オプショングループ作成

以下の通り作成します。

項目 内容
名前 qiita-spring-ecs-option-group
エンジン mysql
メジャーエンジンバージョン 8.4

2) パラメータグループ作成

以下の通り作成します。

項目 内容
名前 qiita-spring-ecs-parameter-group
エンジンのタイプ MySQL Community
パラメータグループファミリー mysql8.4

3) サブネットグループ作成

以下の通り作成します。

項目 内容
名前 qiita-spring-ecs-subnet-group
VPC qiita-spring-ecs-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-ecs-prod-db
マスターユーザ名 admin
認証情報管理 セルフマネージド(パスワードを自動生成:オン)
VPC qiita-spring-ecs-rds-vpc
DBサブネットグループ qiita-spring-ecs-subnet-group
パブリックアクセス なし
セキュリティグループ qiita-spring-ecs-rds-sg-db
データベース認証 パスワード認証
最初のデータベース名 qiita_spring_ecs_prod
DBパラメータグループ qiita-spring-ecs-parameter-group
オプショングループ qiita-spring-ecs-option-group

image.png
作成が完了すると、上記メッセージが表示されます。
自動生成としたパスワードですが、上記メッセージの「接続の詳細の表示」から確認できます。

パスワードを確認できるのはこの時だけのようなので、忘れずに控えておきます。

5) ユーザ作成

本番環境での実行時にアプリケーションが使用するユーザを作成します。
手順としては、AWSが提供するCloudShellを利用してRDSへ接続し、管理者ユーザでMySQLにログインして作業を行います。

image.png
CloudShellを開きます。

image.png
+ボタンから「Create VPC environment (max 2)」を選択します。

以下の通り作成します。

項目 内容
Name qiita-spring-ecs-rds-shell(任意)
VPC qiita-spring-ecs-rds-vpc
Subnet private subnet 3 (1a)
Security group qiita-spring-ecs-rds-sg-service

RDSを構築したVPC・サブネットに対して、ECSサービス用のセキュリティグループを設定して接続しています。

image.png
シェルが立ち上がります。

DBサーバ上のMySQLにログインします。

mysql -u admin -h <作成したデータベースのエンドポイント> -p

パスワードの入力が求められるので、先ほど控えたパスワードを入力します。

ログインできたら、以下コマンドでユーザの作成を行います。

CREATE USER 'qiita_spring_ecs_prod_user'@'10.0.%' IDENTIFIED BY 'prodpassword';

ホスト名については、2つのWebサーバから使用するユーザになるので、それらのアドレスを集約しています。

続いて、本番用のデータベース内に作成する全てのテーブルに対する全ての権限をこのユーザに付与します。

GRANT ALL ON qiita_spring_ecs_prod.* TO 'qiita_spring_ecs_prod_user'@'10.0.%';

本来であれば、本番用のユーザには最小限の権限を付与するべきかと思います。

CloudShellには、今回使用したMySQLクライアント含め、GitやDockerなど開発でよく使用されるツールが事前にインストールされています。
別途必要なツールがあれば、ベースはAmazon Linuxなので、yumコマンドでインストールできます。

4. 本番用DB接続情報登録(Secrets Manager)

本番用DBに接続するために使用するパスワードなどの機密情報は、AWS Secrets Managerに保存し、ECSタスクからはこちらを参照して使用するようにします。

Secrets Managerから、以下の通りシークレットを保存します。

項目 内容
シークレットのタイプ Amazon RDS データベースの認証情報
ユーザー名 qiita_spring_ecs_prod_user
パスワード prodpassword
データベース qiita-spring-ecs-prod-db
シークレットの名前 prod/qiita-spring-ecs-rds/mysql

5. サンプルアプリケーションの更新

1) 本番用DB接続情報の追加

本番環境で動くアプリケーションから本番用DBへのアクセス用に、prodプロファイルを用意します。

application-prod.properties
spring.datasource.url=jdbc:mysql://<作成したデータベースのエンドポイント>:3306/${PROD_DB_DATABASE}
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

開発環境同様、接続情報は環境変数を参照していますが、本番環境では.envファイルではなくSecrets Managerから環境変数として取得します。

6. プライベートリポジトリの作成(ECR)

ECRに以下の通りプライベートリポジトリを作成します。

項目 内容
名前 qiita-spring-ecs-rds-app
ミュータビリティ Mutable
暗号化設定 AES-256

7. Dockerイメージの作成

1) 本番用イメージ定義作成(Dockerfile)

作成済みのDockerfileに下の2行を追加します。

Dockerfile
FROM amazoncorretto:21 AS base
WORKDIR /app
COPY target/demo-0.0.1-SNAPSHOT.jar app.jar
COPY .env .env
EXPOSE 8080

FROM base AS dev
EXPOSE 5005
ENTRYPOINT ["java", "-Djava.net.preferIPv4Stack=true", "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005", "-jar", "/app/app.jar", "--spring.profiles.active=docker"]

FROM base AS prod
ENTRYPOINT ["java", "-jar", "/app/app.jar", "--spring.profiles.active=prod"]

本番環境では、prodステージを指定して作成したイメージを使用します。
こちらは開発環境と異なり、デバッグ機能はなくしており、またSpring Bootのプロファイルはprodを指定しています。

2) イメージのビルド・プッシュ

はじめに、アプリケーションをビルドしておきます。

./mvnw clean package

dbサービスが立ち上がっていない場合ビルドが失敗するので、docker compose up -d dbで立ち上げておきます。

ECRのレジストリに対して認証を行います。

aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin <AWSアカウントID>.dkr.ecr.ap-northeast-1.amazonaws.com

先ほど作成したDockerfileをもとに、prodステージを指定してDockerイメージをビルドします。

docker build --target prod -t qiita-spring-ecs-rds-app-prod .

最後に、作成したイメージに1.0.0のタグを付け、ECRへプッシュします。

docker tag qiita-spring-ecs-rds-app-prod:latest <AWSアカウントID>.dkr.ecr.ap-northeast-1.amazonaws.com/qiita-spring-ecs-rds-app:1.0.0
docker push <AWSアカウントID>.dkr.ecr.ap-northeast-1.amazonaws.com/qiita-spring-ecs-rds-app:1.0.0

8. VPCエンドポイントの作成

ECSサービスはプライベートサブネットに配置しますが、VPC外部のAWSサービスへアクセスする必要があるため、エンドポイントを作成します。

作成するエンドポイントは以下の5つです。

エンドポイント 内容
com.amazonaws.ap-northeast-1.ecr.dkr Dockerイメージのプル
com.amazonaws.ap-northeast-1.ecr.api Dockerレジストリへの認証
com.amazonaws.ap-northeast-1.s3(Gateway) Dockerイメージの保存
com.amazonaws.ap-northeast-1.logs CloudWatch Logsへのログ書き込み
com.amazonaws.ap-northeast-1.secretsmanager シークレットの取得

3つ目のs3は、初めの「ネットワークの構築」でVPCと併せて作成しているので、残り4つを作成します。

ecr.dkr
以下の通り作成します。

項目 内容
名前 qiita-spring-ecs-rds-vpce-ecr-dkr
タイプ AWSのサービス
サービス com.amazonaws.ap-northeast-1.ecr.dkr
VPC qiita-spring-ecs-rds-vpc
サブネット private subnet 1 (1a), private subnet 2 (1c)
セキュリティグループ qiita-spring-ecs-rds-sg-vpce

名前・サービス以外の項目は同一の内容で、残り3つのエンドポイントも作成します。

9. ロードバランサーの作成(ELB)

はじめに以下の通りターゲットグループを作成します。

項目 内容
ターゲットタイプ IPアドレス
名前 qiita-spring-ecs-rds-tg
プロトコル/ポート HTTP/8080
VPC qiita-spring-ecs-rds-vpc
ヘルスチェックプロトコル HTTP
ヘルスチェックパス /users

ターゲットには何も登録せずに登録とします。

ECSタスク起動時に、ECSがタスクに対してIPアドレスの割り当て・ターゲットグループへの追加を自動で行ってくれるので、ここでは何も登録しなくて大丈夫です。

続いて以下の通りロードバランサーを作成します。

項目 内容
ロードバランサータイプ Application Load Balancer
名前 qiita-spring-ecs-rds-elb
スキーム インターネット向け
VPC qiita-spring-ecs-rds-vpc
サブネット public subnet 1 (1a), public subnet 2 (1c)
セキュリティグループ qiita-spring-ecs-rds-sg-elb
プロトコル/ポート/デフォルトアクション HTTP/80/qiita-spring-ecs-rds-tg

ロードバランサーのステータスが「アクティブ」となっていることを確認します。

10. ECSの構築

1) クラスターの作成

以下の通り作成します。

項目 内容
名前 qiita-spring-ecs-rds-cluster
インフラストラクチャ AWS Fargate (サーバーレス)

2) IAMロールの作成

続いて、この後作成するタスク定義にアタッチするIAMロールを作成します。

image.png
ECSTaskExecutionRoleというロールを作成し、2つのポリシーをアタッチします。

各ポリシーの役割は以下の通りです。

ポリシー 役割
AmazonECSTaskExecutionRolePolicy ECRからイメージ取得、CloudWatch Logsへログ出力
AmazonECSSecretsManagerAccessPolicy Secrets Managerからシークレット取得

実際に作成していきます。

AmazonECSSecretsManagerAccessPolicy
IAMポリシーから以下の通り作成します。

項目 内容
アクセス許可 以下の通り
名前 AmazonECSSecretsManagerAccessPolicy
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetSecretValue"
      ],
      "Resource": [
        "<Secrets Managerに登録したシークレットのARN>"
      ]
    }
  ]
}

ECSTaskExecutionRole
IAMロールから以下の通り作成します。

項目 内容
エンティティタイプ AWSのサービス
サービスまたはユースケース Elastic Container Service
ユースケース Elastic Container Service Task
許可ポリシー AmazonECSTaskExecutionRolePolicy, AmazonECSSecretsManagerAccessPolicy
名前 ECSTaskExecutionRole

3) タスク定義の作成

以下の通りタスク定義を作成します。

項目 内容
名前 qiita-spring-ecs-rds-task
起動タイプ AWS Fargate
タスク実行ロール ECSTaskExecutionRole

コンテナは以下の通り1つ作成します。

項目 内容
名前 qiita-spring-ecs-rds-app
イメージURI <作成したECRリポジトリのURI>:1.0.0
必須コンテナ はい
プライベートレジストリ認証 オフ
コンテナポート 8080
プロトコル TCP
アプリケーションプロトコル HTTP

また、環境変数を以下の通り設定します。

キー 値のタイプ
PROD_DB_DATABASE ValueFrom Secrets Managerに登録したシークレットのARN:dbname::
PROD_DB_USERNAME ValueFrom Secrets Managerに登録したシークレットのARN:username::
PROD_DB_PASSWORD ValueFrom Secrets Managerに登録したシークレットのARN:password::

4) サービスの作成

先ほど作成したクラスターから、サービスを作成します。

項目 内容
タスク定義ファミリー qiita-spring-ecs-rds-task
リビジョン 1(最新のもの)
サービス名 qiita-spring-ecs-rds-service
コンピューティングオプション 起動タイプ
起動タイプ FARGATE
プラットフォームバージョン LATEST
必要なタスク 2
リバランス オン
VPC qiita-spring-ecs-rds-vpc
サブネット private subnet 1 (1a), private subnet 2 (1c)
セキュリティグループ qiita-spring-ecs-rds-sg-service
パブリックIP オフ
ロードバランサーの種類 Application Load Balancer
コンテナ qiita-spring-ecs-rds-app 8080:8080
ロードバランサー qiita-spring-ecs-rds-elb
リスナー HTTP:80
ターゲットグループ qiita-spring-ecs-rds-tg

image.png
5分ほど待ち、作成されたサービスを確認すると、ステータスはアクティブとなり、2件のタスクが実行中であることが分かります。

11. 本番用テーブルの作成

1) マイグレーション実行

先ほどのサービス作成によりタスクが起動し、アプリケーションが実行されました。
これにより、本番環境でもFlywayによるマイグレーションが実行されているはずです。

再びCloudShellからRDSに接続し、テーブルが作成されていることを確認します。

mysql -u qiita_spring_ecs_prod_user -h <作成したデータベースのエンドポイント> -p qiita_spring_ecs_prod

ログインできたら、以下コマンドでテーブルを確認します。

show tables;
+---------------------------------+
| Tables_in_qiita_spring_ecs_prod |
+---------------------------------+
| flyway_schema_history           |
| users                           |
+---------------------------------+
2 rows in set (0.003 sec)

正常に作成されていることが分かります。

2) 初期データ登録

この後の動作確認で使用するため、本番用テーブルに以下の通りデータを登録します。

INSERT INTO users (
    name,
    age
)
VALUES
    ('本番太郎', 70),
    ('本番花子', 80),
    ('本番一郎', 90);

12. 動作確認

以下URLにアクセスします。
http://<ロードバランサーのDNS名>/users
image.png
無事動いています!

後片付け

本手順において、AWSサービスに対する必要以上の課金を防ぐ必要がある場合、最低限行う対応は以下の通りです。

  • ロードバランサーの削除
  • ECSサービスの削除
  • ECSタスク定義の削除
  • ECRにプッシュしたイメージの削除
  • VPCエンドポイント(ecr.dkr, ecr.api, logs, secretsmanager)の削除
  • RDSデータベースの削除
  • Secrets Managerの削除

おわりに

以上で、DBを利用したWebアプリケーションにおける、AWSを使用した本番環境の構築・コンテナ化アプリのデプロイが完了しました。

サーバは三層構成とし、WebサーバとDBサーバはプライベートサブネットに配置することで外部から隠蔽しています。
両サーバはマルチAZ構成でサーバを冗長化し、ロードバランサーによるトラフィックの分散、およびDBのレプリケーションを実現しました。

アプリケーションのDockerイメージは、マルチステージビルドを利用して、開発環境用・本番環境用を切り替えられるようにしています。

また、開発環境同様、Spring Bootのプロファイルを利用して本番用DBに接続しています。
接続情報はSecrets Managerで安全に管理しています。

最後に、他にも基礎的なAWSインフラ構築関連の記事を書いているので、よければご参照ください。

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?