この記事は約7分で読めます。
この記事では、Amazon EC2のAuto Scaling機能とAmazon S3を用いて、比較的安価に可用性の高いウェブページをデプロイする方法を紹介します。 今回は以下のような環境を作ってみます。

前提知識
VPC、EC2、ALB、IAM、S3の基本的な知識(触ったことがある、程度でOK)
なぜAuto Scalingを使うのか?
Auto Scalingは、複数AZ(アベイラビリティゾーン)に跨って自動でEC2インスタンスを起動・削除できる機能です。 Auto Scalingを使うことで、インスタンスを需要に応じて増減させ、コストを抑えつつ必要十分なだけのリソースを確保することができます。
例1)Webサーバーに対し、特定の時期や時間帯だけアクセス数が急増しており、サーバーに負荷がかかっている
→インスタンス台数をスケジューリングし、アクセスが増える時間帯だけ増やすことで、需要に合わせたリソースを確保
例2)予測できないアクセス増が見込まれる
→自動スケーリングを設定して、急なアクセス増加時もサーバーダウンを回避
Auto Scalingを用いる際は、AMI(Amazonマシンイメージ)と呼ばれるイメージを事前に準備し、それを元に新規サーバーを自動で起動します。 そのため、環境構築やコンテンツの更新には工夫が必要となります。
本記事では、S3バケットにコンテンツをアップロードし、Auto Scalingで作成されたインスタンスがバケット内のコンテンツを同期するような設定を行うことで、比較的安価でコンテンツ更新をしやすい環境の構築方法を紹介します。
やり方
コンソールから構築していきます。
VPC作成
まずはVPCを立ち上げます。
今回は以下のように、2AZ構成で構築します。コンソールの作成画面で「VPCなど」をオプションをクリックすると、関連リソースが一気に作成できて便利です。
- 名前:
auto-scaling-test-vpc
- パブリックサブネット2つ(2AZ)
- プライベートサブネット2つ(2AZ)
- インターネットゲートウェイ
- S3用のエンドポイントを作成

また、後ほどの検証でセッションマネージャーからログインするため、パブリックサブネットにNATゲートウェイを設置し、プライベートサブネットのルートテーブルにこのNATゲートウェイへのルートを追加しておきます。 (利用料がそこそこかかるので、NATゲートウェイやそこに紐づいたElastic IPは検証後に消すのをお忘れなく!)
S3バケット作成
続いて、コンテンツ格納用のS3バケットを作成します。
S3バケットの名前は世界で一意である必要があります。今回は以下のように命名します。
auto-scaling-test-contents-(AWSアカウントID)
その他の設定はデフォルトで大丈夫です。

作成後、適当な内容のindex.html
をアップロードしておきます。今回は以下のような内容のものを入れておきます。
<html> <body> Auto Scaling Test </body> </html>
IAMロール作成
次に、EC2インスタンス用のIAMロールを作成します。
デフォルトの状態では、EC2インスタンスにはS3へのアクセス権限が与えられていません。なので、今回の構成で作る各インスタンスがコンテンツを取得できるよう、S3へのアクセス権限を与えるIAMロールを作成します。
ユースケースは「EC2」、許可ポリシーはAmazonS3ReadOnlyAccess
と、後の検証のためにAmazonSSMManagedInstanceCore
も選択しておきます。
ロール名は今回はauto-scaling-test-role-ec2
としておきます。

AMI作成用のインスタンス(ゴールデンイメージ)を起動
Auto Scalingの設定に必要なAMIを取得するためのEC2インスタンスを起動します。 今回は検証のため、小さめのインスタンスで起動していきます。
以下のように設定を変更して起動します。他は全てデフォルトで大丈夫です。
- 名前:
auto-scaling-test-gi
- インスタンスタイプ:t3.micro
- キーペアを作成or選択
- VPC:
auto-scaling-test-vpc
- サブネットはいずれかのパブリックサブネットを選択
- パブリックIP:有効化
- セキュリティグループは新規に作成する
- 名前:
auto-scaling-sg-gi
- インバウンドルール:自分のIPからのSSH接続を許可
- 名前:
- 「高度な詳細」欄を開き、「IAMインスタンスプロフィール」から
auto-scailng-test-role-ec2
を選択


