はじめに
初めまして。
突然ですが皆さんは自分の Web サイトを使ってハッピーメリークリスマスを伝えたいと思ったことはないでしょうか。
僕は無いです。
ないですが、AWS を使ってフルスタック的な Web サイトは作ってみたいと思い、その練習の備忘録として今回この記事を書きます。
こちらの記事は未経験からエンジニアの職について 3 ヶ月目の超ピヨピヨが執筆しますので、至らぬ点などもあるかと思いますが
どうか温かい目で見守っていただければと思います。
やること・やらないこと
作業に入っていく前に断っておきたいことがあるのですが、今回の記事ではアプリケーションの細かい実装の説明などは省かせていただきます。
あくまでこちらの記事は、「ローカルで動作確認済みのアプリケーションを、AWS でデプロイしてみよう」というコンセプトの元で記事を書いていきます。
やること
- AWS でデプロイするまでの AWS Console 上での操作
- AWS 上で構築する際の設定と、ソースコード上での関連の説明
やらないこと
- ローカルで動作するアプリケーションの作成
- Docker での環境構築
- ソースコードの説明
前提条件
- アプリケーションがローカル環境で動く
- Docker, docker-compose で構築している
- AWS アカウントが存在する
- フロントエンド:Vue + VITE
- バックエンド:Nest.js
- データベース:Prisma + MySQL
インフラ構成について
- VPC, Fargate, ECR, CloudFront, S3, RDS で構築していきます
イメージはこんな感じ ↓
それでは、こちらにならって早速やっていきましょう!
手順 1:S3 にフロントエンドのビルド済みファイルをアップロードしよう
1-1:S3 バケットの作成
まず AWS Console 上で S3 を探してアクセスします。右上のオレンジ色ボタンの「バケットを作成」を押しましょう。
すると以下のような画面が現れるので、バケットにわかりやすい名前をつけましょう。今回は「isono-bucket」とします。
名前をつけたら、残りはデフォルトのままでいいのでそのままバケット作成まで進みます。
1-2:S3 バケットにビルド済みファイルをアップロード
先ほど作成したバケットの設定画面に移っていただいて、アップロードを押しましょう。
そうするとファイルをアップロードできるようになるので、ローカル環境でビルド済みのファイル(npm run build コマンドなどで作成されるファイル群)をドラッグ&ドロップもしくは選択してアップロードします。
注意
dist フォルダごとではなく、dist/配下にあるファイルをアップロードしてください。
ここまでできたら S3 の設定は完了です!
手順 2:CloudFront から S3 バケットにアクセスできるようにしよう!
2-1:CloudFront ディストリビューションの作成
こちらもまず S3 と同様に、AWS Console 上で CloudFront を探してアクセスしてください。
ディストリビューション作成画面に移り、ディストリビューションを作成していきます。
今回はシンプルなアプリケーションなので無料プランにしましょう。
名前の設定は S3 と同じような感じで「isono-distribution」とします。

Origin type は Amazon S3 を設定します。
S3 origin には、先ほど自分で作成した S3 bucket を選択します。
今回でいえば「isono-bucket」ですね。右の Browse S3 から探して適用しましょう。
残りの設定は全てデフォルトで進めていきます。そのままディストリビューション作成まで行って大丈夫です。

ディストリビューションを作成したらデプロイが完了するまで少し待ちましょう。
以下のように origin が「isono-bucket」になってるディストリビューション(私の場合は)が作成されていたら成功です!
2-2:OAC の追加
OAC とはオリジンアクセスコントロールの略で、文字通りオリジン(S3 バケット)へのアクセスを制御するものです。
自分のディストリビューションの設定画面から、オリジンタブを選択し、自分のオリジンにチェックをつけて編集ボタンを押してください。そうすると以下のページになるのでここで OAC を作成していきます。
この 1 番下に書いてある「Origin access control」欄から、Create new OAC ボタンを押し、自分の S3 バケットに対する OAC を作成していきましょう。

