「Elastic Beanstalkを使って中規模くらいまで耐えられるインフラ環境を構築したいんだけどゼロからの解説している記事ないかな?」
こんにちは、タカフです。
本記事では、上記のような悩みを解決するべくAWS Elastic Beanstalkを使って小規模から中規模くらいまで耐えられるインフラ環境の構築方法を解説していきます。
本記事の通りに環境構築すれば、スモールスタート時は最小コストで作ることが出来て、
予期せぬアクセスが来ても自動的にサーバー台数を増やせるスケールアウトを可能とし、
定常的にユーザーが増えてきたら強めのサーバースペックに簡単にスケールアップ出来る環境が作れます。
月1000万PVのメディアサイトも、強力なWordPressのサーバーもこれで骨組みは構築出来ます。
本記事で使う言語は主にLAMP(Linux/Apache/MySQL/PHP)です。
「弊社ではPHPアプリを得意としているのでなるべくこの技術は活かしつつAWSで盤石なインフラ構築したい」といった会社さんには特にお役に立てるかと思います。
Dockerもあえて使っていません。Elastic Beanstalkの機能が優れているのでそれに乗っかった方が楽だからです。既存の枯れた技術を使いこなすのも大切な事です。
読み終えた頃にはPHPerだったあなたもフルスタックエンジニアへの第一歩を踏み出せると思います。むしろマスターしたら結構重宝されるエンジニアになれる事でしょう。
それでは、はじめていきましょう。
鉄板インフラ構築 その1 〜概要編〜
本記事ではPHPを使ったWebアプリケーション「MyApp」というアプリを作り上げる想定で進めていきます。
「MyApp」では、オートスケーリングするEC2から、DBであるRDS(Aurora)と共有ストレージのEFSに接続しアプリを提供をし、前段にCloudFrontを配置してRoute53からドメインを向けるというWebアプリの鉄板構成となっています。
大抵のWebアプリはこの構成で構築することが出来ることでしょう。
本ページではそのAWS構成について説明いたします。
構築インフラ構成図
本記事では小規模時のインフラ構成で構築します。
そのインフラ構成図を下記に示します。

この構成は小規模案件で特にミニマムスタートの時です。EC2は最低2台配置して負荷が高まった時だけオートスケーリングでEC2の台数が増えます。
この構成で構築して、Webアプリもこのインフラを意識して作っていれば(ステートレス)、後々インフラ増強する時に比較的簡単にスケールアップすることが出来ます。
これはサービスがうまくいくかどうかわからない時にランニングコストを下げるのに非常に有用です。
そして中規模構成になってくると以下のように変化していきます。

構成は変えずにEC2のスペック・常時台数やAuroraのスペック・レプリカ台数を増やしていくのです。
このように初期段階でスケールアップしやすいように構築しておけば、規模が上がった時でも対応しやすくなるわけです。
鉄板インフラ構築 その2 〜下準備編〜
ここでは、Elastic BeanstalkでWebアプリ構築する前の下準備をしていきます。
主に、VPC・RDS・EFSなどを準備していきます。
ネットワーク(VPC)の構築
Elastic Beanstalkで環境構築する場合、そのWebアプリ専用のVPCを作ってその中で構築していった方が何かと良いです。
なので、ここではVPCの作成を解説致します。
VPCの作成
VPCの設定画面において[VPCの作成]を押下します。

MyAppのためのVPCなので、名前タグに vpc-myapp とします。
IPv4の利用可能なIPアドレスは 172.32.0.0/16 とします。つまりこのIPアドレスの範囲のプライベートネットワークとなります。
そして[作成]ボタンを押下します。

VPCが作成されたら、「DNS解決」と「DNSホスト名」は有効になるようにしておきましょう。
こちらは後ほど使用するEFSの接続時に必要です。
「DNS解決」はデフォルトで有効になっているようですが、「DNSホスト名」はデフォルト無効だったのでこれを有効にします。
vpc-myappのアクションで[DNSホスト名の編集]を押下します。

有効化にチェックを入れて保存します。

これでVPC自体は完了です。
サブネットの作成
専用のVPCが出来たので、ここにサブネットを東京リージョンのアベイラビリティゾーン(以下AZ)ごとに作成していきます。
サブネットの設定画面において[サブネットの作成]ボタンを押下します。

MyAppのVPCにおいてAZがap-northeast-1aのところに作るサブネットなので、subnet-myapp-aとします。
VPCは先ほど作成したvpc-myappをプルダウンで選択するとそのVPC IDがセットされます。
アベイラビリティゾーン(AZ)はap-northeast-1aを選択します。
このサブネットで利用可能なIPアドレスの範囲は、AZ-AなのでAを16進数と見立てて文字って172.32.10.0/24とします。
そして[作成]ボタンを押下します。

これをAZ-CとAZ-Dも同様に作っていきます。3つ全部作ると以下のように作成されます。

キレイに作れましたね。
インターネットゲートウェイの作成
この作成したVPCに対して、外部とのネットワークが出来るインターネットゲートウェイを作っていきます。
インターネットゲートウェイの設定画面で、[インターネットゲートウェイの作成]を押下します。

MyAppのインターネットゲートウェイなのでigw-myappという名前タグにして[作成]を押下します。

インターネットゲートウェイを作成しただけではまだVPCにアタッチされていないので(detached状態)、選択して[アクション]から[VPCにアタッチ]を押下します。

次の画面で先ほど作成したvpc-myappを選択して[アタッチ]を押下します。

これでElastic Beanstalkを構築する時にこのVPCが出現します。
ルートテーブルの編集
先ほど作成VPCにルートテーブルというのがあるので、VPCから外にいけるようにルートテーブルを編集します。
ルートテーブルの設定画面において先ほどのVPCを選択して、[ルートの編集]を押下します。

送信先に外部にルーティング出来るようの0.0.0.0/0をセットします。
ターゲットのプルダウンでInternet Gatewayを選択すると先ほど作成したインターネットゲートウェイが出てくるのでそれを選択します。
そして[ルートの保存]を押下します。

データベース(Aurora)の構築
VPCが出来たら、そこにWebアプリケーションから使うデータベースを構築することが出来ます。
データベースにはMySQL互換のAuroraを使います。
ちょっと前まではAuroraは高価なサービスだったんですが、価格も落ち着いてきて今ならわざわざRDSのMySQLを使う必要はないかなと思っています。
※厳密に言うとRDS内のAuroraというサービスなのですが、対比をわかりやすくするためにAuroraかRDSかという表現をしております。
パラメータグループの作成
Auroraのインスタンスを作った後ほぼ必ずやる日本語対応のutf8mb4パラメータグループの作成です。もうやるのはわかっているので先にパラメータグループを作ります。
インスタンス作成・データベース作成後に適用するとデフォルト設定を変えたりする必要があるので先にパラメータグループを作った方がいいのです。
RDSのパラメータグループの設定画面で[パラメータグループの作成]を押下します。

