編集者– この投稿は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 deployment nginx --replicas=5
sleep 12
kubectl scale deployment 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 |
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nginx-ingress
namespace: nginx-ingress
spec:
selector:
matchLabels:
app: nginx-ingress
template:
metadata:
labels:
app: nginx-ingress
#annotations:
#prometheus.io/scrape: "true"
#prometheus.io/port: "9113"
spec:
serviceAccountName: nginx-ingress
nodeSelector:
kubernetes.io/hostname: gke-rawdata-cluster-default-pool-3ac53622-6nzr
hostNetwork: true
containers:
- image: gcr.io/nginx-demos/nap-ingress:edge
imagePullPolicy: Always
name: nginx-plus-ingress
ports:
- name: http
containerPort: 80
hostPort: 80
- name: https
containerPort: 443
hostPort: 443
- name: readiness-port
containerPort: 8081
#- name: prometheus
#containerPort: 9113
readinessProbe:
httpGet:
path: /nginx-ready
port: readiness-port
periodSeconds: 1
securityContext:
allowPrivilegeEscalation: true
runAsUser: 101 #nginx
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: 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
フラグが省略されています)。kind: ConfigMap
apiVersion: v1
metadata:
name: nginx-config
namespace: nginx-ingress
data:
worker-connections: "10000"
worker-rlimit-nofile: "10240"
keepalive: "100"
keepalive-requests: "100000000"
apiVersion: apps/v1
kind: DaemonSet
metadata:
labels:
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/managed-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
imagePullPolicy: IfNotPresent
lifecycle:
preStop:
exec:
command:
- /wait-shutdown
args:
- /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:
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
runAsUser: 101
allowPrivilegeEscalation: true
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
readinessProbe:
httpGet:
path: /healthz
port: 10254
scheme: HTTP
periodSeconds: 1
ports:
- name: http
containerPort: 80
protocol: TCP
- name: https
containerPort: 443
protocol: TCP
- name: webhook
containerPort: 8443
protocol: TCP
volumeMounts:
- name: webhook-cert
mountPath: /usr/local/certificates/
readOnly: true
serviceAccountName: ingress-nginx
terminationGracePeriodSeconds: 300
volumes:
- name: webhook-cert
secret:
secretName: ingress-nginx-admission
apiVersion: v1
kind: ConfigMap
metadata:
name: ingress-nginx-controller
namespace: ingress-nginx
data:
max-worker-connections: "10000"
max-worker-open-files: "10204"
upstream-keepalive-connections: "100"
keep-alive-requests: "100000000"
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
nodeSelector:
kubernetes.io/hostname: gke-rawdata-cluster-default-pool-3ac53622-t2dz
containers:
- name: nginx
image: nginx
ports:
- containerPort: 8080
volumeMounts:
- name: main-config-volume
mountPath: /etc/nginx
- name: app-config-volume
mountPath: /etc/nginx/conf.d
readinessProbe:
httpGet:
path: /healthz
port: 8080
periodSeconds: 3
volumes:
- name: main-config-volume
configMap:
name: main-conf
- name: app-config-volume
configMap:
name: app-conf
---
apiVersion: v1
kind: ConfigMap
metadata:
name: main-conf
namespace: default
data:
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 on;
access_log off;
include /etc/nginx/conf.d/*.conf;
}
---
apiVersion: v1
kind: ConfigMap
metadata:
name: app-conf
namespace: default
data:
app.conf: "server {listen 8080;location / {default_type text/plain;expires -1;return 200 'Server address: $server_addr:$server_port\nServer name:$hostname\nDate: $time_local\nURI: $request_uri\nRequest ID: $request_id\n';}location /healthz {return 200 'I am happy and healthy :)';}}"
---
apiVersion: v1
kind: Service
metadata:
name: app-svc
spec:
ports:
- port: 80
targetPort: 8080
protocol: TCP
name: http
selector:
app: nginx
---
「このブログ投稿には、入手できなくなった製品やサポートされなくなった製品が参照されている場合があります。 利用可能な F5 NGINX 製品およびソリューションに関する最新情報については、 NGINX 製品ファミリーをご覧ください。 NGINX は現在 F5 の一部です。 q。"