OAC を作成したら「変更を保存」をクリックします。
すると、画面上部に「S3 バケットポリシーを更新する必要があります」という青いバナーが表示されます。
このバナーの中にある「ポリシーをコピー」ボタンをクリックして、バケットポリシーをコピーしておきましょう。
次に、S3 の設定画面に移動します。
- S3 コンソールで先ほど作成した「isono-bucket」を開く
- 「アクセス許可」タブを選択
- 「バケットポリシー」セクションの「編集」ボタンをクリック
- 先ほどコピーしたポリシーを貼り付けて「変更の保存」をクリック
これで CloudFront から S3 バケットへのアクセスが許可されました。
2-3:ルートパスで index.html にアクセスできるようにする(やらなくてもいい)
今回は、手間を減らすためルートパスにアクセスしたら自動で index.html にアクセスするように設定していきます。必須の作業ではないのでここは飛ばしていただいても構いません。
もしやらない場合は、CloudFront のドメインにアクセスした場合、url の末尾に/index.html と打ち込むことでサイトが見られるようになります。
行うこととしては CloudFront 用の関数を定義することです。
それでは設定に移っていきます。
まず、画面左側にある CloudFront のメニューの中から、「関数」と書かれている部分をクリックしてください。
そうすると右上に、オレンジ色の「関数を作成」ボタンがあると思うのでこちらをクリックして関数を作成していきます。
今回も例に倣って関数名は「isono-function」にしましょう。

そうすると関数の詳細画面のようなところに遷移するので、こちらでこの関数の挙動を定義しておきます。
今回実現したいことは「ルートパスに遷移したら/index.html を表示したい」ということなので、以下のようなコードを開発タブの中に記述します。
function handler(event) {
var request = event.request;
var uri = request.uri;
// ルートパス(/)の場合、/index.htmlにリダイレクト
if (uri === "/") {
request.uri = "/index.html";
}
return request;
}
変更を保存します。
次に、作成した関数と自分の CloudFront ディストリビューションを関連づけます。
先ほどコードを埋め込んだ開発タブと同じ並びにある発行タブへ移っていただき
「関連付けを追加」を押しましょう。
自分のディストリビューションに関連づけることができたら以下のようになっているはずです。

ディストリビューションに間違いがなければオレンジ色の「関数を発行」ボタンを押して関数を発行させましょう。
ここまでできたら関数の適用は完了です。
ちなみに、紐づいているかどうかは CloudFront 側の画面で確認することができます。

先ほど作成した「isono-function」がちゃんとありますね。
2-4:動作確認
ここまでできたらあとは動作確認をするだけです。
自分のディストリビューションの詳細画面を開きます。
左上に書いてある「ディストリビューションドメイン名」をコピーし、ブラウザの検索欄に貼り付けましょう。
自分で作ったフロントエンドの画面が表示されればフロントエンド編は完了です!
お疲れ様でした!
手順 3:VPC の構築
喜びも束の間、次はバックエンド&DB 側のお話です。
まずはそれらの全ての土台となる VPC の作成から行っていきます。
VPC とは「Virtual Private Cloud」の略で、簡単に言うと AWS 上に仮想的なネットワーク空間を自分で作ることを可能にしてくれるものです。
それでは、早速ですが VPC の構築を行っていきましょう。
3-1:VPC の作成
まず AWS Console 上で VPC を探してアクセスしてください。
右上のオレンジ色の「VPC を作成」ボタンを押して VPC を作成していきましょう。
以下の画面になるので、今回もわかりやすいように VPC の名前は「isono」とします。
(isono-vpc にすると、AWS 側で自動的に isono-vpc-vpc という名前になってしまうため、「isono」のみにしています)
また、作成するリソースについては、サブネットなども自動で作成してほしいので「VPC など」を選択しましょう。

あとはデフォルトのまま進めていくとあら不思議、
必要なものは AWS 様が作ってくれます!

AWS が必要なリソースを自動で作成してくれます。
(まだ必要な設定がありますが、それは後の手順で作成していきます。)
状態が Available になっていれば OK です!