パラメータグループファミリーは、aurora-mysql5.7を選びます。AuroraでMySQL互換と言ったら2020年4月現在これしかありません。
タイプは、DB Cluster Parameter Groupを選択します。DB Parameter Groupではないのでご注意ください。
グループ名は、任意の名称を入力します。前述の通りほっとんどのAuroraのインスタンスを作ったらこのパラメータグループを適用するので、僕は汎用的な名前としてaurora-mysql57-utf8mb4としました。(ピリオド使えなかったです…)
説明も必須のようで、適当に「utf8mb4 and asia/tokyo timezone」としておきました。

作成したパラメータグループ「aurora-mysql57-utf8mb4」の編集画面に遷移します。
まず変更すべきなのは以下のパラメータです。
character_set_client = utf8mb4
character_set_connection = utf8mb4
character_set_database = utf8mb4
character_set_results = utf8mb4
character_set_server = utf8mb4
time_zone = Asia/Tokyo
フィルター入力のところでcharacter_setと入力すると、探しやすくなります。そして[パラメータの編集]を押下します。

上記のパラメータをutf8mb4に選択していきます。(character_set_filesystemは変更しなくて大丈夫です。)

次にフィルター入力でtime_zoneと入力して、time_zoneのパラメータをAsia/Tokyoを選択したら、[変更の保存]を押下します。

一応変更のプレビューで見ておくと以下のようになります。

Auroraの作成
日本語・日本時間対応のパラメータグループが出来たらAuroraのインスタンスを作っていきます。
RDSのデータベース設定画面で[データベースの作成]を押下します。

データベースの作成画面では以下のように設定します。
| 項目 | 値 | 説明 |
|---|---|---|
| エンジンのタイプ | Amazon Aurora | 当然ですね |
| バージョン | Aurora(MySQL5.7)2.07.2 | MySQL5.7で最新バージョンでOKです。 MySQL5.6はサーバーレスのようなので要注意です。 |
| テンプレート | 本番稼働用 | 今回は本番用として想定しています。 |
| DBクラスター識別子 | aurora-cluster-myapp | 任意の名称です。 |
| マスターユーザー名 | admin | 任意の名称です。adminはデフォルト値なので変更してください。 パスワードは自動生成でもOKだと思っています。 AWSオススメの小難しい文字列になるでしょう。 |
| DBインスタンスサイズ | db.t3.small | 今回は本番用としながらもミニマムスタートなので小さめです。 こちらも案件に合わせて選びます。 |
| 可用性と耐久性 | 別のAZでAuroraレプリカ… | 本番用想定なのでマルチAZです。 小規模案件ならレプリカ無しでもいいと思っています。 レプリカ無しでもフェイルオーバーでも10分以内に復帰してくれるらしいので。 |
| VPC | vpc-myapp | ここで先ほど作成したVPCを選択します。 |
| VPCセキュリティグループ | 既存の選択 | 次に選択したVPCのdefaultを選択します。 |
| 既存のセキュリティグループ名 | default | VPC内のEC2インスタンスからは全て接続許可とします。 パブリック公開していないのでこれで十分かと思います。 |
| DBインスタンス識別子 | aurora-instance-myapp | 任意の名称です。Auroraのインスタンス名となります。 |
| 最初のデータベース名 | db_myapp | PHPから接続するデータベース名です。 案件に合わせて入力しましょう。 |
| DBクラスターのパラメータグループ | aurora-mysql57-utf8mb4 | 来ました!先ほど作成したパラメータグループです。 これで日本語化・日本時間対応となります。 |
これが基本設定となることでしょう。
後のログのエクスポート設定等は案件に応じて選択してください。基本的には全選択です。

最後に[データベースの作成]を押下すると作り始められます。
そしてすぐに下記画面が表示され[認証情報の詳細を表示]を押下すると、自動生成したDBパスワードが現れますのでそれをコピーしておきましょう。

これでAmazon Aurora(MySQL互換)を使ったデータベースの構築は完了です。
共有ストレージ(EFS)の構築
本記事で構築するWebサーバー(EC2)はステートレスとなります。
ステートレスとは、Webサーバーの方で状態を持たないという意味で、Webサーバーをステートレス構成にしておくと後からWebサーバーを増やしたり減らしたりすることが出来るのでWebサーバー台数を自由にスケーリング出来るメリットをもたらします。
しかし、案件によっては運用において後から画像や動画などのファイルをアップロードすることもあるでしょう。WordPressのuploadsディレクトリがそれにあたりますね。
そういったファイルはステートレスなWebサーバーには保存出来ないので、ステートレス構成でも複数のWebサーバーから一つのディレクトリのように読み書き出来る共有ストレージが必要になってくるわけです。
それがEFSの役目となります。
ここでは先ほど作成したVPC内からのみ読み書きできるEFSを構築していきます。
EFSの作成
EFSのトップ画面に遷移して[ファイルシステムの作成]を押下します。

次に先ほど作成VPCを選択します。
それによりサブネットも自動でa, c, dのやつが選択されることでしょう。3つともチェックを入れることで3つのサブネットからのアクセスを許可します。
セキュリティグループはそのままでOKです。

「ファイルシステムの設定」では案件に応じて設定します。
より高速に読み書きするには、価格は上がるけれどプロビジョニング済みや最大I/Oを選択します。
ここではデフォルト設定で進めます。

「クライアントアクセスを設定」も案件に応じて設定します。
ここもデフォルト設定で進めます。

最後に[ファイルシステムの作成]を押下します。

数分すると利用可能になります。
各EC2からは下記のDNS名をマウントします。後ほど使うのでコピーしておきましょう。
そして同時に設定したセキュリティグループ(VPC内のみアクセス可)をもってアクセスしにいきます。

※DNS名等のリソース名をこちら表記していますが、これらのリソースは記事の為に一時的に作っていて後ほど削除します。
ドメイン(Route53)の購入
本記事では小規模案件の本番環境を想定しているので、ドメインも実際に(自腹で)購入していきます。
今回は新規ドメインとして「kahoo-myapp.net」を購入していきます。
Route53のトップページにて[ドメインの登録]を押下します。

