NGINXチュートリアル:オートスケーリングでKubernetesのレイテンシを低減

NGINX | 2022年3月15日

このチュートリアルは、「Microservices March 2022: Kubernetes Networking」の概念を実践する4つのチュートリアルのうちの1つです:

NGINXをさらに多くのKubernetesネットワーキングのユースケースで活用するための詳しいガイダンスをお探しですか?無料のeBook「Managing Kubernetes Traffic with NGINX: 実践ガイド」をダウンロードしてください。

組織でKubernetes上に構築したアプリが、今や人気を集めています。1日あたりの訪問者数は、わずか数人から数百人(時には数千人)にまで増えました。しかし、問題があります……増加したトラフィックがボトルネックに達し、ユーザー側で遅延やタイムアウトが発生しています。ユーザー体験を改善できなければ、アプリは使われなくなってしまいます。

皆さんには、勇敢なKubernetesエンジニアとして解決策があります。Ingress controllerをデプロイしてトラフィックをルーティングし、トラフィックの変動に応じてIngress controllerのPod数が即座に増減するよう、オートスケーリングポリシーを設定します。これで、Ingress controllerのPodはトラフィックの急増にもスムーズに対応でき、「レイテンシーにさようなら!」。トラフィックが減少すればスケールダウンしてリソースを節約でき、「コスト削減にこんにちは!」。お見事です。

ラボとチュートリアルの概要

このブログは、Microservices March 2022のユニット1のラボ「高トラフィックWebサイト向けKubernetesクラスターの設計」に対応しています。NGINX Ingress Controllerを使用してアプリを公開し、高トラフィックに応じてIngress Controller Podを自動スケーリングする方法を紹介します。

このチュートリアルを実行するには、以下を備えたマシンが必要です。

  • 2 CPU以上
  • 2 GBの空きメモリ
  • 20 GBの空きディスク容量
  • インターネット接続
  • Docker、Hyperkit、Hyper‑V、KVM、Parallels、Podman、VirtualBox、VMware Fusion/Workstationなどのコンテナまたは仮想マシンマネージャー
  • minikubeがインストールされていること
  • Helmがインストール済み
  • ブラウザーウィンドウを起動できる構成。起動できない場合は、ブラウザーから該当するサービスにアクセスする方法を確認する必要があります。

ラボとチュートリアルを最大限に活用するため、開始前に以下の準備を行うことを推奨します。

このチュートリアルでは、以下のテクノロジーを使用します。

各チャレンジの手順には、アプリの設定に使用するYAMLファイルの全文が含まれています。また、F5のGitHubリポジトリからテキストをコピーすることもできます。各YAMLファイルのテキストには、GitHubへのリンクも併記されています。

このチュートリアルには、4つの課題が含まれています。

  1. Kubernetesクラスター上でシンプルなアプリを構成する
  2. NGINX Ingress Controllerを使用してアプリにトラフィックをルーティングする
  3. トラフィックの生成と監視
  4. NGINX Ingress Controllerを自動スケーリング

チャレンジ1:Kubernetesクラスターにシンプルなアプリを構成する

このチャレンジでは、minikubeクラスターを作成し、サンプルアプリとしてPodinfoをインストールします。

Minikubeクラスターの作成

Create a minikubeクラスターを作成します。数秒後、デプロイが成功したことを示すメッセージが表示されます。

$ minikube start 🏄  Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default 

Podinfoアプリのインストール

Podinfoは、「Kubernetesでマイクロサービスを実行するためのベストプラクティスを紹介する、Goで作成されたWebアプリケーション」です。フットプリントが小さいため、サンプルアプリとして使用します。

  1. 任意のテキストエディターを使用して、以下の内容で「1-deployment.yaml」というYAMLファイルを作成します(または、GitHubからコピーします)。このファイルでは、レプリカが1つのDeploymentとServiceを定義します。
apiVersion: apps/v1 kind: Deployment 
metadata: 
  name: podinfo 