3-2:ALB 用セキュリティグループの作成
VPC の画面左メニューの中から、セキュリティグループをクリックしてください。
セキュリティグループ一覧画面が表示されます。
右上のオレンジ色の「セキュリティグループを作成」ボタンを押しましょう。
セキュリティグループ名は「isono-sg-alb」にしましょう。
説明は書いても書かなくてもいいですがわかりやすくするため書いておきましょう。
VPC は言わずもがな自分の作成した VPC です。「isono-vpc」
ところで、ALB とは Application Load Balancer の略で、これは後ほど登場します。
簡単に言うと、インターネット上からのアクセスを自動で振り分けてくれるロードバランサーです。
順番が少し前後しましたが、セキュリティグループとは「どこから来たアクセスなら許可するか」と「どこへのアクセスなら許可するか」などを適用できる、セキュリティを実装してくれるものです。
「どこから来たアクセスなら許可するか」が「インバウンドルール」
「どこへのアクセスなら許可するか」が「アウトバウンドルール」です。

ALB はフロントエンド側から来たリクエストの 1 番最初の受け手なので、
インバウンドルールは CloudFront から受け付ける設定のみにします。
インバウンドルールの設定:
- タイプ:HTTP
- ポート:80
- ソース:虫眼鏡をクリックしてプレフィックスリストの中から「com.amazonaws.global.cloudfront.~~」(例:pl-58a04531)を選択
アウトバウンドは、設定してもいいのですが今回は簡単なものを作るので全てのトラフィックにしましょう。
あとは作成ボタンを押せば ALB 用のセキュリティグループ、「isono-sg-alb」が完成です。
3-3:パブリックサブネット用セキュリティグループの作成
次は VPC を作成した時に一緒にできたパブリックサブネット用のセキュリティグループを作成します。
今回のアプリケーションの例では、ALB の次に到達するポイントですね。
つまり、パブリックサブネット(Fargate タスクが稼働する場所)は、ALB からのアクセスに限定しておけば良いということになります。
その設定を以下の手順で行っていきます。
セキュリティグループを作成します。
セキュリティグループ名は「isono-sg-public」にしましょう。
インバウンドルールの設定:
- タイプ:カスタム TCP
- ポート:3000(バックエンドアプリケーションのポート)
- ソース:セキュリティグループから「isono-sg-alb」を選択
セキュリティグループの中に先ほど作成した isono-sg-alb があります!
これをルールに設定することで、このセキュリティグループを適用しているものは ALB からのアクセスに絞ることができます。
アウトバウンドは相変わらず全てにしておきましょう。
3-4:プライベートサブネット用セキュリティグループの作成
最後に VPC を作成した時に一緒にできたプライベートサブネット用のセキュリティグループを作成します。
今回のアプリケーションの例では、RDS(データベース)が配置される場所です。
Fargate タスクからのデータベースアクセスを許可する必要があります。
それでは作成していきましょう!
セキュリティグループ名は「isono-sg-private」にします。
インバウンドルールの設定:
- タイプ:MYSQL/Aurora
- ポート:3306
- ソース:セキュリティグループから「isono-sg-public」を選択
パブリックサブネットのセキュリティグループ(isono-sg-public)からのアクセスのみを許可します。
これにより、Fargate タスクからのみデータベースにアクセスできるようになります。
ちなみに、アウトバウンドルールは無しで大丈夫です。ここが最終終着点なのでこれ以上どこかにアクセスすることはないからです。
ここまでで大体の VPC の構築は完了してます。残りの必要な設定は都度行っていきましょう。
手順 4:ECR の作成とイメージアップロード
ECR とは以下のように定義されています。
Amazon Elastic Container Registry (Amazon ECR) は、安全でスケーラブル、信頼性の高い AWS マネージドコンテナイメージレジストリサービスです。
(Amazon AWS Documentation より)
つまり、コンテナイメージのレジストリサービスです。
コンテナといえばそう、Docker ですよね。
イメージといえば、Docker を build した時にできますよね。
そう、つまり ECR とは「Docker でビルドしたイメージを AWS 上に保管できるサービスですよ」というふうに言い換えることができます。(※今回のアプリケーション構成の場合)
というわけで早速ビルド済み Docker image を ECR にアップロードしていきましょう。
まずは AWS Console 上で ECR にアクセスし、リポジトリを作成していきましょう。
リポジトリの名前は「isono-repository」にします。
他に特に設定する項目はないので、そのままリポジトリを作成しましょう。
リポジトリが作成できたら、一覧画面から作成したリポジトリにアクセスしましょう。
右上にいつものオレンジ色の「プッシュコマンドを表示」ボタンがあるのでこちらをクリックしてください。
そうすると 4 ステップ出てくると思うので順番に実行していきます。
この 4 ステップを完了すると、ECR にビルド済みイメージをアップロードすることできます。