次の画面で「kahoo-myapp」を入力して、ドロップダウンで.netを選択してチェックを押下します。
ステータスが利用可能なら誰にも登録されていないドメインなので購入することが出来ます。
[カートに入れる]を押下して[続行]を押下します。

僕の会社名や住所は特に非公開情報でもないので晒します。
電話番号は日本の場合+81を1番目に書いて、次に1文字目の0を抜いた電話番号を2番目に入力しましょう。
1点注意点として、ドメイン購入はこのように連絡先を記載する必要があるのですが、個人情報なので晒したくないという時は最後のプライバシー保護の箇所を有効化にしておくとで隠すことが出来ます。
全てOKなら[続行]を押下します。

次の画面に遷移すると最後にEメールアドレスの実在確認としてメールが送信されている記載がありその確認を待機しています。

メーラーを開くとURL付きのメールが来ているを事を確認出来ます。

クリックすると検証完了です。

先ほどのページに戻って[ステータスの更新]を押下すると検証済みに変わります。
ドメインを自動的に更新にしておくのと規約を読んでチェックを入れて、最後に[注文を完了]を押下します。

ドメイン購入したらすぐに使えるわけではないので、最大3日かかることもあるそうなのでドメインは決まったら前もって購入しておくことをお勧めします。
以下の通り購入直後では保留中になっています。

と、言いつつその後10分後くらいにメールが来て無事登録完了となりました。

SSL証明書(Certificate Manager)の準備
イマドキのWebアプリケーションはSSL(https)化は必須ですよね。
本記事では本番環境相当の内容で構築していくので、SSL対応もしていきます。
AWSではドメインベースのSSLは無料で取得出来るAmazon Certificate Manager(ACM)なるものがあるのでそちらで進めていきます。
この章より前にドメイン購入があったのはその為でした。
1点先に重要な事を書いておきます。
本記事の構成では、CloudFrontとALBの2つに対して証明書が必要なのですがそれぞれ取得すべきリージョンが異なります。
CloudFrontで使われるSSL証明書のリージョンはバージニア北部リージョンで作成し、
ALBで使われるSSL証明書のリージョンは東京リージョンで作成します。(厳密にはそのALBがあるリージョン)
ワイルドカードSSL証明書の作成(東京リージョン)
まずは東京リージョンから作っていきましょう。
ACMのトップ画面で[今すぐ始める]を押下します。

「パブリック証明書のリクエスト」にチェックが入ったまま[証明書のリクエスト]ボタンを押下します。

ドメイン名に先ほどに購入した、kahoo-myapp.netのワイルドカード版である*.kahoo-myapp.netを入力して[次へ]を押下します。

次に「DNSの検証」にチェックのまま[次へ]を押下します。
これはそのドメインを所有しているかどうかの検証です。
昔はEメールの検証しか出来なくて面倒でしたが、今はDNSレコードで所有確認出来るようになりました。

タグは特に使わなければ無記入でOKです。

次の確認画面で[確定とリクエスト]を押下します。

次の検証画面で表示されたCNAMEレコードをDNSに登録するのですが、今回はRoute53でドメイン所有しているので[Route53でのレコードの作成]ボタンを押下で登録してくれます。
同じAWS内で作業するメリットですね。

数分すると「発行済み」状態となります。これでALBで使えるようになります。

ワイルドカードSSL証明書の作成(バージニア北部リージョン)
次にCloudFrontで使うSSL証明書を作成していきます。
右上の東京リージョンを押下して「米国東部(バージニア北部)」を選択します。

そして、この後の作業は東京リージョンでSSL証明書を作成した方法と全く一緒です。
一つ前の章と全く同じ事を繰り返し作業しましょう。
秘密鍵の作成
次の章ではいよいよElastic Beanstalkの設定をしていきますが、そこでEC2にSSHアクセスの為の秘密鍵の設定があります。
その時にすぐに指定が出来るように秘密鍵を作っておきます。
EC2の画面に遷移して、サイドメニュー[キーペア]の[キーペアを作成]ボタンを押下します。

名前に、MyApp用の秘密鍵ということで myapp-private-key とでも入力して[キーペアの作成]ボタンを押下します。

ボタンを押下すると自動で myapp-private-key.pem ファイルがダウンロードされます。
これが秘密鍵となるので厳重に扱いましょう。
鉄板インフラ構築 その3 〜Elastic Beanstalk編〜
※前章までの作業で「バージニア北部」リージョンになっている場合は「東京」リージョンに切り替えましょう。
下準備が長かったですがやっと本題に入れますね(笑)
さぁアプリケーション部分であるElastic Beanstalkを構築してきます。
Elastic Beanstalkでは「アプリケーション」という名の大枠の中に、「環境」という名の枠を必要に応じて作っていきます。
この「環境」には、Webアプリでよくある 本番環境、開発環境、ステージング環境等を作っていきます。
Webアプリではよく環境単位で使い分けることがほとんどですので、Elastic Beanstalkのこの分け方はとてもわかりやすいですよね。
アプリケーションの作成
まずは大枠のアプリケーションを作成していきます。
Elastic Beanstalkの画面に遷移して「Create Application」を押下します。
※この画面はしょっちゅう変わっている気がします。基本的にはアプリを作成するボタンを押せばOKです

Elastic Beanstalkは、初回のアプリケーション作成だけ環境作成も一緒になっているおせっかい設定なのですがこれは分けて設定した方がよいです。おいおい説明していきます。
次の画面で、
アプリケーション名は任意の名称なので今回のアプリ名である「MyApp」を入力します。
アプリケーションタグは適当にどうぞ。
プラットフォーム枠のところは一旦PHPだけ選択します。それ以外も適当に選択します。
これは後ほどの環境作成のところでセットする項目ですがここをセットしないと先に進めないのでセットします。
最後に[より多くのオプションの設定]を押下します。
アプリケーションの作成を押下してしまうとデフォルト設定の環境がすぐに作られるてしまうので要注意です。

そしたら次の画面の時点でアプリケーションという枠は出来たので、一旦サイドメニューの[アプリケーション]を押下しましょう。
この画面のまま進めると環境名が「Myapp-env」とデフォルト設定されている為です。

一旦アプリケーションという枠組みが出来てしまえば、あとはその中に環境という枠をいくらでも作れます。
環境を作ることに慣れた方がいいので次の章で環境の新規作成画面から始めます。
環境の設定
アプリケーション一覧画面から先ほど作成した「MyApp」を押下します。