spec: 
  selector: 
    matchLabels: 
      app: podinfo 
  template: 
    metadata: 
      labels: 
        app: podinfo 
    spec: 
      containers: 
      - name: podinfo 
        image: stefanprodan/podinfo 
        ports: 
        - containerPort: 9898 
--- 
apiVersion: v1 
kind: Service 
metadata: 
  name: podinfo 
spec: 
  ports: 
    - port: 80 
      targetPort: 9898 
      nodePort: 30001 
  selector: 
    app: podinfo 
  type: LoadBalancer 
  1. アプリをデプロイします:
$ kubectl apply -f 1-deployment.yaml deployment.apps/podinfo created 
service/podinfo created
  1. Podinfo Podがデプロイされ、Running列の値がSTATUSになっていることを確認します。
$ kubectl get podsNAME                       READY   STATUS   RESTARTS   AGE 
podinfo-5d76864686-rd2s5   1/1     Running  0          3m38s
  1. ブラウザーでPodinfoを開きます。「greetings from podinfo」ページが表示されれば、Podinfoは稼働しています。
$ minikube service podinfo

課題2:NGINX Ingress Controllerを使用してトラフィックをアプリにルーティングする

この課題では、NGINX Ingress Controllerをデプロイし、Podinfoアプリにトラフィックをルーティングするように設定します。

NGINX Ingress Controllerをデプロイ

NGINX Ingress Controllerを最も迅速にインストールするには、Helmを使用します。

  1. NGINXリポジトリをHelmに追加します:
$ helm repo add nginx-stable https://helm.nginx.com/stable 
  1. NGINX Open SourceベースのNGINX Ingress Controller(F5 NGINXが保守)をダウンロードしてインストールします。出力の最終行で、インストールが正常に完了したことを確認できます。
$ helm install main nginx-stable/nginx-ingress \ --set controller.watchIngressWithoutClass=true \ --set controller.service.type=NodePort \ --set controller.service.httpPort.nodePort=30005 
NAME: main 
LAST DEPLOYED: Tue Mar 15 09:49:17 2022 
NAMESPACE: default 
STATUS: deployed 
REVISION: 1 
TEST SUITE: None 
NOTES: The NGINX Ingress Controller has been installed.
  1. NGINX Ingress Controllerポッドがデプロイされたことを、RunningがSTATUS列に表示されていることで確認します(読みやすくするため、出力は2行に分けています)。
$ kubectl get podsNAME                                   READY   STATUS    ...
main-nginx-ingress-779b74bb8b-mtdkr    1/1     Running   ...
podinfo-5d76864686-fjncl               1/1     Running   ...

       ... RESTARTS   AGE
       ... 0          18s 
       ... 0        2m36s

トラフィックをアプリにルーティング

  1. 任意のテキストエディターを使用して、以下の内容で「2-ingress.yaml」というYAMLファイルを作成します(または、GitHubからコピーします)。このファイルでは、Podinfoにトラフィックをルーティングするために必要なIngressマニフェストを定義します。
apiVersion: networking.k8s.io/v1 kind: Ingress 
metadata: 
  name: podinfo 
spec: 
  ingressClassName: nginx 
  rules: 
    - host: "example.com" 
      http: 
        paths: 
          - backend: 
              service: 
                name: podinfo 
                port: 
                  number: 80 
            path: / 
            pathType: Prefix 
  1. Ingressリソースをデプロイします:
$ kubectl apply -f 2-ingress.yaml ingress.networking.k8s.io/podinfo created 

課題3:トラフィックの生成と監視

この課題では、さまざまなトラフィック負荷におけるNGINX Ingress Controllerのパフォーマンスを観察します。準備として、NGINX Ingress Controllerで利用可能なメトリクスを一覧表示し、Prometheusをデプロイし、Locustをインストールします。次に、Locustを使用してトラフィックの急増をシミュレートし、パフォーマンスへの影響を追跡します。その結果はPrometheusで確認します。