手順 5:RDS の作成
AWS Console 上で Aurora and RDS にアクセスしてください。
早速 AWS 上にデータベースを作っていきましょう。
最初にエンジンのタイプを選択する場所があると思うのですが、こちらはご自身のアプリで使ってる DB と同じにしてください。
私の場合、今回は MySQL を使用しているので「Aurora (MySQL Compatible)」を選択します。
DB の設定では以下のようにします。
DB クラスター識別子は「database-isono」
マスターユーザーは「admin_isono」
パスワードに関しては、本来は Secrets Manager で管理するのが望ましいですが、今回はセルフで作るかつ AWS 様に自動でつくっていただきます。
インスタンスの設定についてですが、特に高性能なものは必要ないので
「db.t3.medium」にしておきます。もし必要であれば皆さんで変えていただいて構いません。
接続の項目に関しては自分の VPC を設定するのを忘れないでおきましょう。

追加設定のセクションで、「初期データベース名」を設定しましょう。
ここで設定した名前が、環境変数の MYSQL_DATABASE に対応します。
例:mydb や isono_db など、任意の名前を設定してください。
そしてここで 1 回目のセキュリティグループの登場です。

先ほど作成したセキュリティグループの中から、「isono-sg-private」選択しましょう。
RDS は DB なので private な環境に置きます。VPC の中のプライベートサブネットというとこですね。
なので private のためのセキュリティグループをここで適応します。
これで RDS の設定は以上です。作成しましょう。
パスワードは RDS 作成直後にしか確認できません。
もし見逃してしまった場合はもう一度パスワードを作り直す必要があります。
確認の仕方は以下参照
右上の「接続の詳細を表示」をクリックし、パスワードをメモしておいてください。

手順 6:Fargate でコンテナ稼働
AWS Fargate とは以下のように定義されています。
AWS Fargate は、サーバーレスで従量制料金のコンピューティングエンジンであり、サーバーを管理することなくアプリケーションの構築に集中することができます。
(Amazon Web Service より)
Fargate を使うと ECR にアップロードしたイメージを用いてアプリケーションを動作させることができます。
私の理解では、Fargate は「AWS バージョンの Docker」のようなものです。
Docker は Dockerfile があればコンテナを立ち上げ、アプリケーションを動かすことができます。
Fargate にも同様にサービスという概念やタスクという概念があります。
タスクは Docker でいうコンテナに近いですが、タスクは 1 個以上のコンテナを動かすことができる点が異なります。
文で書いていても理解には限界があると思うので実際に手を動かしていきましょう。
まずは Fargate を作成していきます。
と言いましたが、Fargate そのものを作成するというよりは、タスク定義、タスク、サービス、これらをまとめるクラスターというものを作ることを指しています。
それでは、やっていきましょう。
6-1:タスク定義の作成
Fargate を作っていく上で、これが 1 番大事かもしれません。
これは Docker でいう Dockerfile, docker-compose-yml に近いと思います。
ここがしっかりしていないと、サービスが起動しないので、アプリケーションが動かなくなります。
それではタスク定義の作成を行っていきます。
タスク定義は、AWS Console の Elastic Container Service (ECS) から作成することができます。
タスク名は「isono-task-definition」
オペレーティングシステムは、自分はデフォルトのものから Linux/ARM64 に変更してるのですが、
これは私のイメージがこのアーキテクチャだからです。
もし確認したければ、以下のコマンドをターミナルで実行してください。
docker inspect バックエンドアプリケーションのイメージ名 --format '{{.Os}} {{.Architecture}}'
これで使用しているアーキテクチャを確認できます。
次にそのまま進めていくとコンテナの設定画面に映ると思います。
ここは他と比べると設定する箇所が多いので少し注意しながらやってみてください。