内部作業
AMI取得用インスタンスの起動が完了したら、SSH接続してコンテンツ用S3バケットからコンテンツを同期するための設定を行います。
本記事ではAmazon Linux 2023とApacheを用いたやり方を紹介しますが、他のOSやWebサーバーアプリケーションを用いる場合でも、AWS CLIのS3 syncコマンドでS3の内容を定期的にドキュメントルートにコピーできればOKです。
Apacheの導入
# Apacheをインストール $ sudo yum install -y httpd # 自動起動をオンにする $ sudo systemctl enable httpd.service # デフォルトのDocumentRootに移動 $ cd /var/www/html # 空のインデックスページを作成(ALBのヘルスチェックを通すため) $ sudo touch index.html
Cronieの導入
S3と同期するシェルスクリプトを定期的に実行させる設定を行います。今回は簡単に実装するため、cronを使用します。 Amazon Linux 2023にはcronが標準搭載されていないため、Cronieのインストールから行います。(AWSアカウントID)の部分は実際のものに書き換えてください。
# Cronieのインストール $ sudo yum install cronie -y # ディレクトリ移動 $ cd /usr/local/bin/ # 起動時に同期するためのシェルスクリプトを作成 $ sudo touch s3sync_boot.sh #シェルスクリプトを編集 $ sudo vim s3sync_boot.sh # 以下をコピペし、保存する。(AWSアカウントID)の部分は実際のものに書き換える sudo aws s3 sync --exact-timestamps s3://auto-scaling-test-contents-(AWSアカウントID)/var/www/html sudo service httpd restart # 定期的に同期するためのシェルスクリプトを作成 $ sudo touch s3sync_scheduled.sh # シェルスクリプトを編集 $ sudo vim s3sync_scheduled.sh # 以下をコピペし、保存する sudo aws s3 sync --exact-timestamps s3://auto-scaling-test-contents-(AWSアカウントID)/var/www/html sudo service httpd reload # cronで実行できるように、シェルファイルの権限を変更 $ sudo chmod 755 s3sync_boot.sh $ sudo chmod 755 s3sync_scheduled.sh
※小ネタ
aws s3 sync
コマンドを用いた際は、変更があったオブジェクトのみが同期されます。ここで、変更後のオブジェクトのディレクトリ・オブジェクト名・サイズが完全に一致していると、変更されていないオブジェクトとみなされ、仮に内容が違っていても正常に同期されません。これを防ぐために、--exact-timestamps
オプションを用いることで、オブジェクトの更新日時を参照して変更の判定を行うことができます。
crontabの編集
今回は起動時および5分間隔でS3バケットと同期する設定を行います。
# cronの設定ファイルを開く $ crontab -e # 以下をコピペして保存 @reboot /usr/local/bin/s3sync_boot.sh */5 * * * * /usr/local/bin/s3sync_scheduled.sh
ここで、S3との同期がうまくいっているか確認してみましょう。インスタンスを再起動し、以下のコマンドを入力してみます。同期設定がうまくいっていれば、空のページではなく、先ほどS3バケットにアップロードしたindex.html
の内容が表示されるはずです。
$ curl localhost

AMIの取得
インスタンス一覧から上で作成したインスタンスを選択し、「アクション」→「イメージとテンプレート」からAMIを取得します。
名前はauto-scaling-test-ami
としておきます。