すでに確認したとおり、Ingressコントローラーは、リバースプロキシ(ここではNGINX)とKubernetesとの統合用コードを組み合わせた通常のKubernetes Podです。アプリが大量のトラフィックを受信する場合は、NGINX Ingress Controllerの過負荷によるレイテンシーを回避するため、Podレプリカ数を増やす必要があると考えられます。

利用可能なメトリクスの一覧表示

スケーリングのタイミングと規模を判断するには、NGINX Ingress Controllerのパフォーマンスに関する正確な情報が必要です。このチュートリアルでは、スケーリングのタイミングを判断するためのNGINXメトリクスとして、アクティブな接続数(nginx_connections_active)を使用します。ここでは、NGINX Ingress Controllerがこのメトリクスを追跡していることを確認します。

NGINX Ingress Controllerは複数のメトリクスを公開します。このチュートリアルで使用するNGINX Open Sourceベースのモデルでは8個、NGINX Plusベースのモデルでは80個以上のメトリクスを公開します。

  1. メトリクスの一覧を照会するため、NGINX Ingress ControllerポッドのIPアドレスを取得します。アドレスはIPフィールドに表示されます。ここでは172.17.0.4です。(読みやすくするため、RESTARTS列とAGE列を省略し、出力を2行に分けています。)
$ kubectl get pods -o wide NAME                                  READY   STATUS    ...
main-nginx-ingress-779b74bb8b-6hdwx   1/1     Running   ...
podinfo-5d76864686-nl8ws              1/1     Running   ...

    ... IP           NODE       NOMINATED NODE  READINESS GATES 
    ... 172.17.0.4   minikube   <none>          <none> 
    ... 172.17.0.3   minikube   <none>          <none>
  1. Kubernetesクラスター内のホスト上に、シェルを備えた一時的なBusyBox Podを作成します:
$ kubectl run -ti --rm=true busybox --image=busyboxIf you don't see a command prompt, try pressing enter. 
/ # 
  1. NGINX Ingress Controllerによって生成されたメトリクスを一覧表示し、次のメトリクスが含まれていることを確認します:nginx_connections_active。<IP_address>には、手順1で取得した値を指定します。
/# wget -qO- <IP_address>:9113/metrics
  1. シェルを終了して、Kubernetesサーバーに戻ります。
/# exit 

Prometheusをデプロイ

NGINX Ingress Controllerがnginx_connections_activeメトリクスを追跡していることを確認できたので、次にメトリクスを収集(「スクレイプ」)するツールが必要です。このチュートリアルでは、Prometheusを使用します。

NGINX Ingress Controllerと同様に、Helmを使用するのがPrometheusをインストールする最も速い方法です。

  1. PrometheusリポジトリをHelmに追加します:
$ helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
  1. Prometheusをダウンロードしてインストールします:
$ helm install prometheus prometheus-community/prometheus \ --set server.service.type=NodePort --set server.service.nodePort=30010
  1. インストールを確認します。通常、完了までに最大60秒かかります。次の出力例では、確認コマンドを実行したのがhelm installコマンドの実行からわずか数秒後だったため、インストールはまだ進行中で、一部のPrometheus PodのSTATUSフィールドにContainerCreatingと表示されています。すべてのPodのステータスがRunningになると、インストールは完了です。(読みやすいように、出力を2行に分けています。)
$ kubectl get podsNAME                                           READY  ...
main-nginx-ingress-779b74bb8b-mtdkr            1/1    ...
podinfo-5d76864686-fjncl                       1/1    ...
prometheus-alertmanager-d6d94cf4b-85ww5        0/2    ...
prometheus-kube-state-metrics-7cd8f95cb-86hhs  0/1    ...
prometheus-node-exporter-gqxfz                 1/1    ...
prometheus-pushgateway-56745d8d8b-qnwcb        0/1    ...
prometheus-server-b78c9449f-kwhzp              0/2    ...

      ... STATUS             RESTARTS  AGE 
      ... Running            0         3m23s 
      ... Running            0         5m41s 
      ... ContainerCreating  0         7s
      ... Running            0         7s
      ... Running            0         7s
      ... ContainerCreating  0         7s
      ... ContainerCreating  0         7s
  1. Prometheusを開きます。minikube環境では、次のコマンドを実行すると、デフォルトのブラウザーでPrometheusダッシュボードが開きます。