まずコンテナ名はいつものように「isono-container」
イメージ URI は ECR にアップロードしたイメージを選択しましょう
コンテナポートは、自分のバックエンドアプリケーションがどのポートで動いているかで変わります。私の場合は 3000 で開放してるのでデフォルトの 80 から 3000 に変更しています。
環境変数は個人の環境に依存します。
ご自身のアプリケーションはどんな環境変数を使っているのかを確認した上で、
こちらに追加していくようにしてください。
-
DB_HOST:RDS のライターインスタンスのエンドポイント -
MYSQL_DATABASE:RDS のデータベース名 -
DB_PASSWORD:RDS のパスワード(RDS 作成時に保存したパスワード) -
DB_USER:RDS 作成時に設定したマスターユーザー -
PORT:バックエンドの開放ポート(私の場合は 3000) -
RUN_SEED:初期データを流すかどうかのフラグ -
DATABASE_URL:データベースに接続するためのURL。形式は"mysql://ユーザー名:パスワード@インスタンスへのエンドポイント:3306/データベース名"
環境変数を定義したら、タスク定義を作成しましょう。
タスク定義一覧に自分のタスクが作成されていて、ステータスがアクティブなら OK です!
6-2:ALB の作成
Fargate とは少し領域が異なりますが、サービスの作成に ALB が必要になるのでここで作成しましょう。
ALB は EC2 サービスの中から作成できます。
AWS Console で EC2 を選択し、左のメニューの中からロードバランサーを選択してください。
ロードバランサータイプは「Application Load Balancer」にします。
基本的な設定は以下です。
今回も名前は習慣的に「isono-alb」とします。

ネットワークマッピングは以下のように設定します。

VPC は言わずもがな自分の VPC ですね。
アベイラビリティーゾーンとサブネットは
1a と 1c、両方ともパブリックサブネットを選択するようにしてください。
セキュリティグループは作成した isono-sg-alb を適用します。

次はリスナーとルーティングに移りますが、
まだターゲットグループが作成できてないのでここで作成しましょう。
「ターゲットグループを作成」リンクを押してください。

そうすると以下のような画面に移りますので、以下のように設定します。
- ターゲットタイプ:IP アドレス
- ターゲットグループ名:isono-tg-alb
- プロトコル:HTTP
- ポート:3000(バックエンドアプリケーションのポート)
- VPC:自分の VPC(isono-vpc)
設定したら次に移りましょう。
「ターゲットを登録 - 推奨」ページに遷移すると思うのですが、こちらは特に設定しなくて大丈夫です。
ターゲットグループを作成したら、ロードバランサーの作成画面に戻ります。
リロードをしてもらうと、たった今作成したターゲットグループ(isono-tg-alb)が出現すると思うので、適用します。

あとはそのまま進めていただければロードバランサーの作成は完了です。
6-3:CloudFront と ALB の統合
ここでは、フロントエンドとバックエンドを繋ぐため、CloudFront と ALB を統合します。
作成した ALB と CloudFront が繋がるように設定を行います。
CloudFront のディストリビューションの設定画面にうつり、
オリジンタブを選択してください。
右上のオリジンを作成ボタンを押します。
そうするとオリジンを作成する画面に移るので、
オリジンの選択から自分の作成した ALB を選択しましょう。

