編集者– この投稿は10 部構成のシリーズの一部です。
また、ブログの完全セットを無料の電子書籍「 Taking Kubernetes from Test to Production」としてダウンロードすることもできます。
コンテナ化されたアプリケーションを本番環境で実行する企業が増えるにつれて、Kubernetes はコンテナ オーケストレーションの標準ツールとしての地位を固め続けています。 同時に、COVID-19パンデミックによる在宅勤務の取り組みによりインターネットトラフィックの増加が加速したため、クラウドコンピューティングの需要は数年早まっています。 顧客が大規模なネットワーク障害や過負荷を経験しているため、企業はインフラストラクチャのアップグレードに急いで取り組んでいます。
クラウドベースのマイクロサービス環境で必要なレベルのパフォーマンスを達成するには、次世代のハイパースケール データ センターの拡張性とパフォーマンスを活用する、高速で完全に動的なソフトウェアが必要です。 Kubernetes を使用してコンテナを管理する多くの組織は、NGINX ベースの Ingress コントローラーを使用してユーザーにアプリを配信しています。
このブログでは、現実的なマルチクラウド環境における 3 つの NGINX Ingress コントローラーのパフォーマンス テストの結果を報告し、インターネット経由のクライアント接続のレイテンシを測定します。
負荷生成プログラムwrk2 を
使用してクライアントをエミュレートし、定義された期間に HTTPS 経由で継続的にリクエストを送信しました。 テスト対象の Ingress コントローラー (コミュニティ Ingress コントローラー、NGINX Open Source に基づく NGINX Ingress コントローラー、または NGINX Plus に基づく NGINX Ingress コントローラー) は、Kubernetes Pod にデプロイされたバックエンド アプリケーションにリクエストを転送し、アプリケーションによって生成された応答をクライアントに返しました。 Ingress コントローラのストレステストを行うために、クライアント トラフィックの安定したフローを生成し、次のパフォーマンス メトリックを収集しました。
すべてのテストでは、AWS のクライアントマシンで実行されているwrk2
ユーティリティを使用してリクエストを生成しました。 AWS クライアントは、Google Kubernetes Engine (GKE) 環境のGKE-node-1に Kubernetes DaemonSetとしてデプロイされた Ingress コントローラの外部 IP アドレスに接続しました。 Ingress コントローラーは、SSL ターミネーション (Kubernetes Secretを参照) とレイヤー 7 ルーティング用に設定され、タイプ
LoadBalancer
の Kubernetesサービスを介して公開されました。 バックエンド アプリケーションは、GKE-node-2上の Kubernetes Deploymentとして実行されました。
クラウド マシンの種類とソフトウェア構成の詳細については、付録を参照してください。
AWS クライアントマシンで次のwrk2
(バージョン 4.0.0) スクリプトを実行しました。 2 つのwrk
スレッドが生成され、それらが一緒に GKE にデプロイされた Ingress コントローラへの 1000 の接続を確立します。 3 分間のテスト実行ごとに、スクリプトは 1 秒あたり 30,000 件のリクエスト (RPS) を生成します。これは、実稼働環境の Ingress コントローラーにかかる負荷を適切にシミュレートしていると考えられます。
wrk -t2 -c1000 -d180s -L -R30000 https://app.example.com:443/
どこ:
-t
– スレッド数を設定する (2)-c
– TCP接続数を設定します(1000)-d
– テスト実行の継続時間を秒単位で設定します(180、つまり3分)-L
– 分析ツールにエクスポートするための詳細なレイテンシパーセンタイル情報を生成します-R
– RPSの数を設定します(30,000)TLS 暗号化には、 2048 ビットのキー サイズと Perfect Forward Secrecy を備えた RSA を使用しました。
バックエンドアプリケーション( https://app.example.com:443でアクセス)からの各応答は、約1KBの基本的なサーバーメタデータと、 200
OK
HTTP ステータス コード。
バックエンド アプリケーションの静的デプロイメントと動的デプロイメントの両方でテスト実行を実施しました。
静的デプロイメントでは、5 つの Pod レプリカがあり、Kubernetes API を使用して変更は適用されませんでした。
動的デプロイメントでは、次のスクリプトを使用して、バックエンドのnginxデプロイメントを 5 つの Pod レプリカから 7 つに定期的にスケールし、その後 5 つに戻しました。 これは動的な Kubernetes 環境をエミュレートし、Ingress コントローラーがエンドポイントの変更にどれだけ効果的に適応するかをテストします。
while [ 1 -eq 1 ]
do
kubectl scale deploy nginx --replicas=5
sleep 12
kubectl scale deploy nginx --replicas=7
sleep 10
done
グラフに示されているように、3 つの Ingress コントローラはすべて、バックエンド アプリケーションの静的デプロイメントで同様のパフォーマンスを達成しました。 これらはすべて NGINX オープンソースに基づいており、静的デプロイメントでは Ingress コントローラーから再構成する必要がないことを考えると、これは理にかなっています。
このグラフは、バックエンド アプリケーションを 5 つのレプリカ ポッドから 7 つまで定期的にスケーリングした動的デプロイメントで、各 Ingress コントローラによって発生したレイテンシを示しています (詳細については、 「バックエンド アプリケーションのデプロイメント」を参照してください)。
この環境では、 NGINX Plus ベースのIngress コントローラーだけが優れたパフォーマンスを発揮し、99.99 パーセンタイルまで実質的に遅延が発生しないことは明らかです。 コミュニティと NGINX オープンソース ベースの Ingress コントローラーはどちらも、かなり低いパーセンタイルで顕著な遅延が発生しますが、パターンはかなり異なります。 コミュニティ Ingress コントローラーの場合、レイテンシは緩やかに、しかし着実に 99 パーセンタイルまで上昇し、そこで約 5000 ミリ秒 (5 秒) で安定します。 NGINX オープンソースベースの Ingress コントローラの場合、レイテンシは 99 パーセンタイルで約 32 秒に急上昇し、99.99 パーセンタイルでは再び60 秒に上昇します。
「動的デプロイメントのタイムアウトとエラー結果」でさらに説明するように、コミュニティと NGINX オープンソースベースの Ingress コントローラーで発生する遅延は、バックエンド アプリケーションのエンドポイントの変更に応じて NGINX 構成が更新および再ロードされた後に発生するエラーとタイムアウトによって発生します。
以下は、前のグラフと同じテスト条件でのコミュニティ Ingress コントローラーとNGINX Plus ベースのIngress コントローラーの結果の詳細なビューです。 NGINX Plus ベースのIngress コントローラーは、99.99 パーセンタイルまでは実質的に遅延が発生しませんが、99.9999 パーセンタイルでは 254 ミリ秒に向かって上昇し始めます。 コミュニティ Ingress コントローラーのレイテンシ パターンは、99 パーセンタイルで 5000 ミリ秒のレイテンシまで着実に増加し、その時点でレイテンシは安定します。
この表には、遅延結果の原因がより詳しく示されています。
NGINX オープンソース | コミュニティ | NGINX プラス | |
---|---|---|---|
接続エラー | 33365 | 0 | 0 |
接続タイムアウト | 309 | 8809 | 0 |
読み取りエラー | 4650 | 0 | 0 |
NGINX オープンソース ベースの Ingress コントローラーでは、バックエンド アプリケーションのエンドポイントが変更されるたびに NGINX 構成を更新して再ロードする必要があるため、多くの接続エラー、接続タイムアウト、読み取りエラーが発生します。 接続/ソケット エラーは、NGINX がリロードするのにかかる短い時間の間に、クライアントが NGINX プロセスに割り当てられなくなったソケットに接続しようとすると発生します。 接続タイムアウトは、クライアントが Ingress コントローラーへの接続を確立したが、バックエンド エンドポイントが利用できなくなった場合に発生します。 エラーとタイムアウトはどちらもレイテンシに重大な影響を及ぼし、99 パーセンタイルでは 32 秒、99.99 パーセンタイルでは再び60 秒に急上昇します。
コミュニティ Ingress コントローラーでは、バックエンド アプリケーションのスケールアップとスケールダウンに伴うエンドポイントの変更により、8,809 回の接続タイムアウトが発生しました。 コミュニティ Ingress コントローラーは、エンドポイントが変更されたときに構成の再読み込みを回避するために Lua コードを使用します。 結果は、NGINX 内で Lua ハンドラーを実行してエンドポイントの変更を検出すると、エンドポイントを変更するたびに構成を再ロードする必要があることから生じる NGINX オープンソース ベース バージョンのパフォーマンス制限の一部に対処できることを示しています。 それでも、接続タイムアウトは依然として発生し、高いパーセンタイルでは大きな遅延が発生します。
NGINX Plus ベースのIngress コントローラーでは、エラーやタイムアウトは発生せず、動的環境はパフォーマンスにほとんど影響を与えませんでした。 これは、エンドポイントが変更されたときに NGINX Plus API を使用して NGINX 構成を動的に更新するためです。 前述のように、最高のレイテンシは 254 ミリ秒で、99.9999 パーセンタイルでのみ発生しました。
パフォーマンス結果から、動的な Kubernetes クラウド環境でタイムアウトとエラーを完全に排除するには、Ingress コントローラーがイベント ハンドラーや構成の再読み込みなしでバックエンド エンドポイントの変更に動的に調整する必要があることがわかります。 結果に基づくと、 NGINX Plus API は、動的な環境で NGINX を動的に再構成するための最適なソリューションであると言えます。 私たちのテストでは、 NGINX Plus ベースのIngress コントローラーのみが、ユーザーの満足を維持するために必要な、高度に動的な Kubernetes 環境で完璧なパフォーマンスを達成しました。
機械 | クラウドプロバイダー | マシンタイプ |
---|---|---|
クライアント | アマゾン | m5a.4xlarge |
GKE ノード 1 | グーグル | e2-標準-32 |
GKE ノード 2 | グーグル | e2-標準-32 |
apiバージョン: apps/v1
種類: DaemonSet
メタデータ:
名前: nginx-ingress
名前空間: nginx-ingress
仕様:
セレクター:
matchLabels:
アプリ: nginx-ingress
テンプレート:
メタデータ:
ラベル:
アプリ: nginx-ingress
#アノテーション:
#prometheus.io/scrape: "true"
#prometheus.io/port: "9113"
仕様:
サービス アカウント名: nginx-ingress
ノード セレクター:
kubernetes.io/ホスト名: gke-rawdata-cluster-default-pool-3ac53622-6nzr
ホスト ネットワーク: true
コンテナ:
-イメージ: gcr.io/nginx-demos/nap-ingress:edge
イメージ プル ポリシー: 常に
名前: nginx-plus-ingress
ポート:
- 名前: http
コンテナポート: 80
ホストポート: 80
- 名前: https
コンテナポート: 443
ホストポート: 443
- 名前: 準備ポート
コンテナポート: 8081
#- 名前: プロメテウス
# コンテナポート: 9113
readinessProbe:
httpGet:
パス: /nginx-ready
ポート: readiness-port
periodSeconds: 1
securityContext:
allowPrivilegeEscalation: true
runAsUser: 101 #nginx
機能:
削除:
- ALL
追加:
- NET_BIND_SERVICE
環境:
- 名前: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- 名前: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
args:
- -nginx-plus
- -nginx-configmaps=$(POD_NAMESPACE)/nginx-config
- -default-server-tls-secret=$(POD_NAMESPACE)/default-server-secret
注:
nginx‑plus
への参照が調整されました。gcr.io/nginx-demos/nap-ingress:edge
) に含まれていますが、無効になっています ( -enable-app-protect
フラグが省略されています)。親切: ConfigMap
apiVersion: v1
メタデータ:
名前: nginx-config
名前空間: nginx-ingress
データ:
ワーカー接続: 「10000」
ワーカー制限なしファイル: 「10240」
キープアライブ: 「100」
キープアライブ要求: 「100000000」
apiバージョン: apps/v1
種類: DaemonSet
メタデータ:
ラベル:
helm.sh/chart: ingress-nginx-2.11.1
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/version: 0.34.1 app.kubernetes.io/maned-by: Helm
app.kubernetes.io/component: controller
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
selector:
matchLabels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/component: controller
template:
metadata:
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/component: controller
spec:
nodeSelector:
kubernetes.io/hostname: gke-rawdata-cluster-default-pool-3ac53622-6nzr
hostNetwork: true
containers:
- name: controller
image: us.gcr.io/k8s-artifacts-prod/ingress-nginx/controller:v0.34.1@sha256:0e072dddd1f7f8fc8909a2ca6f65e76c5f0d2fcfb8be47935ae3457e8bbceb20
イメージプルポリシー: IfNotPresent
ライフサイクル:
preStop:
exec:
コマンド:
- /wait-shutdown
引数:
- /nginx-ingress-controller
- --election-id=ingress-controller-leader
- --ingress-class=nginx
- --configmap=$(POD_NAMESPACE)/ingress-nginx-controller
- --validating-webhook=:8443
- --validating-webhook-certificate=/usr/local/certificates/cert
- --validating-webhook-key=/usr/local/certificates/key
securityContext:
機能:
ドロップ:
- ALL
追加:
- NET_BIND_SERVICE
runAsUser: 101
allowPrivilegeEscalation: true
env:
- 名前: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
readinessProbe:
httpGet:
path: /healthz
port: 10254
スキーム: HTTP
期間秒数: 1
ポート:
- 名前: http
コンテナポート: 80
プロトコル: TCP
- 名前: https
コンテナポート: 443
プロトコル: TCP
- 名前: webhook
コンテナポート: 8443
プロトコル: TCP
ボリュームマウント:
-名前: webhook-cert
マウントパス: /usr/local/certificates/
読み取り専用: true
サービスアカウント名: ingress-nginx
終了GracePeriodSeconds: 300
ボリューム:
- 名前: webhook-cert
シークレット:
シークレット名: ingress-nginx-admission
apiバージョン: v1
種類: ConfigMap
メタデータ:
名前: ingress-nginx-controller
名前空間: ingress-nginx
データ:
max-worker-connections: 「10000」
ワーカーが開くファイルの最大数: 「10204」
アップストリーム キープアライブ接続: 「100」
キープアライブリクエスト: 「100000000」
apiバージョン: apps/v1
種類: デプロイメント
メタデータ:
名前: nginx
仕様:
セレクター:
matchLabels:
アプリ: nginx
テンプレート:
メタデータ:
ラベル:
アプリ: nginx
仕様:
ノードセレクター:
kubernetes.io/hostname: gke-rawdata-cluster-default-pool-3ac53622-t2dz
コンテナ:
- 名前: nginx
イメージ: nginx
ポート:
- コンテナポート: 8080
volumeMounts:
- 名前: main-config-volume
mountPath: /etc/nginx
- 名前: app-config-volume
mountPath: /etc/nginx/conf.d
readinessProbe:
httpGet:
パス: /healthz
ポート: 8080
期間秒数: 3
ボリューム:
- 名前: main-config-volume
configMap:
名前: main-conf
- 名前: app-config-volume
configMap:
名前: app-conf
---
apiバージョン: v1
種類: ConfigMap
メタデータ:
名前: main-conf
名前空間: default
データ:
nginx.conf: |+
user nginx;
worker_processes 16;
worker_rlimit_nofile 102400;
worker_cpu_affinity auto 1111111111111111;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 100000;
}
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
sendfile on;
tcp_nodelay オン;
access_log オフ;
/etc/nginx/conf.d/*.conf をインクルードします;
}
---
apiVersion: v1
kind: ConfigMap
メタデータ:
名前: app-conf
名前空間: default
データ:
app.conf: "server {listen 8080;location / {default_type text/plain;expires -1;return 200 'サーバー アドレス: $server_addr:$server_port\nサーバー名:$hostname\n日付: $time_local\nURI: $request_uri\nリクエスト ID: $request_id\n';}location /healthz {return 200 '私は幸せで健康です :)';}}"
---
apiバージョン: v1
種類: サービス
メタデータ:
名前: app-svc
仕様:
ポート:
- ポート: 80
ターゲットポート: 8080
プロトコル: TCP
名前: http
セレクタ:
アプリ: nginx
---
「このブログ投稿には、入手できなくなった製品やサポートされなくなった製品が参照されている場合があります。 利用可能な F5 NGINX 製品およびソリューションに関する最新情報については、 NGINX 製品ファミリーをご覧ください。 NGINX は現在 F5 の一部です。 以前の NGINX.com リンクはすべて、F5.com の同様の NGINX コンテンツにリダイレクトされます。"