目的 背景
私事ながら転職をすることになり、今まではアプリ側の経験しかありませんでしたが、転職先の会社ではAWSを経験できる環境があるとのことで事前準備としてAWSの学習を行なっています。実際に幾つかのハンズオンを経験する中で、指示に従って設定するだけで自分の頭を使って試行錯誤する感覚が薄かったので、実際に自分で作成したアプリをデプロイすることでいろんな罠に引っかかりながら理解を深めようと思い、それが誰かの役に立てば嬉しいなと思い執筆しました。AWS初学者なので、間違っていることもあるかもしれませんので、その際はご指摘よろしくお願いします🙇
目次
- 構築するインフラ構成
- 事前準備
- ネットワーク構築
- S3構築
- DB構築
- EC2構築
- アプリの動作確認
- 補足 セキュリティグループの設定
- 最後に
- 参考資料
構築するインフラ構成
今回は上のような構成を構築します。
VPCを作成して、その中にパブリックサブネットとプライベートサブネットを2つずつ配置します。プライベートサブネットには、APサーバを2つとDBサーバを1つ構築します。またこれらのプライベートサブネットにアクセスするためのリソースとして、踏み台サーバをパブリックサブネットに構築します。コマンド実行やデプロイ作業はすべてこの踏み台サーバを経由することにより、APサーバやDBサーバーを安全なプライベートサブネットに配置しながら作業を進めることができます。
また、S3にVueのアプリをデプロイして、APサーバへのアクセスの際にALBを経由させて負荷分散を実施します。
事前準備
前提条件
Vue.js
- Node.js 16.x以上
- npm 8.6.0
SpringBoot
- Java17
事前にこれらの環境を構築した上で、以下のサンプルコードを私のGitHubから持ってきてください。
こちらのサンプルアプリをAWS上で動かしてみたいと思います。
3.ネットワーク構築
今回はCIDRを192.168.0.0/16にしました。
CIDRを設計する際に気を付けるポイントは以下になります。
CIDRは/16~/24にする
CIDRは/16から/24の範囲で設定することが一般的です。これはIPアドレスを枯渇させないためです。
VPCのCIDRの設計はサブネットの数を考慮する必要があります。
/16ということはそのVPCの中に2^16=65536個のIPアドレスが存在することになり、
/24ということはそのVPCの中に2^8=256個のIPアドレスが存在することになります。
私はインフラ構築を実務で経験したことがないのでそんなに必要なのかとは思いますが、必要なのでしょう🧐
プライベートIPアドレスを割り当てる
プライベートIPアドレスとは以下のようなIPアドレスです。
クラス | NWアドレス |
---|---|
A | 10.0.0.0~10.255.255.255 |
B | 172.16.0.0~172.31.255.255 |
C | 192.168.0.0~192.168.255.255 |
これらの中から選びましょう。
IPアドレスの重複に気をつける
オンプレミスとのハイブッド環境などでは、オンプレミスのIPアドレスと重複しないように注意しましょう。
サブネットの設計
次に作成したVPCにサブネットを作成します。
今回はVPC(192.168.0.0/16)の中に、192.168.1.0/24~192.168.4.0/24の4つのサブネットを作成します。
名前 | サブネット |
---|---|
private-1a | 192.168.1.0/24 |
private-1c | 192.168.2.0/24 |
public-1a | 192.168.3.0/24 |
public-1c | 192.168.4.0/24 |
サブネットの設計について意識するポイントは以下になります。
/24などの大きめのサブネットを作成する
VPCと同じ理由でIPアドレスが枯渇しないようにするためです。
予約済みのIPアドレスに注意する
各サブネットのCIDRブロック内で、以下の5つのIPアドレスは予約されており、使用できません。
- ネットワークアドレス(例: 192.168.1.0/24 の場合、192.168.1.0)
- VPCルーター用(例: 192.168.1.1)
- Amazon提供のDNSサーバー(例: 192.168.1.2)
- 将来の利用のために予約(例: 192.168.1.3)
- ブロードキャストアドレス(例: 192.168.1.255)
詳細については、AWS公式ドキュメントをご参照ください。
インターネットゲートウェイの設定
次にインターネットゲートウェイを設定します。
インターネットゲートウェイは、VPC内のリソースがインターネットと通信するための出入口となる重要なコンポーネントです。
これを設定しないとVPC内のインスタンスはインターネットに接続できません。
以下のように名前のみ指定して作成します。
またインターネットゲートウェイは作成しただけでは、VPCとインターネットを接続しません。作成したインターネットゲートウェイをVPCにアタッチする必要があります。
ルートテーブルの設定
次にルートテーブルを設計します。ルートテーブルは、VPC内および外部へのトラフィックの経路を定義します。各サブネットに関連付けることで、サブネット内のリソースがどのように通信するかを制御できます。
privateサブネットとpublicサブネット両方にそれぞれ作成します。
ルートテーブルとサブネットの関連付け
次にルートテーブルとサブネットの関連付けをします。
パブリックサブネット
プライベートサブネット
こうすることでプライベートサブネットとプライベートルートテーブル、パブリックサブネットとパブリックルートテーブルが関連づけられました。
ルートテーブルにインターネットゲートウェイを登録
最後にパブリックルートテーブルに対して、インターネットゲートウェイを登録します。この作業を行うことで、パブリックサブネットは初めてインターネットからアクセスできるようになります。
ここまででルートテーブルの設定も完了しました。
踏み台サーバ構築
次にプライベートサブネットに存在するEC2にアクセスするための踏み台サーバを構築します。まず一般的にAPサーバ(EC2)はセキュリティの観点からプライベートサブネットに配置します。ただ、これだとインターネット経由でアクセスができないため、運用時に不便なため、踏み台サーバを構築し、踏み台サーバからAPサーバに通信することでセキュリティを担保しながら作業を進めることが可能になります。
セキュリティグループ作成
踏み台サーバ用のセキュリティグループを作成します。
先に踏み台サーバにどのような通信が発生するのかを確認します。
少しわかりにくいですが、整理すると以下になります。
イン/アウト | 通信相手 |
---|---|
インバウンド | 運用PCからのSSH通信 |
アウトバウンド | APサーバ1 |
アウトバウンド | APサーバ2 |
アウトバウンド | DBサーバ |
踏み台サーバには、ローカルのPCからSSH接続を行うので、インバウンドルールにSSHを設定します。本来は接続元も自分のIPアドレスを指定した方がよりセキュリティは高まりますが、今回は指定しません。アウトバウンドに関しては、まだこの時点でAPサーバ用、DBサーバ用のセキュリティグループを作成していないのでまだ指定しなくて構いません。
踏み台サーバ構築
次に踏み台サーバの実態となるEC2を建てます。デフォルト設定から変更する箇所だけ画像を貼ります。
キーペアを作成します。
キーペアを作成ボタンをクリックすると勝手にダウンロードされるので、保管しておいてください。これはEC2にアクセスする際に必ず必要な秘密鍵になりますので紛失しないように注意してください。
VPCは自分の作成したVPCを選択して、踏み台サーバはパブリックサブネットに配置するので、public-1aを選択します。SSH接続をする際にIPアドレスを指定しないといけないのでパブリックIPを自動割り当てを有効化します。セキュリティグループは先ほど作成したものを選択します。
ここまでできたらEC2を起動してください。
踏み台サーバ接続
踏み台サーバが起動できたら、踏み台サーバに接続できることを確認してみましょう。以下のコマンドを実行してください。
chmod 400 秘密鍵
ssh -i 秘密鍵 ec2-user@踏み台サーバのパブリックIP
上の画像のようになればEC2に対してログイン成功です!
もしうまくいかない場合は以下の観点で確認してみてください。
うまくいかない場合
- 踏み台サーバ用のセキュリティグループのインバウンドルールにおいて、インターネット上(0.0.0.0/0)からのSSH通信を許可しているか
- パブリックサブネットにルートテーブルが紐づいているか
- パブリックルートテーブルにインターネットゲートウェイが紐づいているか
- EC2インスタンスが起動しているか
- キーペアが正しいか
ここまでできたら踏み台サーバの構築が完了しました。
DBの構築
まずは、DBを構築します。初めにDB用のセキュリティグループを作成します。
セキュリティグループの作成
踏み台サーバの時と同様再度、通信を確認します。
整理すると、
イン/アウト | 通信相手 |
---|---|
インバウンド | 踏み台サーバ |
インバウンド | APサーバ1 |
インバウンド | APサーバ2 |
DBはプライベートサブネットに存在しており、インターネット上から直接アクセスすることができないので、踏み台サーバを経由してアクセスします。また、APサーバからもアクセスします。この時点では踏み台サーバのセキュリティグループしか作成していないので一旦、踏み台サーバのセキュリティグループを設定します。タイプはPostgreSQLを指定します。
PostgreSQL構築
次にDBサーバを構築します。設定箇所が多いため、デフォルト設定から変更した箇所のみ記載します。
エンジンはPostgreSQLを選択して、テンプレートは無料利用枠を選択します。
マスタユーザ名とパスワードはご自身のお好きなように設定してください。
VPCは自分の作成したものを選択して、セキュリティグループはDB用のセキュリティグループを選択してください。
追加設定でDBサーバの名前を設定してください。
踏み台サーバからDBにアクセスしてみる
セキュリティグループの編集
踏み台サーバからPostgreSQLに接続し、操作するためには踏み台サーバに対してpsqlをインストールする必要があります。ただ今のままでは、踏み台サーバはインターネットからpsqlをインストールすることができないのでセキュリティグループに新たに以下の設定を追加します。また、先ほどDBのセキュリティグループを作成していないため保留にしていた、DBセキュリティグループへのアウトバウンド設定も追加します。
踏み台サーバに対して
すでに設定している内容↓
イン/アウト | 通信相手 |
---|---|
インバウンド | 運用PCからのSSH通信 |
アウトバウンド | APサーバ1 |
アウトバウンド | APサーバ2 |
アウトバウンド | DBサーバ |
踏み台サーバに対して
追加設定する内容↓
イン/アウト | 通信相手 |
---|---|
アウトバウンド | インターネット(HTTP) |
アウトバウンド | インターネット(HTTPS) |
アウトバウンド | DB用セキュリティグループ |
※踏み台サーバからAPサーバにSSH通信するのでその設定が抜けていますが、まだAPサーバ用のセキュリティグループを作成していないので後ほど設定します。
ここまでできたら踏み台サーバにログインして、次のコマンドを打ち込んでください。
sudo yum update -y
次にCloudShellを起動して、PostgreSQLのバージョンを確認します。
CloudShellって何?という方は以下の記事を参考にして起動してみてください。
CloudShellを起動して次のコマンドを打ってください。
aws rds describe-db-engine-versions --default-only --engine postgres
このコマンドを実行することでPostgreSQLのバージョンを確認します。私の環境ではバージョン16でした。
ここまでできたら、いよいよ踏み台サーバにpsqlをインストールします。ご自身の環境のDBバージョンに合わせてください。踏み台サーバにログインして以下のコマンドを打っていってください。
sudo yum install -y postgresql16
インストールが完了したら念の為インストールできたかを確認してください。
psql --version
バージョンが表示されればOKです。やっとここまででDBに接続する準備ができました。
ここまでできれば、以下のコマンドで実際にDBに接続してみてください。
psql -h <RDSのエンドポイント> -U <ユーザー名> -d <データベース名>
ちなみにRDSのエンドポイントは以下に記載があります。
ユーザ名とデータベース名は私と同じ設定であれば以下になります。
項目 | 設定値 |
---|---|
ユーザ名 | postgres |
データベース名 | postgres_server |
下のようになれば接続できています!
テーブル作成&サンプルデータ投入
次にテーブル作成とサンプルデータの投入をします。
サンプルアプリの以下のディレクトリのschema.sqlにまとまっています。
schema.sqlを踏み台サーバにコピー
DBサーバへの操作は踏み台サーバからしかできないので、踏み台サーバにschema.sqlを送信し、踏み台サーバでsqlを実行してDBにテーブル作成&データを追加します。
以下のコマンドをローカルで実行して下さい。
ローカルのschema.sqlを踏み台サーバに転送します。
scp -i [秘密鍵.pem] ローカルのschema.sqlのパス 踏み台サーバの保存先パス
次にちゃんと踏み台サーバにデータが転送されてるかを確認します。
踏み台サーバにログインして、ご自身が転送されたパスにschema.sqlがあれば成功です。
SQLを実行してDBにデータを追加
次に踏み台サーバにログインして、schema.sqlを実行してDBにデータを追加します。以下のコマンドを実行してください。
psql -h <エンドポイント> -p <ポート番号> -U <ユーザー名> -d <データベース名> -f schema.sql
上のようになれば成功しています。念の為、本当にデータがあるかを確認しています。
ここまででDBの構築とセットアップが完了しました。
APサーバ構築
次にAPサーバを構築していきます。
EC2用セキュリティグループの作成
APサーバを構築する前に、APサーバ用のセキュリティグループを作成します。
イン/アウト | 通信相手 |
---|---|
インバウンド | 踏み台サーバ用セキュリティグループ |
アウトバウンド | インターネット(HTTP) |
アウトバウンド | インターネット(HTTPS) |
アウトバウンド | DB用セキュリティグループ |
APサーバへのアクセスは踏み台サーバ経由で行うため、インバウンドで踏み台サーバ用のセキュリティグループを指定します。またELBを経由して負荷分散を行うため、本来はインバウンドとして、ELB用のセキュリティグループも設定が必要ですが、これはまだ作成していないので保留します。アウトバウンドではDBサーバにアクセスするため、DB用セキュリティグループを指定します。また、Javaのインストールなどをインターネット経由で行うため、HTTP,HTTPSを指定します。
踏み台サーバセキュリティグループ編集
踏み台サーバのセキュリティグループのアウトバウンドルールでAPサーバのセキュリティグループを指定しないといけませんでしたが、まだ未作成で設定できていなかったのでこのタイミングでしておきます。
NATゲートウェイの構築
APサーバはプライベートサブネットに存在しています。これからEC2の構築をするにあたって、APサーバにJavaをインストールする必要があります。ただ、今のままではインターネットに接続することができないのでNATゲートウェイを構築します。NATゲートウェイはインターネットからAPサーバに接続することはできませんが、APサーバからインターネットの単方向のみ接続できるというものです。
NATゲートウェイ作成
VPCのサイドバーよりNATゲートウェイを選択して、以下のような設定にします。
サブネットはパブリックを選択して、ElasticIPの割り当てを選択します。
ルートテーブルの編集
プライベートサブネットのルートテーブルを選択します。
送信先を0.0.0.0/0(インターネット)を指定してターゲットで先ほど作成したNATゲートウェイを選択します。これでNATゲートウェイが使えるようになりました。
APサーバの構築
APサーバ用のEC2を2台立てていきます。
APサーバは2つ構築するので、ap-server-1,ap-server-2としてください。
NW設定に関してはサブネットだけ異なるので注意してください。どちらもprivateを選択してください。
ここまでできたらEC2を起動してください。
ELBの設定
次にリクエストを二つのAPサーバに分散させるためにELBを作成します。
セキュリティグループを作成
インバウンドルールはインターネットからのアクセスを許可するのでHTTP,HTTPSを許可します。
アウトバウンドルールはAPサーバに振り分けるのでポートは8000(Springbootアプリがポート8000で起動する)でセキュリティグループはAPサーバ用を指定します。
ターゲットグループの作成
ターゲットグループとはロードバランサーの負荷分散先のことです。
ELBの作成
今回はインターネットからのアクセスをEC2に分散するのでALBを選択します。基本はデフォルトの設定で構いません。アベイラビリティゾーンはこのALBが動作するAZを選択するため、public-1aとpublic-1cを選択します。セキュリティグループは先ほど作成したELB用を選択します。ターゲットグループも先ほど作成したものを選択します。
APサーバ用セキュリティグループの編集
先ほどAPサーバ用のセキュリティグループを作成しましたが、まだELBを未作成だったため、ELBのセキュリティグループからのインバウンドルールの設定を保留にしていました。ここで、APサーバ用セキュリティグループに対して、ELBからのインバウンドルールを設定します。
ここまできたら、いよいよEC2にSpringbootアプリをデプロイしたいのですが、CORSの関係上、通信を許可するドメインを指定した上でアプリをビルド&デプロイする必要があります。ドメインについてはS3の設定を先に行わないとわからないため、中途半端ですが先にS3の設定を行います。
S3構築
S3を構築して、VueアプリをS3にデプロイします。
Vueアプリの準備
まずはデプロイするVueアプリの準備をします。
パッケージインストール
clientディレクトリに移動して、以下のコマンドを実行してパッケージをインストールしてください。
npm install
環境変数の設定
ご自身の環境に応じて環境変数を設定します。このアプリでは.env.productionでAWSにデプロイする用の環境変数の設定を行います。該当ファイルは以下のディレクトリに存在します。
上記の.env.productionにロードバランサーのDNS名を指定してください。
ちなみにロードバランサーのDNS名は以下にあります。
これはソースを見てもらえればわかるのですが、APIエンドポイントを指定しています。今回はAPサーバに直接リクエストを送信するのではなくて、ALBを経由するため、ここでALBのDNS名を指定する必要があります。
次に以下のコマンドを実行してビルドしてください。
npm run build
これでdistフォルダ配下にファイルが生成されればOKです。
S3バケットの設定
バケットの作成
まずはS3バケットを作成します。
注意点としてはバケット名はグローバルで一意でないといけないので、ご自身の好きなものに設定してください。またパブリックアクセスの設定についてはインターネットからアクセスしたいので、チェックを外してください。
ビルドファイルのアップロード
ビルドファイルをアップロードします。
distフォルダ配下にあるファイルたちをS3にアップロードします。
次にバケットタグに移動して、一番下の静的Webサイトホスティングを有効にします。
インデックスドキュメントとエラードキュメントは両方index.htmlに設定します。
そうするとサイトのURLが生成されるので試しにこのURLにアクセスしてみます。
すると403エラー(閲覧禁止)が返ってきます。
これはまだ、S3パケットに対して閲覧権限がないためです。そこでこのバケットに対するアクセス権限を変更して行きます。
バケットの権限変更
アクセス許可タブに移動してバケットポリシーの編集を行います。
そして以下のJSONをコピペしてください。
{
"Version": "2012-10-17",
"Id": "Policy1739401990507",
"Statement": [
{
"Sid": "Stmt1739401980782",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::practice-for-aws-vue-backet/*"
}
]
}
軽く説明すると、誰(Principal)がどこ(Resource)にどんな操作権限(Action)を持っているかを定義しています。この設定では、すべてのユーザが、practice-for-aws-vue-backet/配下のリソースに対して、オブジェクト(index.htmlやcssなど)を取得する権限を持っています。なので、画像のアップロードなどはできません。
一つ注意点として、arnに関してはご自身のものに置き換えてください。
ちなみにarnはここに表示されています。
そして再度サイトのURLにアクセスするとアクセスできました!!
ちなみにポリシージェネレータというツールがあり、これを使えば自分でポリシーの設定を行うことができますので興味のある方は使ってみてください。
使い方は以下のサイトを参考にしてみてください。
SpringBootアプリのデプロイ
ここまで準備ができたらいよいよSpringbootアプリをデプロイしていきます。
Springアプリの設定修正
application.properties絡みについて軽く説明すると下のようになります。
ファイル名 | 役割 |
---|---|
application.properties | 共通設定 |
application-development.properties | 開発用(ローカル動作確認) |
application-production.properties | 本番用(AWSデプロイ用) |
今からは実際にAWSにデプロイするので、application-production.propertiesをご自身のDB、CORS設定に修正してください。RDSのエンドポイントとS3のドメイン名を指定してください。
Springアプリのビルド
serverディレクトリまでカレントディレクトリを移動してビルドしてください。
./gradlew build
以下のようになれば成功です!
ビルドが成功すると以下の場所にjarファイルが作成されますのでこれをデプロイしていきます。
Springアプリのデプロイ
デプロイも踏み台サーバ経由でしかできませんので、まずはローカルから踏み台サーバに対して
- ビルドで生成されたjarファイル(server-0.0.1-SNAPSHOT.jar)
- 秘密鍵
を転送します。
ローカルで以下のコマンドを実行してください。
scp -i 秘密鍵 送信するファイル ec2-user@<踏み台サーバのIP>:/home/ec2-user
踏み台サーバにログインして転送を確認できればOKです。
次は踏み台サーバに転送した二つのファイルをAPサーバ1,APサーバ2にそれぞれ以下のコマンドで転送します。
scp -i 秘密鍵 server-0.0.1-SNAPSHOT.jar ec2-user@<プライベートEC2のプライベートIP>
これでAPサーバにJARファイルを転送することができました!
Javaのインストール
まだこのままではAPサーバにはJavaがインストールされていないので、Springbootアプリを動かすことができません。そこで、APサーバにJavaのインストールを行います。APサーバにログインして以下のコマンドを打ってください。
sudo yum install -y java-17-amazon-corretto-devel
SpringBootアプリの起動
ここまでできたらあとはアプリを起動するだけです。以下のコマンドを打ってください。
java -jar server-0.0.1-SNAPSHOT.jar --spring.profiles.active=production
以下のように Started ServerApplicationと表示されれば成功です!!
ここまできたらもう一つのAPサーバにも同様の手順でJavaのインストールとアプリのデプロイ、起動を行ってみてください。
動作確認
ここまでできたら、AWSの設定は完了です。実際にアプリが動くかどうかを確認してみましょう。
まずはログインページにアクセスしてください。
会員登録できていないと思うので、新規会員登録ページに遷移します。
会員登録画面に遷移したら好きなユーザで新規会員登録を行ってください。
登録をクリックすると再度ログインページに遷移しますので、先ほど登録したユーザでログインしてください。
ログインできたら、ハンバーガーメニューの書籍検索から書籍検索画面に遷移してください。
ここで検索ボタンをクリックすれば、いろんな書籍情報が一覧できます。
今回のハンズオンではAWS上にアプリをデプロイすることが目的のため、サンプルアプリはCursorを使って爆速実装し、簡単な動作確認しかしていません。それゆえアプリのレイアウト崩れや、不具合などあるかもしれませんがご了承ください🙇
補足 セキュリティグループの設定
私が今回のハンズオンをやっていく中で、うまくいかなかったポイントの多くはセキュリティグループの設定が足りていないなどの要因でした。そこで念の為、私のセキュリティグループの設定を最後に載せますので、もしうまくいかない方はこちらを参考にしてみてください。
ロードバランサー
踏み台サーバ
APサーバ
DBサーバ
最後に
実際に自分でインフラ構成を考えて自分で作ったアプリをデプロイすることで、特にセキュリティグループやELBの設定周りなどを中心にいろんなところに詰まりました。そしてそれを解決する中で知識が深まっていきました。転職後はよりAWSなどを実務で触る機会も多いと思いますので積極的にチャレンジにしていきたいと思います。
参考記事