次に[新しい環境の作成]ボタンを押下します。

「ウェブサーバー環境」選択のまま選択ボタンを押下します。

環境名に、今回作るのは本番環境なので「Myapp-master」とします。環境一覧から見て本番環境であることをわかりやすいようにします。
ドメインも、myapp-masterとします。これは結局製品としてこのドメインを使うわけではないですがわかりやすければ何でも良いです。
プラットフォームでは、LAMPなのでPHPを選択します。
プラットフォームのブランチで、PHPのバージョンを選択します。案件次第ですが基本は最新がベターです。
プラットフォームのバージョンは、AmazonLinuxのバージョンですね。Recommendedが良いでしょう。
アプリケーションコードは、一旦ここではサンプルアプリケーションにしておきます。
(最終的には本記事5ページ目でAWS Pipelineからデプロイする仕組みを構築します。)
最後に[より多くのオプションの設定]を押下します。
([環境の作成]を押下するとデフォルト設定ですぐに構築処理が走り出すので押さないでください!)

次の画面で詳細設定を設定していきます。
カスタム設定を選択しましょう。

[ネットワーク]の設定
まず始めにネットワークの設定から行います。ここでの設定が他の設定にも反映される為です。
VPCで先ほど作成したvpc-myappを選択します。
これによりインスタンス設定画面でVPCに従ったセキュリティグループが反映されます。
ロードバランサーの設定では、
可視性をパブリックにすることでインターネットからのアクセスを可能とします。
サブネットを全てONにしてこの3つにまんべんなくEC2を配置するようにします。
インスタンスの設定では、
パブリックIPアドレスをONにします。これにより各WebサーバーへのSSHアクセスが可能となります。
僕はいざという時にSSHアクセス出来た方がなんだかんだ助かるのでONにします。
昔ながらのSSHでサーバーログインして一時的にソース編集したりPHPファイルをアップするにはこれが必要です。

[ソフトウェア]の設定
ソフトウェアの設定です。主にPHPのソフトウェアとしての設定周りとなります。
| 項目 | 値 | 説明 |
|---|---|---|
| ドキュメントのルート | いわゆるDocumentRootです。 一旦サンプルコードで作るので空にします。 あとで public に変更します。 |
|
| ログのローテーション | ON | Elastic Beanstalkの更新ログです。S3の保存料金などたかがしれてるのでONにします。 |
| ログのストリーミング | ON | これは重要です。ここをONにするだけで各EC2にCloudWatchLogsAgentをインストールしてくれて、アクセスログ・エラーログをCloudWatch Logsに送ってくれます! つまりこれにより各Webサーバーのログをひとまとめに見ることが出来るのです! |
| 環境プロパティ | ENVIRONMENT:master | 環境変数です。これがミソです。これをアプリケーションコードから見ることで環境判別出来ます。 |

[インスタンス]の設定
インスタンスの設定です。EC2の設定ですね。
ボリュームタイプはコンテナのデフォルトで一旦は十分かと思います。
インスタンスセキュリティグループでdefaultを選択します。これにより先ほどセットアップしたAuroraとEFSの接続が可能となります。
(何故か2つ表示されている…バグ?)

[容量]の設定
容量ではオートスケーリングの主に設定となります。
本番環境なので、もちろん負荷分散にします。
インスタンス数では案件によって様々ですが、本番環境なら最低でも最小は2つにしておきましょう。
最小1つも設定出来ますが負荷分散の意味ないですよね(笑)1台死んだらそれで終了ですし。
インスタンスタイプは案件に応じて決めます。画像操作するような案件なら強めにしたりしますが、小規模サイトならt3.smallもありです。
アプリの工夫やCloudFrontのキャッシュでWebサーバーの負担はいくらか下げる事が出来ます。
スケリーングトリガーはまさしくオートスケーリングの設定です。
どういう時にEC2を増やしてどういう時にEC2を減らすかの設定となります。
ここは正直運用始まってから見極めていくところなのでまさに案件次第なのですが、
僕は一番最初はCPU使用率が平均20%を超えたら増やすというようにしています。
でも甘めのしきい値にして、敏感にEC2が増える(スケールする)ような設定の方がいいのかなとも最近思ったりします。

[ロードバランサー]の設定
ロードバランサーの主な設定はこちらです。
選択するロードバランサーはデフォルトのApplication Load BarancerでOKです。
その次の設定は順番に説明していきます。

①Application Load Balancer
こちらの項目では、ALBの受付ポートを設定します。デフォルトではhttpの80ポートが有効となっていてこれはそのままでOKです。
[リスナーの追加]ボタンを押下して、httpsの443ポートを追加します。
ポートは443を入力して、プロトコルにHTTPSを選択します。
SSL証明書は先ほど作成した東京リージョンのSSL証明書が出てくるはずなのでそれを選択します。
SSLポリシーは、AWSが互換性の為に推奨している ELBSecurityPolicy-2016-08 を選択します。

因みに何故ここで443ポートも受け付けるようにするかの理由を説明します。
本記事の構成では最終的に前段にCloudFrontからALBに向けるのですが、CloudFrontとALBの間は外部ネットワークになるので、通信の暗号化していないhttp(80ポート)によるアクセスだと通信の傍受に晒される危険が生じます。
なので、通信の暗号化をしているhttps(443ポート)のアクセスを追加するのです。
(まぁ、CloudFrontとALB間で通信の傍受ってどうやるのか全くわからないですが。。)
ですが、案件によっては全て暗号化しなくても良いケースもあるかと思います。
その場合はここは443は追加しなくてもOKです。
以下のサイトが参考になります。
https://lab.taf-jp.com/aws-https%E5%8C%96%E3%81%99%E3%82%8B%E9%9A%9B%E3%81%AE%E6%A7%8B%E6%88%90/
②プロセス
こちらはALBからEC2へのアクセスの設定となります。
defaultにチェックを入れて[アクション]の[編集]を押下します。
ヘルスチェックではEC2の健康状態を判断する値を設定します。
HTTPコードが200であれば正常とします。(何故かデフォルト空白なので200とします)
パスは15秒に1回リクエストするパスの事です。
一旦ドキュメントルートとしていますが、Webアプリによっては特定のヘルスチェックURLを設けて(例えばそのURLリクエストでDB接続なども確認する)、それを指定するのもありです。

セッションのスティッキーポリシーでは、いちブラウザからアクセスがあった時にALBが常に同じEC2インスタンスにリクエストしてくれる機能のON/OFFになります。
僕はこれは一般的なWebアプリではデフォルトでONでいいと思っています。