$ minikube service prometheus-server
  1. 次のようなページが表示されれば、サーバーが動作していることを確認できます。
  2. 検索バーに「nginx_ingress_nginx_connections_active」と入力して、アクティブ接続メトリクスの現在値を確認します。NGINX Ingress Controllerポッドを1つデプロイしているため、アクティブ接続が1つと表示されます。

Locustのインストール

次のセクションでは、オープンソースの負荷テストツールであるLocustを使用してトラフィックの急増をシミュレートし、PrometheusでNGINX Ingress Controllerのパフォーマンスを確認します。ここでは、Locustをデプロイします。

  1. 任意のテキストエディターを使用して、以下の内容で「3-locust.yaml」という名前のYAMLファイルを作成します(または、GitHubからコピーします)。DeploymentオブジェクトとServiceオブジェクトでLocustポッドを定義します。ConfigMapオブジェクトでは、正しいヘッダーを含むリクエストを生成してポッドに送信する「locustfile.py」というスクリプトを定義します。
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 
        def hello_world(self): 
            self.client.get("/", headers={"Host": "example.com"}) 
--- 
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 
  1. Locustをデプロイします:
$ kubectl apply -f 3-locust.yaml configmap/locust-script created 
deployment.apps/locust created 
service/locust created 

トラフィックの急増をシミュレートし、パフォーマンスへの影響を確認する

  1. ブラウザーでLocustを開きます。
$ minikube service locust
  1. 各フィールドに次の値を入力します:
    • ユーザー数 – 1000
    • 生成レート – 10
    • ホスト – http://main-nginx-ingress
  2. [Start swarming]ボタンをクリックして、Podinfoアプリにトラフィックを送信します。
  3. Prometheusダッシュボードに戻り、NGINX Ingress Controllerの応答を確認します。変化を確認するには、nginx_ingress_nginx_connections_activeに対して新たにクエリを実行する必要がある場合があります。次の画面出力に示すように、多数の接続が確立されると、単一のNGINX Ingress Controller Podでは、レイテンシーを増加させずに増大したトラフィックを処理することが困難になります。Prometheusのグラフから、NGINX Ingress Controller Podあたりのアクティブな接続数が約100に達すると、レイテンシーが急増することがわかります。この情報を使用して、レイテンシーの増加を回避するためにNGINX Ingress Controller Podの数をスケールアップするタイミングを判断できます。

課題4:NGINX Ingress Controllerを自動スケーリングする

最後の課題では、トラフィック量の増加に応じてリソースを自動スケーリングする構成を作成します。このチュートリアルでは自動スケーリングにKEDAを使用するため、まずKEDAをインストールし、スケーリングを実行するタイミングと方法を定義するポリシーを作成します。次に、課題3と同様にLocustを使用してトラフィックの急増をシミュレートし、自動スケーリングが有効な場合のNGINX Ingress ControllerのパフォーマンスをPrometheusで確認します。

KEDAをインストール

KEDAは、Kubernetesのイベント駆動型オートスケーラーです。メトリクスサーバー(Kubernetes向けのメトリクスを保存、変換するコンポーネント)を統合し、Prometheusをはじめとするツールからメトリクスを直接取得できます。これらのメトリクスを使用してHorizontal Pod Autoscaler(HPA)を作成し、Prometheusが収集したメトリクスを橋渡ししてKubernetesに渡します。

NGINX Ingress ControllerやPrometheusと同様に、このチュートリアルではHelmを使用してKEDAをインストールします。

  1. KEDAをHelmリポジトリに追加します:
$ helm repo add kedacore https://kedacore.github.io/charts 
"kedacore" has been added to your repositories 
  1. KEDAをインストールします:
$ helm install keda kedacore/keda NAME: keda 
NAMESPACE: default 
STATUS: deployed 
REVISION: 1 
TEST SUITE: None
  1. KEDAが2つのPodとして実行されていることを確認します。(読みやすくするため、NAME列の一部の値は短縮されています。また、RESTARTS列は省略されています。すべてのPodで値は0です。)
$ kubectl get pods NAME                                    READY  STATUS     AGE 
keda-operator-8644dcdb79-492x5 1/1 Running 59s keda-operator-metrics-apiserver-66d... 1/1 Running 59s 
locust-77c699c94d-dvb5n                 1/1    Running  8m59s 
main-nginx-ingress-779b74bb8b-v7ggw     1/1    Running    48m 
podinfo-5d76864686-c98rb                1/1    Running    50m 
prometheus-alertmanager-d6d94cf4b-8...  2/2    Running    37m 
prometheus-kube-state-metrics-7cd8f...  1/1    Running    37m 
prometheus-node-exporter-j4qf4          1/1    Running    37m 
prometheus-pushgateway-56745d8d8b-9n4nl 1/1    Running    37m 
prometheus-server-b78c9449f-6ktn9       2/2    Running    37m

自動スケーリングポリシーの作成

次に、KEDAの「ScaledObject」カスタムリソース定義(CRD)を使用して、NGINX Ingress Controllerのスケーリング方法を決定するパラメーターを定義します。以下の設定では、

  • Prometheusが収集したnginx_connections_activeメトリクスの値に基づいて自動スケーリングをトリガーします
  • 既存の各podのアクティブ接続数が100に達すると、新しいpodをデプロイします
  • NGINX Ingress ControllerのPodを1個から最大20個まで自動スケーリング

以下の手順を実行します。

  1. 任意のテキストエディターを使用して、以下の内容を含むYAMLファイル「4-scaled-object.yaml」を作成します(または、GitHubからコピーします)。このファイルでは、KEDAの「ScaledObject」を定義します。
apiVersion: keda.sh/v1alpha1 kind: ScaledObject 
metadata: 
 name: nginx-scale 
spec: 
 scaleTargetRef: 
   kind: Deployment 
   name: main-nginx-ingress 
minReplicaCount: 1 
maxReplicaCount: 20 
cooldownPeriod: 30 
pollingInterval: 1 
triggers: 
- type: prometheus 
  metadata: 
    serverAddress: http://prometheus-server 
    metricName: nginx_connections_active_keda 
    query: | 
      sum(avg_over_time(nginx_ingress_nginx_connections_active{app="main-nginx-ingress"}[1m])) 
    threshold: "100" 
  1. デプロイします:ScaledObject:
$ kubectl apply -f 4-scaled-object.yaml scaledobject.keda.sh/nginx-scale created 

トラフィックの急増をシミュレートし、オートスケーリングがパフォーマンスに与える影響を確認

オートスケーリングの効果を本格的に検証するため、接続数をチャレンジ3の2倍に増やします。

  1. ブラウザーでLocustサーバーに戻ります。各フィールドに次の値を入力し、[Start swarming]ボタンをクリックします。
    • ユーザー数 – 2000
    • 生成レート – 10
    • ホスト – http://main-nginx-ingress
  2. PrometheusとLocustのダッシュボードに戻ります。Prometheusグラフの下にあるピンク色のボックスは、NGINX Ingress ControllerのPod数がスケールアップおよびスケールダウンする様子を示しています。
  3. ターミナルに戻り、KEDA HPAを手動で確認します。出力の「REPLICAS」フィールドには、現在デプロイされているPodレプリカの数が表示されます。(読みやすいように、出力は2行に分けて表示しています。)
