このチュートリアルは、2022 年 3 月の Microservices の概念を実践する 4 つのチュートリアルのうちの 1 つです。 Kubernetes ネットワーキング:
さらに多くの Kubernetes ネットワークユースケースで NGINX を使用するための詳細なガイダンスが必要ですか? 無料の電子書籍「NGINX を使用した Kubernetes トラフィックの管理」をダウンロードしてください。 実用ガイド。
あなたの組織は、Kubernetes で最初のアプリと API をリリースしました。 トラフィック量が多くなることが予想されると言われていますが (NGINX Ingress Controller がトラフィックを迅速にルーティングできるように自動スケーリングがすでに実装されています)、API が悪意のある攻撃の標的になる可能性があるという懸念があります。 API が大量の HTTP リクエストを受信すると(ブルートフォース パスワード推測や DDoS 攻撃の可能性あり)、API とアプリの両方が過負荷状態になったり、クラッシュしたりする可能性があります。
でも、あなたは幸運です! レート制限と呼ばれるトラフィック制御技術は、受信リクエスト レートを実際のユーザーにとって標準的な値に制限する API ゲートウェイの使用例です。 NGINX Ingress Controller を構成してレート制限ポリシーを実装すると、リクエストが多すぎてアプリと API が過負荷になるのを防ぐことができます。 素晴らしい仕事です!
このブログは、マイクロサービス 2022 年 3 月のユニット 2 「Kubernetes での API の公開」のラボに付随するもので、複数の NGINX Ingress コントローラーをレート制限と組み合わせて、アプリと API が過負荷になるのを防ぐ方法を示しています。
チュートリアルを実行するには、次の条件を満たすマシンが必要です。
ラボとチュートリアルを最大限に活用するには、開始する前に次のことを実行することをお勧めします。
背景ブログ、ウェビナー、ビデオを確認する
ラボの 18 分間のビデオ概要をご覧ください。
このチュートリアルでは次のテクノロジを使用します。
各チャレンジの手順には、アプリを構成するために使用される YAML ファイルの完全なテキストが含まれています。 GitHub リポジトリからテキストをコピーすることもできます。 各 YAML ファイルのテキストとともに GitHub へのリンクが提供されます。
このチュートリアルには 3 つの課題が含まれています。
このチャレンジでは、 Minikube クラスターをデプロイし、サンプル アプリと API としてPodinfo をインストールします。次に、 NGINX Ingress Controller をデプロイし、トラフィック ルーティングを構成し、 Ingress 構成をテストします。
minikubeクラスターを作成します。 数秒後、デプロイメントが成功したことを確認するメッセージが表示されます。
$ minikube start 🏄 完了!kubectl はデフォルトで「minikube」クラスターと「default」名前空間を使用するように設定されました
Podinfo は、 「Kubernetes でマイクロサービスを実行するためのベスト プラクティスを紹介する、Go で作成された Web アプリケーション」です。 フットプリントが小さいため、サンプル アプリと API として使用しています。
任意のテキスト エディターを使用して、次の内容を含む1-apps.yamlという YAML ファイルを作成します (またはGitHub からコピーします)。 以下を含むデプロイメントを定義します。
apiバージョン: apps/v1
種類: デプロイメント
メタデータ:
名前: api
仕様:
セレクター:
matchLabels:
アプリ: api
テンプレート:
メタデータ:
ラベル:
アプリ: api
仕様:
コンテナ:
-名前: api
イメージ: stefanprodan/podinfo
ポート:
-コンテナポート: 9898
---
apiバージョン: v1
種類: サービス
メタデータ:
名前: api
仕様:
ポート:
- ポート: 80
ターゲットポート: 9898
ノードポート: 30001
セレクター:
アプリ: api
タイプ: ロードバランサー
---
apiVersion: apps/v1
種類: デプロイメント
メタデータ:
名前: frontend
仕様:
セレクター:
matchLabels:
アプリ: frontend
テンプレート:
メタデータ:
ラベル:
アプリ: frontend
仕様:
コンテナ:
- 名前: frontend
イメージ: stefanprodan/podinfo
ポート:
- コンテナポート: 9898
---
apiバージョン: v1
種類: サービス
メタデータ:
名前: フロントエンド
仕様:
ポート:
- ポート: 80
ターゲットポート: 9898
ノードポート: 30002
セレクタ:
アプリ: フロントエンド
タイプ: ロードバランサー
アプリと API をデプロイします。
$ kubectl apply -f 1-apps.yamlデプロイメント.apps/api が作成されました サービス/api が作成されました デプロイメント.apps/frontend が作成されました サービス/frontend が作成されました
STATUS
列の値がRunning で
あることから、 Podinfo APIおよびPodinfo Frontendのポッドが正常にデプロイされたことを確認します。
$ kubectl get pods NAME READY STATUS RESTARTS AGE api-7574cf7568-c6tr6 1/1 実行中 0 87s frontend-6688d86fc6-78qn7 1/1 実行中 0 87s
NGINX Ingress Controller をインストールする最も速い方法は、 Helmを使用することです。
Helm を使用して、 NGINX Ingress Controller を別の名前空間 ( nginx ) にインストールします。
名前空間を作成します。
$ kubectl 名前空間 nginx を作成します
NGINX リポジトリを Helm に追加します。
$ helm リポジトリに nginx-stable を追加します https://helm.nginx.com/stable
クラスターに NGINX Ingress Controller をダウンロードしてインストールします。
$ helm install main nginx-stable/nginx-ingress \ --set controller.watchIngressWithoutClass=true \ --set controller.ingressClass=nginx \ --set controller.service.type=NodePort \ --set controller.service.httpPort.nodePort=30010 \ --set controller.enablePreviewPolicies=true \ --namespace nginx
STATUS
列の値がRunning である
ことで示されるように、NGINX Ingress Controller ポッドがデプロイされていることを確認します (読みやすくするために、出力は 2 行に分かれています)。
$ kubectl get pods -namespace nginx NAME READY STATUS ... main-nginx-ingress-779b74bb8b-d4qtc 1/1 実行中 ... ... 年齢をリスタート... 0 92秒
apiバージョン: networking.k8s.io/v1
種類: Ingress
メタデータ:
名前: first
仕様:
ingressClassName: nginx
ルール:
- ホスト: "example.com"
http:
パス:
- バックエンド:
サービス:
名前: frontend
ポート:
番号: 80
パス: /
パスタイプ: プレフィックス
- ホスト: "api.example.com"
http:
パス:
- バックエンド:
サービス:
名前: api
ポート:
番号: 80
パス: /
パスタイプ: プレフィックス
$ kubectl apply -f 2-ingress.yaml ingress.networking.k8s.io/最初に作成された
Ingress 構成が期待どおりに動作していることを確認するには、一時的なポッドを使用してテストします。 クラスター内で使い捨てのBusyBoxポッドを起動します。
$ kubectl run -ti --rm=true busybox --image=busyboxコマンドプロンプトが表示されない場合は、Enterキーを押してみてください。 / #
ホスト名api.example.comを使用して NGINX Ingress Controller ポッドにリクエストを発行し、 Podinfo API をテストします。 表示される出力は、API がトラフィックを受信していることを示しています。
/ # wget --header="Host: api.example.com" -qO- main-nginx-ingress.nginx { "hostname": "api-687fd448f8-t7hqk", "version": "6.0.3", "リビジョン": "", "カラー": "#34577c", "ロゴ": "https://raw.githubusercontent.com/stefanprodan/podinfo/gh-pages/cuddle_clap.gif", "メッセージ": "podinfo v6.0.3 からの挨拶", "goos": "linux", "goarch": "arm64", "runtime": "go1.16.9", "num_goroutine": "6", "CPU数": "4" }
/ # wget --header="ホスト: example.com" --header="ユーザーエージェント: Mozilla" -qO- main-nginx-ingress.nginx <!DOCTYPE html>
<html>
<head>
<title>frontend-596d5c9ff4-xkbdc</title>
# ...
別のターミナルで、ブラウザで Podinfo を開きます。 podinfo ページからの挨拶は、 Podinfo が実行中であることを示します。
$ minikubeサービスpodinfo
おめでとう! NGINX Ingress Controller はリクエストを受信し、それをアプリと API に転送します。
元のターミナルで、BusyBox セッションを終了します。
/ #終了$
このチャレンジでは、オープンソースの負荷生成ツールであるLocust をインストールし、それを使用して、API を圧倒しアプリをクラッシュさせるトラフィックの急増をシミュレートします。
任意のテキスト エディターを使用して、次の内容を含む3-locust.yamlという YAML ファイルを作成します (またはGitHub からコピーします)。
ConfigMap
オブジェクトは、正しいヘッダーを備えたポッドに送信されるリクエストを生成するlocustfile.pyというスクリプトを定義します。 トラフィックはアプリと API の間で均等に分散されていません。リクエストはPodinfo APIに偏っており、5 件のリクエストのうち 1 件だけがPodinfo Frontendに送られます。
Deployment オブジェクト
とService
オブジェクトは Locust ポッドを定義します。
apiバージョン: v1
種類: ConfigMap
メタデータ:
名前: locust-script
データ:
locustfile.py: |-
from locust import HttpUser, task, between
class QuickstartUser(HttpUser):
wait_time = between(0.7, 1.3)
@task(1)
def visit_website(self):
with self.client.get("/", headers={"Host": "example.com", "User-Agent": "Mozilla"}、timeout=0.2、catch_response=True) をレスポンスとして:
if response.request_meta["response_time"] > 200:
response.failure("フロントエンドが失敗しました")
else:
response.success()
@task(5)
def visit_api(self):
with self.client.get("/", headers={"Host": "api.example.com"}、timeout=0.2) をレスポンスとして:
if response.request_meta["response_time"] > 200:
response.failure("API が失敗しました")
else:
response.success()
---
apiVersion: apps/v1
kind: デプロイメント
メタデータ:
名前: locust
仕様:
セレクタ:
matchLabels:
アプリ: locust
テンプレート:
メタデータ:
ラベル:
アプリ: locust
仕様:
コンテナ:
-名前: locust
イメージ: locustio/locust
ポート:
-コンテナポート: 8089
ボリュームマウント:
- マウントパス: /home/locust
名前: locust-script
ボリューム:
- 名前: locust-script
configMap:
名前: locust-script
---
apiVersion: v1
種類: サービス
メタデータ:
名前: locust
仕様:
ポート:
- ポート: 8089
ターゲットポート: 8089
ノードポート: 30015
セレクタ:
アプリ: locust
タイプ: ロードバランサー
ローカストを展開:
$ kubectl apply -f 3-locust.yaml configmap/locust-script が作成されました。deployment.apps/locust が作成されました。service/locust が作成されました。
kubectl
apply
コマンドのわずか数秒後に実行されたため、 STATUS
フィールドの Locust ポッドの値がContainerCreating である
ことからわかるように、インストールはまだ進行中です。 次のセクションに進む前に、値が実行中に
なるまで待ちます。 (読みやすくするために、出力は 2 行に分かれています。)$ kubectl get pods NAME READY STATUS ... api-7574cf7568-c6tr6 1/1 実行中 ... frontend-6688d86fc6-78qn7 1/1 実行中 ... locust-77c699c94d-hc76t 0/1 コンテナを作成中 ... ... 年齢をリスタート... 0 33分... 0 33分... 0 4秒
ブラウザで Locust を開きます。
$ minikube サービス イナゴ
フィールドに次の値を入力します。
「 Start swarming」ボタンをクリックして、トラフィックをPodinfo APIとPodinfo Frontendに送信します。 Locustチャートと障害タブでトラフィック パターンを観察します。
これは、API を使用する 1 人の悪意のある人物が API だけでなく、NGINX Ingress Controller によって提供されるすべてのアプリを停止できるため、問題となります。
最後のチャレンジでは、2 つの NGINX Ingress Controller をデプロイして、以前のデプロイの制限を排除し、それぞれに個別の名前空間を作成し、 Podinfo FrontendとPodinfo APIに個別の NGINX Ingress Controller インスタンスをインストールし、アプリと API のトラフィックをそれぞれの NGINX Ingress Controller に送信するように Locust を再構成して、レート制限が有効であることを確認します。 まず、アーキテクチャ上の問題にどのように対処するかを見てみましょう。 前回のチャレンジでは、API リクエストで NGINX Ingress コントローラーが過負荷になり、アプリにも影響が出ました。これは、単一の Ingress コントローラーが Web アプリ ( Podinfo Frontend ) と API ( Podinfo API ) の両方へのトラフィックのルーティングを担当していたために発生しました。
各サービスに対して個別の NGINX Ingress Controller ポッドを実行すると、過剰な API リクエストによってアプリが影響を受けるのを防ぐことができます。 これは必ずしもすべてのユースケースに必要なわけではありませんが、私たちのシミュレーションでは、複数の NGINX Ingress コントローラーを実行することの利点を簡単に確認できます。
Podinfo API が過負荷になるのを防ぐソリューションの 2 番目の部分は、NGINX Ingress Controller を API ゲートウェイとして使用してレート制限を実装することです。
レート制限は、ユーザーが特定の期間内に実行できるリクエストの数を制限します。 たとえば、DDoS 攻撃を軽減するには、レート制限を使用して、受信リクエスト レートを実際のユーザーの標準的な値に制限できます。 NGINX でレート制限が実装されている場合、リクエストを多数送信するクライアントはエラー ページにリダイレクトされるため、API に悪影響を与えることはありません。この仕組みについては、 NGINX Ingress Controller のドキュメントを参照してください。
API ゲートウェイは、クライアントからの API リクエストを適切なサービスにルーティングします。 この単純な定義の大きな誤解は、API ゲートウェイが独自のテクノロジーであるという点です。 そうではありません。 むしろ、「API ゲートウェイ」は、さまざまな種類のプロキシ (最も一般的なのは ADC またはロード バランサとリバース プロキシですが、Ingress コントローラやサービス メッシュも増えています) を介して実装できる一連のユース ケースを表します。 レート制限は、API ゲートウェイをデプロイする場合の一般的な使用例です。 KubernetesでのAPIゲートウェイのユースケースの詳細については、 どうやって選べばいいですか? API ゲートウェイ vs. Ingress コントローラー vs. サービスメッシュ 私たちのブログで。
新しいアーキテクチャとレート制限を実装する前に、以前の NGINX Ingress Controller 構成を削除する必要があります。
$ kubectl delete -f 2-ingress.yaml ingress.networking.k8s.io "first" を削除しました
Podinfo Frontend用にnginx‑webという名前空間を作成します。
$ kubectl create namespace nginx-web名前空間/nginx-web が作成されました
Podinfo API用にnginx‑apiという名前空間を作成します。
$ kubectl create namespace nginx-api名前空間/nginx-apiが作成されました
NGINX Ingress Controller をインストールします。
$ helm install web nginx-stable/nginx-ingress --set controller.ingressClass=nginx-web \ --set controller.service.type=NodePort \ --set controller.service.httpPort.nodePort=30020 \ --namespace nginx-web
Podinfo Frontend用の4-ingress-web.yamlという Ingress マニフェストを作成します (またはGitHub からコピーします)。
apiバージョン: k8s.nginx.org/v1 種類: ポリシーメタデータ: 名前: レート制限ポリシー 仕様: レート制限: レート: 10r/s キー: ${binary_remote_addr} ゾーンサイズ: 10M --- apiバージョン: k8s.nginx.org/v1 種類: 仮想サーバーのメタデータ: 名前: api-vs 仕様: ingressClassName: nginx-api ホスト: api.example.com ポリシー: - 名前: rate-limit-policy アップストリーム: - 名前: api サービス: api ポート: 80 ルート: - パス: / アクション: パス: api
新しいマニフェストをデプロイします。
$ kubectl apply -f 4-ingress-web.yaml ingress.networking.k8s.io/frontend が作成されました
次に、Locust を再構成し、次のことを確認します。
次の手順を実行します。
Locust スクリプトを次のように変更します。
Locust はダッシュボードで 1 つの URL のみをサポートするため、次の内容の YAML ファイル6-locust.yamlを使用して Python スクリプトに値をハードコードします (またはGitHub からコピーします)。 各タスク
の URL をメモします。
apiバージョン: v1
種類: ConfigMap
メタデータ:
名前: locust-script
データ:
locustfile.py: |-
from locust import HttpUser, task, between
class QuickstartUser(HttpUser):
wait_time = between(0.7, 1.3)
@task(1)
def visit_website(self):
with self.client.get("http://web-nginx-ingress.nginx-web/", headers={"Host": "example.com", "User-Agent": "Mozilla"}、timeout=0.2、catch_response=True) をレスポンスとして:
if response.request_meta["response_time"] > 200:
response.failure("フロントエンドが失敗しました")
else:
response.success()
@task(5)
def visit_api(self):
with self.client.get("http://api-nginx-ingress.nginx-api/", headers={"Host": "api.example.com"}、timeout=0.2) をレスポンスとして:
if response.request_meta["response_time"] > 200:
response.failure("API が失敗しました")
else:
response.success()
---
apiVersion: apps/v1
kind: デプロイメント
メタデータ:
名前: locust
仕様:
セレクタ:
matchLabels:
アプリ: locust
テンプレート:
メタデータ:
ラベル:
アプリ: locust
仕様:
コンテナ:
-名前: locust
イメージ: locustio/locust
ポート:
-コンテナポート: 8089
ボリュームマウント:
- マウントパス: /home/locust
名前: locust-script
ボリューム:
- 名前: locust-script
configMap:
名前: locust-script
---
apiVersion: v1
種類: サービス
メタデータ:
名前: locust
仕様:
ポート:
- ポート: 8089
ターゲットポート: 8089
ノードポート: 30015
セレクタ:
アプリ: locust
タイプ: ロードバランサー
新しい Locust 構成をデプロイします。 出力では、スクリプトが変更されたが、他の要素は変更されていないことが確認できます。
$ kubectl apply -f 6-locust.yaml configmap/locust-script を設定、deployment.apps/locust は変更なし、service/locust は変更なし
新しい ConfigMap を強制的にリロードするには、Locust ポッドを削除します。 削除するポッドを識別するために、 kubectl
delete
pod
コマンドの引数は、すべてのポッドのリストから Locust ポッドを選択するパイプ コマンドとして表現されます。
$ kubectl ポッドを削除 `kubectl ポッドを取得 | grep locust | awk {'print $1'}`
Locust がリロードされたことを確認します ( AGE
列の Locust ポッドの値は数秒のみです)。
$ kubectl get pods NAME READY STATUS ... api-7574cf7568-jrlvd 1/1 実行中 ... frontend-6688d86fc6-vd856 1/1 実行中 ... locust-77c699c94d-6chsg 0/1 実行中 ... ... 年齢をリスタート... 0 9分57秒... 0 9分57秒... 0 6秒
Locust に戻り、次のフィールドのパラメータを変更します。
「 Start swarming」ボタンをクリックして、トラフィックをPodinfo APIとPodinfo Frontendに送信します。
左上の Locust タイトル バーで、 STATUS列のユーザー数が増加すると、 FAILURES列の値も増加することがわかります。 ただし、API に設定されたレート制限により過剰なリクエストが拒否されるため、エラーはPodinfo フロントエンドからではなく、 Podinfo APIから発生するようになりました。 右下のトレースを見ると、NGINXがメッセージを返していることがわかります。503
サービスは
一時的に
利用できません
。これはレート制限機能の一部であり、カスタマイズ可能です。 API はレート制限されており、Web アプリケーションは常に利用可能です。 よくやった!
現実の世界では、レート制限だけでは、アプリや API を悪意のある行為者から保護するのに十分ではありません。 Kubernetes アプリ、API、インフラストラクチャを保護するには、次の方法のうち少なくとも 1 つまたは 2 つを実装する必要があります。
これらのトピックとその他のトピックについては、「マイクロサービス 2022 年 3 月 – Kubernetes のマイクロサービス セキュリティ パターン」のユニット 3 で取り上げます。 NGINX Plus および NGINX App Protect を搭載した NGINX Ingress Controller for Kubernetes を試すには、今すぐ30 日間の無料トライアルを開始するか、お問い合わせの上、ユースケースについてご相談ください。 NGINX Open Source で NGINX Ingress Controller を試すには、リリース ソース コードを入手するか、 DockerHubからビルド済みコンテナーをダウンロードします。
「このブログ投稿には、入手できなくなった製品やサポートされなくなった製品が参照されている場合があります。 利用可能な F5 NGINX 製品およびソリューションに関する最新情報については、 NGINX 製品ファミリーをご覧ください。 NGINX は現在 F5 の一部です。 以前の NGINX.com リンクはすべて、F5.com の同様の NGINX コンテンツにリダイレクトされます。"