プロトコルは HTTP:80 にします。
本来はセキュアな HTTPS:443 が望ましいですが、証明書の発行などが必要なため今回は割愛させていただきます。
本格的な実装で HTTPS 通信のみ許可するようにしましょう。
次は特定の HTTP リクエストが呼ばれた時に、ALB と紐づけられるようビヘイビアの設定をします。
CloudFront のディストリビューションの設定画面からビヘイビアタブを選択してください。

私のアプリケーションではバックエンドへのリクエストはすべて"/api"から始まるようにしているので、
パスパターンに"/api/*"を設定します。
オリジンには先ほど作成した ALB のオリジンを設定しましょう。
ビューワープロトコルポリシーは「HTTP and HTTPS」にしましょう。
先ほどのオリジンの作成で、プロトコルを HTTP:80 にしたので「Redirect HTTP to HTTPS」にしてしまうと、
HTTPS に変換され上手く ALB との連携ができなくなってしまいます。
以上の全ての設定が完了したら、バックエンドアプリケーションへのリクエストを ALB を通して行うことができます。
イメージとしては、
フロントエンドでなんらかしらのボタンをクリックする →"api/get"などのリクエストが呼ばれる →ALB が検知 → バックエンド側が対応する処理を行う
といった具合でしょうか。
注意点として、私の場合は/api から始まるリクエストに統一してるのでこのような設定になりますが、ご自身の設計によってはパスパターンなども変わってきますのでご注意ください。
6-4:クラスター&サービスの作成
クラスターとサービスを作成します。
まず ECS の画面左メニューからクラスターを選択してください。
クラスター作成画面から以下で作成します。

クラスターはこれだけできます。
次に、クラスターが作成できたらサービスを作成しましょう。
作成したクラスターの画面にアクセスし、画面下部にある「サービスの作成」ボタンを押してください。

タスク定義ファミリーには、自分で作成したタスク定義を適用しましょう。
私の場合は「isono-task-definition」です。
サービス名はデフォルトのを使いましょう。
VPC は自分のを選んでください(私で言えば isono-vpc)
サブネットは、このサービスがどこに属するかということなのでパブリックサブネットを選択しましょう。
それに伴い、セキュリティグループもパブリック用のセキュリティグループを適用します(isono-sg-public)
次はロードバランシングの設定です。
コンテナのポートはタスク定義により設定したポートになります、自分の場合だと 3000
ロードバランサーは既存のロードバランサーを選択し、自分で作成したものを選択します(isono-alb)
リスナーもターゲットグループも既存のものにしましょう

もし ALB に紐づいたターゲットグループが表示されないときはリロードしてみてください。
これでサービスの作成は完了になります!
サービスの作成には数分時間がかかるのでドキドキしながら待ちましょう。
手順 7:動作確認
それではラスト、実際にアプリケーションが動作するか見ていきましょう。
まずは CloudFront のディストリビューション画面から、ディストリビューションのドメイン名をコピーしてアクセスしましょう。開くのは Google でもなんでも大丈夫です。
私の場合は以下の画面に移ります。

データベースには予め世界のメリークリスマスを初期データとして入れてあり、
この「世界のメリークリスマス」を押すとランダムな言語のメリークリスマスが返ってくるようにしています。
それでは、クリックしてみましょう。
無事リクエストが返ってきました!
今回はフランス語の挨拶が表示されましたね!
無事ランダムな言語の挨拶が返ってきたことでバックエンドとの疎通が確認できました!
まとめ
今回は、ローカルで動作済みのアプリケーションを AWS にアップロードして実際に動作する方法を書いていきました。
今回のやり方は、ソースコードによって設定の仕方が微妙に違ったり、環境変数の必要な数なども変わってくるとは思いますが、大まかな手順としてはこの記事を辿っていくことでアプリケーションを AWS でも動作させることができるのではないかと思います。
私自身、人生で記事を書くのが初めてなため至らない点や読みづらい記事になっていたかもしれませんが、どうか温かい目で見守っていただければと思います。
ソースコードの解説含め、もっと厳密な環境構築(HTTPS 通信にしたり)についてはいつかの記事であらためて書こうかなと思っています。
それでは、長い間ありがとうございました。