$ kubectl get hpa
NAME                  REFERENCE                      ... 
keda-hpa-nginx-scale  Deployment/main-nginx-ingress  ... 

    ... TARGETS           MINPODS   MAXPODS   REPLICAS   AGE 
    ... 101500m/100 (avg) 1         20        10         2m45s

次のステップ

アクティブ接続数だけに基づいてオートスケーリングを行う場合、潜在的な制約があります。スケーリングを行ってもNGINX Ingress Controllerの負荷が高まり、接続を切断せざるを得なくなると、オートスケーラーはアクティブ接続数の減少をリクエスト数の減少と解釈し、レプリカ数を減らします。その結果、パフォーマンスがさらに低下する可能性がありますが、複数のメトリクスを組み合わせて利用することで、この事態を防止できます。たとえば、nginxplus_connections_dropped(NGINX PlusベースのNGINX Ingress Controllerで利用可能)では、切断されたクライアント接続を追跡できます。

NGINX PlusおよびNGINX App Protectを搭載したNGINX Ingress Controllerをお試しいただくには、今すぐ30日間の無料トライアルを開始するか、ユースケースについてF5にお問い合わせください。

NGINX Open SourceでNGINX Ingress Controllerをお試しいただくには、リリース版のソースコードを入手するか、DockerHubからビルド済みコンテナをダウンロードできます。


共有
タグ: F5 NGINX, 2022, Tech

関連するブログ記事

チュートリアル:NGINXを使用してアプリケーション向けにOpenTelemetryを構成する
NGINX | 2024/01/18

チュートリアル:NGINXを使用してアプリケーション向けにOpenTelemetryを構成する

OpenTelemetryを使用してNGINXサーバーの状態と健全性をより明確に把握することで、問題のトラブルシューティングを行い、Webアプリケーションのパフォーマンスを向上できます。

AkitaのNGINX Plus認定モジュールでAPIエンドポイントの問題を特定・修正
NGINX | 2023/05/31

AkitaのNGINX Plus認定モジュールでAPIエンドポイントの問題を特定・修正

Akita SoftwareのAPIオブザーバビリティ向け新しいNGINX Plus Certified Moduleを活用して、APIエンドポイントの問題をより迅速に特定し、修正できます。

JavaプロジェクトをスキャフォールディングしてKubernetesネイティブアプリを構築する方法
NGINX | 2023/02/09

JavaプロジェクトをスキャフォールディングしてKubernetesネイティブアプリを構築する方法

Red HatのシニアプリンシパルデベロッパーアドボケイトであるDaniel Oh氏が、Javaプロジェクトをゼロから構築するためのひな形を作成し、Kubernetesネイティブアプリケーションとしてビルドする方法を解説します。

F5 NGINXaaS for Azureのご紹介:Microsoft Azureでネイティブに利用できるSaaS型ロードバランシング
NGINX | 2022/05/24

F5 NGINXaaS for Azureのご紹介:Microsoft Azureでネイティブに利用できるSaaS型ロードバランシング

NGINXaaS for Azureは、NGINX PlusをAzureネイティブのSaaSとして利用できるサービスです。NGINXの設定を容易にリフト&シフトできるため、クラウド導入とモダンアプリの展開を加速できます。

SELinuxでNGINXおよびNGINX Plusを使用する
NGINX | 2018/08/17

SELinuxでNGINXおよびNGINX Plusを使用する

Red Hat Enterprise Linux(RHEL)および関連ディストリビューションでSecurity-Enhanced Linux(SELinux)を有効にすると、デフォルト設定によりNGINXとNGINX Plusの一部の操作が制限されます。この記事では、すべての機能を利用できるようにSELinuxの設定を変更する方法について説明します。

NGINX PlusによるAWS Auto Scalingグループの負荷分散
NGINX | 2017/03/06

NGINX PlusによるAWS Auto Scalingグループの負荷分散

新しいnginx-asg-sync統合ソフトウェアにより、NGINX PlusはAWS Auto Scalingグループの負荷を直接分散できるため、クラウドでの負荷分散がさらに柔軟になります