ALB作成
Auto Scalingで起動するインスタンスを関連付けるためのALB(Application Load Balancer)を作成します。
ALB用のセキュリティグループ
事前準備として、ALB用のセキュリティグループを以下の設定で作成します。
- 名前:
auto-scaling-test-sg-alb
- 説明:
for test
- VPC:
auto-scaling-test-vpc
- インバウンドルール
- タイプ:HTTP
- ソース:Anywhere IPv4
- アウトバウンドルール
- タイプ:すべてのトラフィック
- 送信先:
0.0.0.0/0
ALB本体
続いてALB本体を、以下の設定で作成します。
- ロードバランサー名:
auto-scaling-test-alb
- VPC:
auto-scaling-test-vpc
- サブネット:作成した2つのパブリックサブネット
- セキュリティグループ:
auto-scaling-test-sg-alb
- ターゲットグループは名前を
auto-scaling-test-alb-tg
とし、ターゲットを登録せずに作成
起動テンプレート・Auto Scalingグループ作成
セキュリティグループ
こちらも事前に、Auto Scalingグループ用のセキュリティグループを作成しておきます。
- 名前:
auto-scaling-test-sg-asg
- 説明:
for test
- VPC:
auto-scaling-test-vpc
- インバウンドルール
- タイプ:HTTP
- ソース:ALBのセキュリティグループ
起動テンプレート
起動テンプレートを、先ほど作ったAMIを使って作成します。
- 名前:
auto-scaling-test-template
- AMIは先ほど作った
auto-scaling-test-ami
を指定 - インスタンスタイプ:t3.micro
- キーペアは先ほど作ったものを指定
- サブネットは設定なし
- セキュリティグループ:
auto-scaling-test-sg-asg
- 「高度な設定」→「IAMインスタンスプロフィール」から
auto-scaling-test-role-ec2
を選択
Auto Scalingグループ
続いて、このテンプレートを用いてAuto Scalingグループを作成します。
- 名前:
auto-scaling-test-asg
- 起動テンプレート:
auto-scaling-test-template
- バージョンはLatestを選択
- VPC:
auto-scaling-test-vpc
- サブネットは2つのプライベートサブネットを選択する
- アベイラビリティゾーンのディストリビューションは「バランシング(ベストエフォート)」を選択
- 「ロードバランシング」欄は、以下のようにします
- 「既存のロードバランサーにアタッチする」、「ロードバランサーのターゲットグループから選択する」をそれぞれ選択
- ターゲットグループは
auto-scaling-test-alb-tg
を選択
- VPC Lattice、ARCゾーンシフトは今回はなし
- 「Elastic Load Balancing のヘルスチェックをオンにする」にチェックを入れる
- グループサイズ
- 今回は検証なので、希望するキャパシティ1、最小容量1、最大容量2としておく
スケーリングポリシーについては、予測できるアクセスがある場合は「スケーリングポリシーなし」を選び、作成後にスケーリングをスケジュールします。
予測できないアクセス増がある場合は「ターゲット追跡スケーリングポリシー」を選び、自動スケーリングを設定します。 サーバーの処理能力がパンクしがちな場合はCPU使用率を閾値に、アクセスが多すぎて帯域がパンクしがちな場合はロードバランサーのリクエスト数を閾値にする、など状況に応じて設定を変えてみましょう。
今回は「平均CPU使用率」、ターゲット値は「50」としてみます。

しばらく待つと、自動でインスタンスが1つ立ち上がります。 (今回は名前タグを設定していないので、インスタンス名がついていないものが起動します。)

アクセス・負荷テストをしてみよう
アクセステスト
これで一通りの環境は完成です。実際にアクセスしてみましょう。
ALBのDNS名をコピペし、HTTPで接続してみます。

上手くいっていれば、先ほどS3バケットにアップロードしていたindex.htmlの内容が表示されます。

S3バケットの内容を変えたりして、コンテンツが自動的に同期されるかどうかも確認してみてください。
自動スケーリングのテスト
試しに、立ち上がっているインスタンスを終了(削除)してみましょう。数分待つと、新しいインスタンスが自動で立ち上がります。
インスタンスに負荷をかけ、追加のインスタンスが自動で起動するかどうかも試してみましょう。 1つだけ起動しているインスタンスにセッションマネージャーからログインし、次のコマンドでCPU稼働率を100%にしてしばらく待ちます。
yes > /dev/null
しばらくすると、インスタンスが2個に増えます。yesコマンドをCtrl+Cで中断して再度しばらく待つと、インスタンスの個数は1個に戻ります。

あとがき
今回の構成は、弊社サーバーワークスで私が模擬案件という研修を受けた際に構築したものでした。 当時の私はLinuxやAWSにまだあまり馴染んでいなかったので、この「自動でスケールするWebアプリ環境」を作るための構成と手順を用意するのにかなりの時間がかかってしまいましたが、まったくの素人からは一歩抜け出せたのかな?と思っています。
模擬案件やその他の研修の様子は弊社のもう1つのブログ「サバワク」で私の同期たちがレポートしていますので、そちらの記事も是非ご覧ください!