③ルール
ポートに基づいてEC2へのリクエストするパスを変更することが出来ます。
httpsが標準となった今、大抵は同じドキュメントルートを見せると思うので一般的にはデフォルト設定でOKです。
④ログ
ここではALBを通った時のアクセスログを保存の設定となります。
本記事の構成では前段CloudFrontを配置するので、ここは有効化したとしてもCloudFrontからALBへのアクセスログとなります。
CloudFront側でもアクセスログを取得するので、ここでは無効でも良いと思います。
有効にしたい場合はS3バケットの設定がいくつか必要なので、AWS公式ドキュメントを参考に設定した上で、有効化して下さい。
[ローリング更新とデプロイ]の設定
こちらは主にデプロイ時の設定となります。
デプロイとは、簡単に言うと最新コードをインスタンスにアップロードしていって、最新コードでWebアプリが動くようにする処理の事を言います。
こちらデフォルトの設定では「All at onece(1回にすべて)」となっていて、デプロイ処理を実行すると全てのインスタンスがいっぺんに最新コードが適用される流れとなっています。
初回の設定はこれでも十分です。案件に応じて見直していけば良い項目です。
[セキュリティ]の設定
こちらは主に各リソースからのアクセス権などの設定となります。
サービスロールもIAMインスタンスプロフィールもデフォルトでOKです。
これによりElastic Beanstalkが各AWSリソースにアクセスできるロールやIAMプロフィールを良きように作ってくれます。
EC2キーペアを下準備で作成したキーペアのmyapp-private-keyを選択します。
最後に[保存]を押下します。

[モニタリング]の設定
こちらはデフォルトの設定でよいでしょう。

[管理された更新]の設定
こちらもデフォルトの設定でよいでしょう。
管理された更新を有効にすると、自動でPHPバージョンとか変わりそうなので、安全を期して有効化しなくていいと思います。

[通知]の設定
こちらは、今作成中の環境でElastic Beanstalkに関するイベントがメールで受け取れるようになります。
急な負荷が来てEC2が増えたり減ったりした時のイベントを受け取れると便利です。
案件に携わっている人が設定されたメーリングリストなど設定しておくといいと思います。

保存して環境作成後に確認メールが来るので、メール文中のURLをクリックしてOKとする必要があります。
[データベース]の設定
こちらは、開発およびテスト目的のRDSとなります。
ここで構築すると環境を破棄した時に一緒にRDSインスタンスも破棄してくれます。
本記事では先ほどAuroraを構築しましたし、実際開発環境・テスト環境においても別立てで良いかと思います。
[タグ]の設定
お好みでどうぞ。
環境の作成
上記までで必要な環境の設定は全て完了したので、最後に[環境の作成]ボタンを押下します。

すぐに先ほど設定した通知のメールアドレスに Subscription確認メールが届くので「Confirm Subscription」を押下します。

色々と作ってくれています。大体3分くらいで作成完了します。

環境が正しく作成されて正常に動作しているとヘルスの箇所が緑色となります。

環境毎にElastic BeanstalkによるURLも振られます。
押下すると「Congratulation!」と共に環境が出来上がったページが表示されます。

鉄板インフラ構築 その4 〜つなぎ込み編〜
前章まででWebサーバーとDBサーバーの構築は完了しました。
ここでは、実際に使われるドメインを割り当てたりして、各サーバー間のつなぎ込みをしていきたいと思います。
オリジンサーバーのドメイン(Route 53)の設定
まずは、後ほど設定するCloudFrontからオリジンサーバーに向ける為に、先ほど作成したElastic BeanstalkによるWebサーバーにドメインを振っていきます。
最終的な本番のフロントドメインを www.kahoo-myapp.net にする予定ですので、それのオリジンサーバーのドメインということで、owww.kahoo-myapp.net と割り当てることとします。
Route53の設定画面にて[ホストゾーン]にて、kahoo-myapp.netをクリックします。

次の画面で[レコードセットの作成]を押下し、
右側のエリアで、owwwと入力し、タイプはAレコードをセットします。
Aレコードを選ぶとAWS内のリソースならエイリアスで選択可能です。
先ほど作成したElastic Beanstalkによって割り振られた項目を選択します。
最後に[作成]を押下します。

ドメイン設定が反映されると、そのドメインでアクセスが可能となります。
先ほど、Elastic Beanstalkの設定でACMによるSSLワイルドカード証明書を設定しておいたのでhttpsアクセスも可能です。

キャッシュサーバー(CloudFront)の構築
SSLの効くオリジンサーバーが用意出来たら、キャッシュサーバーであるCloudFrontからオリジンサーバーに向けることが出来ます。
CloudFrontの設定ポリシーは超重要です。
CloudFrontをALBより前に配置して、適切なキャッシュ設定をすれば大抵のアクセスはさばける盤石なインフラを作ることが出来ますが、設定を間違えてしまうと誰かの個人ページをキャッシュして他の人が見られてしまうという事故も起きてしまいます。
基本的な設定方針としては以下の2通りになるかと思います。
①会員サイト・ECサイト系の常に動的ページが必要なサイトなら、デフォルト設定は全通しにして、js/cssや画像/動画などの静的リソースを特定URLにおいてキャッシュ設定を追加する。
②ブログ・メディアサイト系の読み物がメインのサイトなら、デフォルト設定を全キャッシュ出来るようにして、管理画面などのURLを全通しのキャッシュ設定を追加する。
本記事ではキャッシュ効果は少ないけれど安全である①で設定を進めていきます。
CloudFrontの設定画面で[Create Distribution]を押下します。

Webの方で[Get Started]を押下します。

