このチュートリアルは、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 🏄 Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default
Podinfo は、 「Kubernetes でマイクロサービスを実行するためのベスト プラクティスを紹介する、Go で作成された Web アプリケーション」です。 フットプリントが小さいため、サンプル アプリと API として使用しています。
任意のテキスト エディターを使用して、次の内容を含む1-apps.yamlという YAML ファイルを作成します (またはGitHub からコピーします)。 以下を含むデプロイメントを定義します。
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: stefanprodan/podinfo
ports:
- containerPort: 9898
---
apiVersion: v1
kind: Service
metadata:
name: api
spec:
ports:
- port: 80
targetPort: 9898
nodePort: 30001
selector:
app: api
type: LoadBalancer
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: frontend
image: stefanprodan/podinfo
ports:
- containerPort: 9898
---
apiVersion: v1
kind: Service
metadata:
name: frontend
spec:
ports:
- port: 80
targetPort: 9898
nodePort: 30002
selector:
app: frontend
type: LoadBalancer
アプリと API をデプロイします。
$ kubectl apply -f 1-apps.yamldeployment.apps/api created
service/api created
deployment.apps/frontend created
service/frontend created
STATUS
列の値がRunning で
あることから、 Podinfo APIおよびPodinfo Frontendのポッドが正常にデプロイされたことを確認します。
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
api-7574cf7568-c6tr6 1/1 Running 0 87s
frontend-6688d86fc6-78qn7 1/1 Running 0 87s
NGINX Ingress Controller をインストールする最も速い方法は、 Helmを使用することです。
Helm を使用して、 NGINX Ingress Controller を別の名前空間 ( nginx ) にインストールします。
名前空間を作成します。
$ kubectl create namespace nginx
NGINX リポジトリを Helm に追加します。
$ helm repo add 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 Running ...
... RESTARTS AGE
... 0 92s
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: first
spec:
ingressClassName: nginx
rules:
- host: "example.com"
http:
paths:
- backend:
service:
name: frontend
port:
number: 80
path: /
pathType: Prefix
- host: "api.example.com"
http:
paths:
- backend:
service:
name: api
port:
number: 80
path: /
pathType: Prefix
$ kubectl apply -f 2-ingress.yaml ingress.networking.k8s.io/first created
Ingress 構成が期待どおりに動作していることを確認するには、一時的なポッドを使用してテストします。 クラスター内で使い捨てのBusyBoxポッドを起動します。
$ kubectl run -ti --rm=true busybox --image=busybox If you don't see a command prompt, try pressing 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",
"revision": "",
"color": "#34577c",
"logo": "https://raw.githubusercontent.com/stefanprodan/podinfo/gh-pages/cuddle_clap.gif",
"message": "greetings from podinfo v6.0.3",
"goos": "linux",
"goarch": "arm64",
"runtime": "go1.16.9",
"num_goroutine": "6",
"num_cpu": "4"
}
/ # wget --header="Host: example.com" --header="User-Agent: Mozilla" -qO- main-nginx-ingress.nginx <!DOCTYPE html>
<html>
<head>
<title>frontend-596d5c9ff4-xkbdc</title>
# ...
別のターミナルで、ブラウザで Podinfo を開きます。 podinfo ページからの挨拶は、 Podinfo が実行中であることを示します。
$ minikube service podinfo
おめでとう! NGINX Ingress Controller はリクエストを受信し、それをアプリと API に転送します。
元のターミナルで、BusyBox セッションを終了します。
/ # exit
$
このチャレンジでは、オープンソースの負荷生成ツールであるLocust をインストールし、それを使用して、API を圧倒しアプリをクラッシュさせるトラフィックの急増をシミュレートします。
任意のテキスト エディターを使用して、次の内容を含む3-locust.yamlという YAML ファイルを作成します (またはGitHub からコピーします)。
ConfigMap
オブジェクトは、正しいヘッダーを備えたポッドに送信されるリクエストを生成するlocustfile.pyというスクリプトを定義します。 トラフィックはアプリと API の間で均等に分散されていません。リクエストはPodinfo APIに偏っており、5 件のリクエストのうち 1 件だけがPodinfo Frontendに送られます。
Deployment オブジェクト
とService
オブジェクトは Locust ポッドを定義します。
apiVersion: v1
kind: ConfigMap
metadata:
name: locust-script
data:
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) as response:
if response.request_meta["response_time"] > 200:
response.failure("Frontend failed")
else:
response.success()
@task(5)
def visit_api(self):
with self.client.get("/", headers={"Host": "api.example.com"}, timeout=0.2) as response:
if response.request_meta["response_time"] > 200:
response.failure("API failed")
else:
response.success()
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: locust
spec:
selector:
matchLabels:
app: locust
template:
metadata:
labels:
app: locust
spec:
containers:
- name: locust
image: locustio/locust
ports:
- containerPort: 8089
volumeMounts:
- mountPath: /home/locust
name: locust-script
volumes:
- name: locust-script
configMap:
name: locust-script
---
apiVersion: v1
kind: Service
metadata:
name: locust
spec:
ports:
- port: 8089
targetPort: 8089
nodePort: 30015
selector:
app: locust
type: LoadBalancer
ローカストを展開:
$ kubectl apply -f 3-locust.yaml configmap/locust-script created
deployment.apps/locust created
service/locust created
kubectl
apply
コマンドのわずか数秒後に実行されたため、 STATUS
フィールドの Locust ポッドの値がContainerCreating である
ことからわかるように、インストールはまだ進行中です。 次のセクションに進む前に、値が実行中に
なるまで待ちます。 (読みやすくするために、出力は 2 行に分かれています。)$ kubectl get pods
NAME READY STATUS ... api-7574cf7568-c6tr6 1/1 Running ...
frontend-6688d86fc6-78qn7 1/1 Running ... locust-77c699c94d-hc76t 0/1 ContainerCreating ...
... RESTARTS AGE
... 0 33m
... 0 33m
... 0 4s
ブラウザで Locust を開きます。
$ minikube service locust
フィールドに次の値を入力します。
「 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" deleted
Podinfo Frontend用にnginx‑webという名前空間を作成します。
$ kubectl create namespace nginx-web
namespace/nginx-web created
Podinfo API用にnginx‑apiという名前空間を作成します。
$ kubectl create namespace nginx-api
namespace/nginx-api created
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 種類: ポリシーメタデータ: 名前: レート制限ポリシー 仕様: rateLimit: レート: 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 created
次に、Locust を再構成し、次のことを確認します。
次の手順を実行します。
Locust スクリプトを次のように変更します。
Locust はダッシュボードで 1 つの URL のみをサポートするため、次の内容の YAML ファイル6-locust.yamlを使用して Python スクリプトに値をハードコードします (またはGitHub からコピーします)。 各タスク
の URL をメモします。
apiVersion: v1
kind: ConfigMap
metadata:
name: locust-script
data:
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) as response:
if response.request_meta["response_time"] > 200:
response.failure("Frontend failed")
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) as response:
if response.request_meta["response_time"] > 200:
response.failure("API failed")
else:
response.success()
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: locust
spec:
selector:
matchLabels:
app: locust
template:
metadata:
labels:
app: locust
spec:
containers:
- name: locust
image: locustio/locust
ports:
- containerPort: 8089
volumeMounts:
- mountPath: /home/locust
name: locust-script
volumes:
- name: locust-script
configMap:
name: locust-script
---
apiVersion: v1
kind: Service
metadata:
name: locust
spec:
ports:
- port: 8089
targetPort: 8089
nodePort: 30015
selector:
app: locust
type: LoadBalancer
新しい Locust 構成をデプロイします。 出力では、スクリプトが変更されたが、他の要素は変更されていないことが確認できます。
$ kubectl apply -f 6-locust.yaml
configmap/locust-script configured
deployment.apps/locust unchanged
service/locust unchanged
新しい ConfigMap を強制的にリロードするには、Locust ポッドを削除します。 削除するポッドを識別するために、 kubectl
delete
pod
コマンドの引数は、すべてのポッドのリストから Locust ポッドを選択するパイプ コマンドとして表現されます。
$ kubectl delete pod `kubectl get pods | grep locust | awk {'print $1'}`
Locust がリロードされたことを確認します ( AGE
列の Locust ポッドの値は数秒のみです)。
$ kubectl get pods
NAME READY STATUS ... api-7574cf7568-jrlvd 1/1 Running ...
frontend-6688d86fc6-vd856 1/1 Running ... locust-77c699c94d-6chsg 0/1 Running ...
... RESTARTS AGE
... 0 9m57s
... 0 9m57s
... 0 6s
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 の一部です。 q。"