はじめる前に
- 必須AWS アカウントを持っていること
- 必須マネジメントコンソールにサインインできること
- 必須EC2 インスタンスを複数台起動した経験があること
- 必須セキュリティグループの設定経験があること
- 必須SSH で EC2 にログインした経験があること
- あると良いWeb サーバーの設定ファイルを編集した経験
ローカルの PowerShell から Windows 標準の OpenSSH を使って、3 台の EC2 にそれぞれ SSH 接続します。
参照する公式ドキュメント
手順に迷ったときや、用語の意味を確かめたいときに開きましょう。
proxy_pass をはじめ、転送のための設定項目がまとまっています。
nginx.org/en/docs/http/ngx_http_proxy_module.html
nginx のロードバランシング機能
↗
upstream ブロックの書き方や、振り分け方式の種類を確認できます。
nginx.org/en/docs/http/load_balancing.html
EC2 セキュリティグループ
↗
インバウンドルールの考え方や、ソースにセキュリティグループを指定する方法を確認できます。
docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/ec2-security-groups.html
EC2 インスタンスへの接続
↗
SSH での接続方法や、接続できないときの確認ポイントがまとまっています。
docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/AccessingInstances.html
※ リンク切れの場合は、ページタイトルで検索してください。
背景・シナリオ
1 台のサーバーだけでアクセスを受け止めていると、そのサーバーが処理しきれなくなったり、壊れたりしたときにサービスが止まってしまいます。マネージドサービスのロードバランサーを使えば、複数のサーバーへのアクセスの振り分けや、調子の悪いサーバーを自動的に避ける仕組みを AWS が代わりに用意してくれます。今回はその裏側にある考え方を理解するため、ふつうの EC2 に Web サーバーソフト「nginx」を入れ、自分の手で「振り分ける役(リバースプロキシ)」を組み立てます。
「リバースプロキシ」って何?
利用者からのアクセスをいったん受け止め、その裏にある別のサーバー(今回はバックエンドの 2 台のサーバー)へ転送する仕組みです。利用者からは 1 つの窓口(プロキシ)にアクセスしているように見えますが、実際の処理は背後の複数のサーバーが分担します。
「調子の悪いサーバーを自動的に避ける」とは、具体的にどういう動き?
nginx の設定で、一定回数連続して応答が失敗したサーバーを、しばらくの間振り分け先から外す、という挙動を設定できます。今回作る設定もこの挙動を持たせます。ただし、これは「実際にアクセスが失敗したとき」に初めて気づく仕組みです。マネージドサービスのロードバランサーは、アクセスがなくても定期的に様子を見に行く「ヘルスチェック」を行っており、この点で挙動が異なります。
2 台のバックエンド EC2(Web サーバー、それぞれ自分のホスト名を表示する簡単なページ)と、1 台のプロキシ用 EC2(nginx でリバースプロキシを構成)を作る。プロキシのパブリック IP にアクセスして、表示されるホスト名が 2 台の間で切り替わることを確認し、片方のバックエンドを止めても自動的に避けられることを確認する。
つくる構成
中央のプロキシ用 EC2 が利用者からのアクセスを受け止め、背後の 2 台のバックエンド EC2 へ順番に振り分けます(ラウンドロビン)。
プロキシの 1 か所へ
設定ファイルを自分で書く
表示するページ
表示するページ
要件
以下の要件を満たす構成を作り、ブラウザで振り分けと自動切り離しを確認してください。
| No | 要件 |
|---|---|
| 1 | リージョンは「東京(ap-northeast-1)」を使用する。 |
| 2 | バックエンド用 EC2 を 2 台起動する(Amazon Linux 2023、無料利用枠タイプ、名前タグ自由・例:web-1 / web-2)。それぞれに httpd を導入し、自分のホスト名を表示する簡単なページを置く。 |
| 3 | バックエンド用セキュリティグループで、HTTP(80)をプロキシ用セキュリティグループからのみ許可する。 |
| 4 | プロキシ用 EC2 を 1 台起動する(Amazon Linux 2023)。セキュリティグループで HTTP(80)をインターネットから許可し、SSH をマイ IP から許可する。 |
| 5 | プロキシ EC2 に nginx を導入し、2 台のバックエンドのプライベート IP アドレスへ振り分ける設定(upstream ブロック、max_fails・fail_timeout 付き)を行う。 |
| 6 | プロキシ EC2 のパブリック IP にブラウザでアクセスし、表示されるホスト名が 2 台のバックエンドの間で切り替わることを確認する。片方のバックエンドの httpd を停止し、しばらくアクセスを続けるとそちらが振り分け先から外れることを確認する。 |
構築の進め方
「セキュリティグループ → バックエンド 2 台 → プロキキシ用 EC2 → nginx の設定 → 動作確認」の順に組み立てます。
-
マネジメントコンソールにサインインし、リージョンを東京に合わせる
ブラウザで AWS マネジメントコンソールにサインインし、画面右上のリージョンが「アジアパシフィック(東京)ap-northeast-1」になっていることを確認します。
-
セキュリティグループを 2 つ作成する
EC2 コンソールの「セキュリティグループ」から、次の 2 つを作成します。先にプロキシ用セキュリティグループを空の状態で作っておき、あとからバックエンド用のルールで参照すると迷いません。
プロキシ用セキュリティグループ インバウンド:HTTP(80)を 0.0.0.0/0(インターネット)から許可、SSH(22)を「マイ IP」から許可バックエンド用セキュリティグループ インバウンド:HTTP(80)をソースにプロキシ用セキュリティグループを指定して許可(SSH も必要であれば「マイ IP」から許可しておくと、後片づけ時のログイン確認に使えます) なぜプロキシ経由だけに絞るのかバックエンドへの直接アクセスを閉じておくことで、利用者が必ずプロキシを通る経路にそろいます。振り分けや自動切り離しが効くのも、この経路が 1 本にそろっているからです。
-
バックエンド用 EC2 を 2 台起動する
EC2 コンソールで「インスタンスを起動」を 2 回行い、Amazon Linux 2023・無料利用枠タイプで、名前タグを自由に決めて(例:
web-1/web-2)起動します。セキュリティグループは手順 2 のバックエンド用を選びます。「高度な詳細」→「ユーザーデータ」に次の内容を貼り付けます。#!/bin/bash dnf install -y httpd echo "<h1>Hello from $(hostname)</h1>" > /var/www/html/index.html systemctl enable httpd systemctl start httpd1 行ずつ確認しましょう。
dnf install -y httpdAmazon Linux 2023 のパッケージ管理コマンド dnfで、Web サーバーソフトのhttpd(Apache)を確認なしで導入します。echo "..." > /var/www/html/index.htmlその時点のホスト名( $(hostname))を埋め込んだ簡単なページを、Web サーバーの公開フォルダに作成します。これにより、どちらのサーバーが応答したか見分けられます。systemctl enable httpdインスタンスを再起動しても httpdが自動的に立ち上がるよう設定します。systemctl start httpdhttpdを今すぐ起動します。プライベート IP アドレスを控えておく起動後、各インスタンスの詳細画面でプライベート IP アドレスを確認し、メモしておきましょう。あとで nginx の設定に使います。
-
プロキシ用 EC2 を 1 台起動する
同じように「インスタンスを起動」から、Amazon Linux 2023・無料利用枠タイプで 1 台起動します。セキュリティグループは手順 2 のプロキシ用を選びます。パブリック IP の自動割り当てを有効にしておきます。
-
プロキシ EC2 に SSH でログインし、nginx を導入する
ローカルの PowerShell から、Windows 標準の OpenSSH を使ってプロキシ EC2 に接続します。
PS> ssh -i "C:\Users\you\Downloads\your-key.pem" ec2-user@<プロキシEC2のパブリックIP>ログインできたら、nginx を導入します。
$ sudo dnf install -y nginx秘密鍵ファイルのアクセス権限Windows 標準の OpenSSH では、
.pemファイルのアクセス権限が緩すぎると接続を拒否されることがあります。エラーが出た場合は、鍵ファイルのプロパティから自分以外のアクセス権を外してみましょう。 -
nginx の設定ファイルを作成する
プロキシ EC2 内で、設定ファイル(例:
/etc/nginx/conf.d/proxy.conf)を作成します。手順 3 で控えた 2 台のプライベート IP アドレスを使います。upstream backend_pool { server <web-1のプライベートIP>:80 max_fails=2 fail_timeout=10s; server <web-2のプライベートIP>:80 max_fails=2 fail_timeout=10s; } server { listen 80; location / { proxy_pass http://backend_pool; proxy_next_upstream error timeout http_502 http_503 http_504; } }1 行ずつ確認しましょう。
upstream backend_pool { ... }振り分け先のグループに backend_poolという名前を付けて定義します。server <IP>:80 max_fails=2 fail_timeout=10s;振り分け先のサーバーを 1 台ずつ記載します。 max_fails=2は「連続 2 回失敗したら」、fail_timeout=10sは「10 秒間は振り分け先から外す」という意味です。値は自由に決められますが、悩む場合はこの例の値から始めるとよいでしょう。listen 80;プロキシ自身が HTTP(80 番ポート)でアクセスを受け付けることを示します。 proxy_pass http://backend_pool;受け付けたアクセスを、先ほど定義した backend_poolへ転送します。ここで台数や振り分け方式を意識せず書けるのがupstreamの利点です。proxy_next_upstream error timeout http_502 http_503 http_504;転送先からエラーやタイムアウトが返ってきた場合に、別の振り分け先へ自動的に再試行する条件を指定します。 IP アドレスは自由に決まる値ですプライベート IP アドレスは、自分の VPC・サブネットの設定によって変わります。手順 3 で確認した値をそのまま使ってください。
-
構文チェックをして、nginx を起動する
設定ファイルを保存したら、構文に誤りがないか確認します。
$ sudo nginx -t # syntax is ok / test is successful と表示されれば問題ありません $ sudo systemctl enable nginx $ sudo systemctl start nginx # 既に起動している場合は次で設定を反映します $ sudo systemctl reload nginx
-
動作確認をする
プロキシ EC2 のパブリック IP アドレスにブラウザでアクセスし(
http://<プロキシEC2のパブリックIP>)、ホスト名が表示されることを確認します。再読み込みを繰り返して、表示がweb-1とweb-2の間で切り替わることを確認しましょう。続けて、片方のバックエンドに SSH でログインし、
httpdを停止します。$ sudo systemctl stop httpdその後、プロキシのパブリック IP に何度かアクセスを繰り返し、停止したサーバーが振り分け先から外れていく様子を観察しましょう。
外れるまで少しアクセスが必要max_fails=2の設定では、停止後すぐにではなく、2 回失敗した時点で振り分け先から外れます。最初の数回は失敗(つながらない、もしくは遅い)応答が混ざることがあります。
つまずきポイント
初学者がよく引っかかる箇所を先回りでまとめました。答えそのものは載せていませんが、「どこを見直せばよいか」の手がかりとして使ってください。
「ブラウザでプロキシにアクセスしても、ページが表示されない・502 エラーになる」
①バックエンド用セキュリティグループが、プロキシ用セキュリティグループからの HTTP(80)を許可しているか、②upstream に書いた IP アドレスが、プライベート IP ではなくパブリック IP になっていないかを順に見直してみましょう。プロキシとバックエンドは同じ VPC 内の通信なので、パブリック IP は使いません。
「ホスト名の表示や振り分けの挙動が、変更前と変わらない」
nginx -s reload または systemctl reload nginx を忘れていないか確認しましょう。また、設定ファイルに構文エラーがある場合、反映自体が失敗しています。sudo nginx -t を実行し、エラーが出ていないかをまず確認してください。
完了チェック
要件の再確認ではなく、画面のどこを見れば達成を確認できるかをまとめました。ブラウザと SSH 接続先のターミナルで、次を順に確かめましょう。
- プロキシのパブリック IP にブラウザでアクセスすると、ホスト名を表示するページが表示される。
- 複数回アクセス(再読み込み)すると、表示されるホスト名が
web-1とweb-2の間で切り替わる。 - プロキシ EC2 内で
sudo nginx -tを実行してもエラーが出ない。 - 片方のバックエンドで
httpdを停止すると、数回の失敗のあと、そちらのホスト名が表示されなくなる(振り分け先から外れる)。 - 停止した
httpdを再開すると、しばらくしてそのホスト名が再び表示されるようになる(振り分け先に戻る)。
考えてみよう
手を動かすことに加えて、次の問いに自分の言葉で答えられるようにしておくと、理解がより深まります。
- 実際のロードバランサーは、リクエストが来なくてもバックエンドの状態を定期的に確認しに行きます(アクティブヘルスチェック)。今回の nginx の設定は、リクエストが失敗したときに初めて気づく仕組みでした。この違いは、どんな場面で問題になりそうでしょうか。
ヒント
「リクエストが来てから気づく」方式では、最初にそのサーバーへ振り分けられた利用者が、必ず一度は失敗した応答を受け取ってしまいます。アクセスの頻度が低い時間帯や、サーバーが落ちた直後にアクセスが集中する場面を想像してみましょう。 - プロキシ自体(このEC2)が落ちたら、システム全体はどうなるでしょうか。
ヒント
バックエンドが 2 台とも正常でも、その手前にいる窓口が 1 つしかなければ、その窓口が止まった時点で利用者は誰もアクセスできなくなります。「振り分ける役」自体を複数台にする、または冗長化する方法がないか考えてみましょう。 - バックエンドを 3 台、4 台と増やしたら、設定ファイルのどこを変更する必要がありそうでしょうか。
ヒント
upstream backend_pool { ... }の中に並んでいるserver行を見てみましょう。台数が増えるたびに、この設定ファイルを自分で編集して反映し直す必要がある、という点が今回の方式の特徴です。
後片づけ
3 台の EC2 とセキュリティグループを、依存関係につまずかない順番で削除します。
- プロキシ用 EC2 を削除する:EC2 コンソールの「インスタンス」でプロキシ用のインスタンスを選び、「インスタンスを終了(Terminate)」を実行します。
- バックエンド用 EC2 を 2 台削除する:同様に
web-1・web-2を選び、「インスタンスを終了(Terminate)」を実行します。 - セキュリティグループを削除する:今回作成したプロキシ用・バックエンド用の 2 つのセキュリティグループを、インスタンスを終了したあとに削除します。
削除するのは、このハンズオンで自分が作ったものだけ
セキュリティグループやインスタンスの一覧には、他のハンズオンや検証で使っているリソースが並んでいることもあります。名前タグをよく確認し、このハンズオンのために作ったものだけを選んで削除してください。デフォルト VPC やデフォルトのセキュリティグループは消さないようにしましょう。
コストに関する注意: 今回作成するのは通常のEC2 インスタンス 3 台のみで、それぞれインスタンスタイプに応じた時間課金が発生します。マネージドサービスのロードバランサーのような時間課金や、処理量に応じた課金(LCU)は発生しません。各インスタンスに付くディスク(EBS ボリューム)や、割り当てられるパブリック IPv4 アドレスにも料金がかかる場合があります。セキュリティグループ自体には料金はかかりません。検証が終わったら、上の「後片づけ」に沿って 3 台とも削除してください。最新の料金は AWS の公式料金ページで確認してください。