次にDistributionの設定です。
ここでは以下のように設定します。
| 項目 | 値 | 備考 |
|---|---|---|
| Origin Domain Name | owww.kahoo-myapp.net | オリジンサーバーへの向き先です。 先ほどRoute53で設定したALBへのドメインです。 |
| Origin Protocol Policy | HTTPS Only | ALBにはhttps接続のみとします。 |
| Viewer Protocol Plicy | Redirect HTTP to HTTPS | CloudFrontへのhttpアクセスは強制的にhttpsにします |
| Allowed HTTP Methods | GET,HEAD,OPTIONS,PUT,POST,PATCH,DELETE | デフォルト設定は全通しとしたいので全て許可します |
| Cache Based on Selected Request Headers | ALL | 全通しの為こちらもALLとします。 ALLを選択すると全部キャッシュ0になる警告が出ますがOKです。 |
| Minimum TTL,Maximum TTL,Default TTL | 0 | 上記でALLを選択するとグレーアウトするので先に0を入力しておきましょう。一応念のためです。 |
| Forward Cookies | ALL | cookieです。全通しなのでALLです。 |
| Query String Forwarding and Caching | Forward all, cache based on all | GETパラメータです。全通しなのでALLです。 |
| Alternate Domain Names(CNAMEs) | www.kahoo-myapp.net | どのドメインからのアクセスを許可するかです。 本番フロントドメインを設定します。 |
| SSL Certificate | Custom SSL Certificate *.kahoo-myapp.net | ACMでワイルドドメインのSSL証明書を作成済みなのでここで選択出来ます。 |
| Logging | Off | アクセスログですが、本番はOnにしてS3にログをためるべきです。 |

最後に[Create Distribution]を押下してDistributionの作成を開始します。
このように、デフォルト設定は全通しにしておいて、案件の内容に応じてさらにパス単位でBehaviorを追加設定をします。
その時キャッシュ時間であるTTLの設定は、以下のように設定すると良いでしょう。
| 項目 | 値 |
|---|---|
| Minimum TTL | 0 |
| Maximum TTL | 31536000 |
| Default TTL | 0 |
CloudFront側では0秒から365日分のキャッシュを持てるようにしておいて、オリジンサーバー側のhtaccessかPHPでキャッシュ時間を返却するのです。
これによりキャッシュコントロールが制御しやすくなります。
CloudFrontでTTLを設定しているとその反映まで時間がかかるので、Webアプリ側である程度自由にカスタム設定出来る方が何かと使い勝手が良いです。
Distribution一覧でStatusが In ProgressからDeployed になれば作成完了です。

キャッシュサーバーのドメイン(Route 53)の設定
CloudFrontの作成が出来たらいよいよ本番ドメインを向けることが出来ます。
先ほどと同様にRoute53の設定画面にて[レコードセットの作成]を押下し、
右側のエリアで、wwwと入力し、タイプはAレコードをセットします。
エイリアスで先ほど設定したCloudFrontディストリビューションが出てくるのでそれを選択します。
最後に[作成]を押下します。

Route53はわりとすぐに反映されます。
本番ドメインでアクセスしてみるときちんとhttpsで表示されることがわかります。

セキュリティ(WAF)の構築
上記までで一通りつなぎ込みは完了して本番ドメインによるアクセスは出来ましたが、これだけはやっておいた方がよいセキュリティ設定があります。
それは、ALBへのIPアドレス直アクセスのブロックです。
運用始めるとわかるんですが、ALBにIPアドレス直でめっちゃ悪意のあるアクセスが来ます。phpMyAdminの脆弱性とか狙った攻撃ですね。
先ほどセットしたowww.kahoo-myapp.netでもElastic Beanstalkの発行するドメインでもいいのですが、それでIPアドレスを正引きしてそのアドレスでアクセスすると同じページが表示されます。これをブロックするわけです。

しかも、IPアドレス直のアクセスが数秒間に連続してくるリクエストが来るのでその分だけPHPが実行されてサーバー負荷にもなったりします。
これは、WAFを導入することでドメインのみのアクセスとすることで回避出来ます。
Web ACLの作成
Web ACLを作っていきます。
WAFの設定画面にいき[Create web ACL]を押下します。

Nameに、任意の識別名称を入力します。
CloudWatch metric nameは同じ名前が自動で入力されます。
Resource typeに Regional resourcesを選択します。
Regionは、Asia Pacificを選択します。
Associated AWS resourcesで先ほどElastic Beanstalkで作成したALBを選択します。
適用したいALBを指します。

RulesでAdd my own rules and rule goupsを選択します。

以下の画面で「HTTP HeaderのHostが指定ドメインではない場合はブロックする」ルールを追加します。
RuleのNameは任意の名前です。
TypeはRegular Ruleです。
If a requestでdoesn't match the statement(NOT)で条件に合致しなかったらにします。
Statementでは HeaderのHostが.kahoo-myapp.netにEnds with match(最後が合致)する条件にします。
これはALB直はowwwになりますが、CloudFront経由の場合はwwwで来るので複数条件に合う為です。またこうしておけばステージング環境や開発環境の別サブドメインにも使えます。
最後にBlockを選びます。

ルールを追加したらどのルールにも合致しない場合は許可であるAllowをONにして[Next]を押下します。

ルールの優先順位はルールが一つなのでそのまま[Next]を押下します。

CloudWatch metricsも自動入力の値のまま[Next]を押下します。

最後に確認画面で確認出来たら[Create web ACL]を押下します。

設定が完了するとIPアドレス直アクセスが、403 Forbiddenになることがわかります。

WAFを入れた途端に色々なIPからスパムアクセスがやってきるのがわかります。恐ろしい世界ですね。

ちなみに、WAFの設定でALBへのアクセスをCloudFrontからのアクセスのみに絞ることも出来るのですが、僕は時にキャッシュサーバーを通さずに直でオリジンサーバーにアクセス出来た方が何かと便利だと思うので、これは設定しない事が多いです。
案件にもよりますが、オリジンドメインもどこからもリンクされなければ基本的にはクロールされないでしょう。
次のページはデプロイ編です。GitHubと連携してコミットされたら自動でデプロイ処理を走る設定をいれます。
鉄板インフラ構築 その5 〜デプロイ編〜
前章までで、一通りのインフラ環境は構築出来ました。
ここでは、実際にWebアプリのデプロイする方法を解説していきます。
Webアプリの準備
まずWebアプリのソースコードをGitHubに配置します。
GitHubにmyappというリポジトリを作成し、ソースルートにpublicというディレクトリを作成しそこにindex.phpを設置します。
中身はこれだけです。
<?php
echo "Hello MyApp!";
そして、もう一つソースルートに.ebextensionsディレクトリを作成し、そこに00_init.configファイルを設置します。
.ebextensionsフォルダに.configファイルを配置すると、デプロイ時にEC2に施したい設定を自動実行してくれるようになります。まさにElastic Beanstalk(eb)の拡張する(extension)為の構成ファイル群ですね。
# ドキュメントルート変更
option_settings:
aws:elasticbeanstalk:container:php:phpini:
document_root: '/public'
commands:
# 日本時間にする
1date:
command: "sudo cp /usr/share/zoneinfo/Japan /etc/localtime"
今まではソースコードのルートがドキュメントルートになっていたのでこれを一つ下のpublicディレクトリに変更します。
そしてEC2の時間設定も日本時間にするコマンドを入れておきます。
これをmasterにプッシュしておきます。リポジトリの作成完了です。
AWS Pipelineの構築
開発ソースが準備出来たらデプロイ処理をするPipelineを構築していきます。
以下のページを参考にしました。
https://aws.amazon.com/jp/getting-started/tutorials/continuous-deployment-pipeline/
CodePipelineの設定画面を開き[パイプラインを作成する]を押下します。

パイプライン名に任意の名称を入力します。ここでは pipeline-myapp としました。
サービスロールは新しいサービスロールを自動作成で良いでしょう。ロール名も勝手に決まります。
[次に]を押下します。

「ソースステージを追加する」、ではソースプロバイダーにGitHubを選択してGitHubの接続をし、GitHub側でここからのアクセスを許可するようにします。
するとそのアカウントで管理しているGitHubリポジトリが読み取れるようになるので、先ほど作成したリポジトリを選択します。本番なのでmasterを選択します。
[次に]を押下します。

「ビルドステージを追加する」、ではデプロイ前にビルドする内容があればここで設定をします。
AWS CodeBuildかJenkinsで追加可能です。
恐らくここでcomposer installしたり、npm installしたりするかと思います。
本記事では一旦こちらはスキップとさせて頂きます。

「デプロイステージを追加する」、ではページ3で構築したElastic Beanstalkの環境を選択していきます。
デプロイプロバイダーに AWS Elastic Beanstalkを選択してリージョンに東京リージョンを選択していくと、次のアプリケーション名・環境名はドロップダウンから選択するだけです。
う〜〜〜ん!簡単すぎる!!
以前はCircleCIからこのあたり色々セットアップしましたがもうこれで十分です。
ベンダーロックにはなるけれど、システムが統合されていると便利ですね。

最後に確認画面を見て[パイプラインを作成する]を押下すれば完了です。

パイプライン作成後すぐに初回のデプロイが発動します。

ですがデプロイのところで失敗します。
先ほど自動作成したロールにlogs:CreateLogGroupのパーミッションがないとのこと。

同じ問題をフォーラムで発見しました。
この方もAWSの公式ページ通りやったけどエラーになったとのこと。
https://forums.aws.amazon.com/thread.jspa?threadID=302282
解決するにはその上記のパーミッションを付与すればいいとのことなので、
IAMページにいってCloudWatchLogsFullAccessを付与しました。
そして先ほどのデプロイ再試行したところ、無事デプロイが完了しました。

デプロイも正常に反映されました。素晴らしいです。

ソースを以下のように改変して、プッシュしてみます。
<?php
echo "Hello MyApp! from Takafumi Suzuki!"
自動的にデプロイ処理が走りWebアプリが更新されるようになりました。

WebアプリのEFS・DB接続
上記までのWebアプリでは、EFS・DBに接続してないただのPHPアプリです。
本記事ではEFSもDBも作成済みなので、それに接続していきます。
本記事はElastic Beanstalkを使ったインフラ構築がメインのネタなので、Webアプリのソースコードとしては最小限のものとします。
ということで、「MyApp」の機能は、アクセスするとDBのレコードとEFSに置いてある画像を読み取って表示するアプリです。スーパーマイクロアプリです。
さて、そのWebアプリの準備を説明していきます。
EFSへの自動接続
Elastic BeanstalkではステートレスなWebサーバーが毎度起動するので、動画や画像などの静的リソースはEFSに置くようにします。いわゆる永続的ストレージってやつです。
ここではそのEFSへの自動接続の説明をします。
実はElastic BeanstalkからEFSへの接続方法は、AWS公式ドキュメントに、その方法が掲載されているのでこれを使います。公式情報が一番安心出来ますからね。
そのページにあるstorage-efs-mountfilesystem.configのリンクの先にあるスクリプトをダウンロードします。
これは、先ほど同様.ebextensionsディレクトリに設置する.configファイルです。
この.configファイルには以下のような説明が書かれてあります。(和訳)
FILE_SYSTEM_ID設定は、storage-efs-createfilesystem.config構成ファイルによって作成された「FileSystem」という名前のリソースを参照します。 このファイルを使用してマウントするには
AWS Elastic Beanstalkの外部で作成したファイルシステムでは、RefをリソースIDで置き換えます
(例:fs-e7605f4e): FILE_SYSTEM_ID:fs-e7605f4e
サンプルスクリプトではEFSの自動作成からやっているのでFileSystemIDがあるのですが、今回はまさしく外部で作成したEFSになるのでリソースIDを置換すればいいわけです。
ですが、本番や開発などの環境によって接続したいEFSは変わってくるので、ソース管理下となるここに固定値を書くのは宜しくありません。
スクリプトを見ると55行目に、
EFS_FILE_SYSTEM_ID=$(/opt/elasticbeanstalk/bin/get-config environment -k FILE_SYSTEM_ID)
と書かれてあり、結局のところ環境プロパティからリソースIDを取得して接続しているので、これを使います。
Elastic Beanstalkの環境の設定画面にいきます。そして
FILE_SYSTEM_IDに先ほど本記事で作成したEFSのリソースIDを追加して適用を押下します。

そして、先ほどのスクリプトの33行目をコメントアウトしましょう。
option_settings:
aws:elasticbeanstalk:application:environment:
# FILE_SYSTEM_ID: '`{"Ref" : "FileSystem"}`'
MOUNT_DIRECTORY: '/efs'
これをプッシュしてデプロイしてみます。
ここで以下のようなエラーがでる場合はDNS名前解決が出来ていない場合です。
Failed to resolve "fs-ad9daa8c.efs.ap-northeast-1.amazonaws.com" - check that your file system ID is correct.
VPCの「DNS解決」「DNSホスト名」を両方とも有効に変更すればOKです。
https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/vpc-dns.html
本記事2ページ目のVPCの作成にも方法を記載しています。
デプロイに成功すると、EFSの自動接続が完了します。
EC2にログインしてdfコマンドをうつと/eftにマウント出来ていることを確認できます。
[ec2-user@ip-172-32-13-234 /]$ df
ファイルシス 1K-ブロック 使用 使用可 使用% マウント位置
devtmpfs 480448 72 480376 1% /dev
tmpfs 491132 0 491132 0% /dev/shm
/dev/nvme0n1p1 8189348 2040556 6048544 26% /
127.0.0.1:/ 9007199254739968 0 9007199254739968 0% /efs
しかし、このままだとルートディレクトリにあるので使いづらいです。
実際の運用ではドキュメントルート以下などで使う事が多いのでシンボリックリンクを張るようにします。
先ほどのスクリプトに以下の記述を足します。
container_commands:
1link:
command: "sudo -u webapp ln -s /efs public/data"
container_commandsはWebアプリのソースコードに対して影響するコマンドの実行です。
公式ドキュメントに詳細内容が記載されています。
ここに列挙していくとアルファベット順で実行するので、1linkとしてcommandを記述します。
注意点としては、この時のカレントディレクトリはソースコードのルートの位置になっているので public/data というような記述の仕方をします。
デプロイしてみます。
/var/www/html/public/ 配下にdataディレクトリが作られていれば完了です。
[ec2-user@ip-172-32-13-234 html]$ ll /var/www/html/public/
合計 4
lrwxrwxrwx 1 webapp webapp 4 5月 1 12:48 data -> /efs
-rw-rw-r-- 1 webapp webapp 439 5月 1 03:46 index.php
実際はWebアプリから画像をアップしたりしますが、今回はWinSCP等のSFTPソフトなどで直接dataディレクトリに画像をアップロードしてみます。
正常にdataディレクトリに置いた画像がブラウザからも見られるようになりました。

EFSの自動接続の設定はこれで完了です。
DBへの接続
WebアプリからDBへの接続処理を書く前に、Webアプリから引っ張ってくる用に何かレコードを1つ入れておきましょう。
レコードのINSERTは今回はターミナルからでもいいですし、MySQLWorkbenchなどのDBクライアントソフトを利用しても良いでしょう。
いずれにせよEC2のSSH経由でレコードをINSERTします。
以下のテストデータを入れてみました。(僕が20歳というわけではありません笑)
mysql> select * from my_table;
+----+--------+------+---------------------+
| id | name | age | create_at |
+----+--------+------+---------------------+
| 1 | suzuki | 20 | 2020-04-30 22:23:10 |
+----+--------+------+---------------------+
さて、PHPからDBへの接続は古来からの方法のPDOやPHPフレームワークのDBライブラリから接続するだけです。
ですが、DBの接続情報もソースコードに記載するよりは、EFSと同様にElastic Beanstalkの環境プロパティに記述した方が使い勝手がよくなります。
Elastic Beanstalkの環境の設定画面にいきます。そして
ページ2で作成したAuroraのホスト名・ユーザー名・パスワードをDB_HOST, DB_USER, DB_PASS として書き込んでいきます。
(EFSでセットした01_efs.configから自動でMOUNT_DIRECTORYも追加されてました。)

そして環境プロパティにセットしたDB接続情報をphpファイルとして出力するconfigファイルを作成します。
[.ebextensions/02_env.config]files:
"/var/script/echo_env.sh":
mode: "000755"
content : |
#!/bin/bash
DB_HOST=$(/opt/elasticbeanstalk/bin/get-config environment -k DB_HOST)
DB_USER=$(/opt/elasticbeanstalk/bin/get-config environment -k DB_USER)
DB_PASS=$(/opt/elasticbeanstalk/bin/get-config environment -k DB_PASS)
echo "<?php";
echo "define(\"DB_HOST\", \"${DB_HOST}\");"
echo "define(\"DB_USER\", \"${DB_USER}\");"
echo "define(\"DB_PASS\", \"${DB_PASS}\");"
container_commands:
# 念のためconfigディレクトリが無くても作成しておく
01_mkdir:
command: "sudo -u webapp mkdir -p config"
# DB接続情報の出力
02_output:
command: |
sudo /var/script/echo_env.sh > config/database_config.php
DB接続情報をいちいちget-configコマンドで取得するのもわずかながら負担かかりそうなので、phpファイルとして出力しておきます。
そうすればphpからはrequireするだけでよくなります。
デプロイしてみるとdatabase_config.phpが生成されていることがわかります。
(パスワードは適当ですし、実際に使っているものではない為晒しています。)
[ec2-user@ip-172-32-13-234 public]$ cat /var/www/html/config/database_config.php
<?php
define("DB_HOST", "aurora-instance-myapp-cluster.cluster-cvywerzt18m3.ap-northeast-1.rds.amazonaws.com");
define("DB_USER", "admin");
define("DB_PASS", "hrANespJayeV");
そしてpublic/index.phpからDBレコードを読む処理を記述します。ついでに先ほど設定したEFSの画像も表示するようにします。
DB接続確認は自分の過去の記事を参考にしました。
<?php
require_once __DIR__ . "/../config/database_config.php";
// defineの値は環境によって変えてください。
define('DB_SCHEME', 'db_myapp');
try {
/// DB接続を試みる
$pdo = new PDO('mysql:host=' . DB_HOST . ';dbname=' . DB_SCHEME, DB_USER, DB_PASS);
$row = $pdo->query("SELECT * FROM my_table WHERE id = 1")->fetch(PDO::FETCH_ASSOC);
} catch (PDOException $e) {
$msg = "MySQL への接続に失敗しました。<br>(" . $e->getMessage() . ")";
echo $msg;
exit;
}
?>
<!doctype html>
<html lang="jp">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>MyApp</title>
</head>
<body>
<h1>MyApp</h1>
<p><?php echo "Hello MyApp! from Takafumi Suzuki!"; ?></p>
<h2>RDSのデータ</h2>
<pre>
<?php print_r($row); ?>
</pre>
<h2>EFSの画像</h2>
<p>
<img src="/data/reiwa.png">
</p>
</body>
</html>
デプロイするとDBのレコードもEFSの画像も表示されていることがわかります。

まとめ
以上、ここまで読んで頂き本当にお疲れ様でした。そしてありがとうございましたm(_ _)m
本記事は書き始めてから仕上げるまで3日くらいかかりました。
本記事の作業をマスター出来るようになり、これをベースとして色々カスタマイズしていけば、中規模案件くらまではこれでさばけるのではないかと思います。
案件規模に対してのスケーリングはEC2とDBのスペックやインスタンス数やCloudFrontのキャッシュ設定を調整していけばいいだけですから。
かなり結構しんどいボリュームでしたが、これを読んであなたのインフラ構築作業のお役に立てれたら嬉しい限りでございます。
これで少しでもWebアプリからインフラまでこなせるフルスタックエンジニアが増える事を願っています。
最後に今回のWebアプリ「MyApp」のソースコードを置いておきます。
現場からは以上です。

