最新の手法を取り入れるPlatform OpsまたはDevOpsエンジニアとして、オープンソース(場合によっては商用)の各種ツールを活用し、開発チーム向けの新しいアプリケーションやコンテナのテスト、デプロイ、管理を行っています。これらのコンテナやPodを開発、テスト、ステージング、本番の各環境で実行するために、Kubernetesを採用しています。マイクロサービスのアーキテクチャと概念を取り入れ、ほとんどの場合は順調に機能しています。しかし、その過程でいくつかの障害にも直面しています。
たとえば、新しいクラスター、サービス、アプリケーションを構築して展開する際、トラフィックを一切中断することなく、これらの新しいリソースを本番環境に容易に統合または移行するには、どうすればよいでしょうか。従来のネットワークアプライアンスでは、DNSレコード、ロードバランサー、ファイアウォール、プロキシの構成を変更する際に、再読み込みや再起動が必要です。DNS、ロードバランサー、ファイアウォールのルールを更新するには「サービス停止」や「メンテナンス時間」が必要となるため、ダウンタイムを発生させずにこれらの設定を変更することはできません。多くの場合、気の重いサービスチケットを提出し、別のチームによる承認と変更作業を待たなければなりません。
メンテナンス時間帯は、チームを立ち往生させ、アプリケーションデリバリーを停滞させ、「トラフィックを管理するもっと良い方法があるはずだ」と思わせる要因になりかねません。そこで、再びスムーズな運用を実現するソリューションを見ていきましょう。
アクティブ/アクティブ型マルチクラスターロードバランシング
複数のKubernetesクラスターがある場合は、両方のクラスターに同時にトラフィックをルーティングするのが理想的です。さらに、A/B、カナリア、またはブルーグリーン方式でトラフィックを分割し、その一部をテストとして送信する方法もあります。これを行うには、NGINX Plusとngx_http_split_clients_moduleを併用できます。
HTTP Split ClientsモジュールはNGINX Open Sourceで作成されており、キーに基づいてリクエストを指定した比率で分散できます。このユースケースでは、クラスターがNGINXの「アップストリーム」に相当します。そのため、クライアントリクエストが到着すると、トラフィックは2つのクラスターに分割されます。クライアントリクエストの振り分けに使用するキーには、利用可能な任意のNGINXクライアント$variableを指定できます。ただし、リクエストごとに振り分けを制御するには、$request_id変数を使用します。これは、受信する各リクエストにNGINXが割り当てる一意の番号です。
分割比率を設定するには、各クラスターに振り分ける割合を決めます。この例では、K8s Cluster1を本番環境用の「大規模クラスター」、Cluster2を本番前テスト用の「小規模クラスター」として使用します。ステージング用の小規模クラスターがある場合は、90:10の比率を使用し、新しい変更を大規模クラスターに展開する前に、トラフィックの10%を小規模クラスターでテストして、すべてが正常に動作することを確認できます。リスクが高すぎると感じる場合は、比率を95:5に変更できます。実際には、0~100%の範囲で任意の比率を選択できます。
ほとんどのリアルタイム本番トラフィックでは、同規模の2つのクラスターに50:50で振り分けるのが適切です。ただし、クラスターの規模やその他の条件に応じて、別の比率も簡単に設定できます。比率を0:100(または100:0)に設定すれば、ダウンタイムなしでクラスター全体のアップグレード、パッチ適用、修復、さらには置き換えも可能です。一方のクラスターで問題に対処している間、NGINXの「split_clients」で稼働中のクラスターにリクエストをルーティングします。
# Nginx Multi Cluster Load Balancing
# HTTP Split Clients Configuration for Cluster1:Cluster2 ratios
# Provide 100, 99, 50, 1, 0% ratios (add/change as needed)
# Based on
# https://www.nginx.com/blog/dynamic-a-b-testing-with-nginx-plus/
# Chris Akker – Jan 2024
#
split_clients $request_id $split100 {
* cluster1-cafe; # All traffic to cluster1
}
split_clients $request_id $split99 {
99% cluster1-cafe; # 99% cluster1, 1% cluster2
* cluster2-cafe;
}
split_clients $request_id $split50 {
50% cluster1-cafe; # 50% cluster1, 50% cluster2
* cluster2-cafe;
}
split_clients $request_id $split1 {
1.0% cluster1-cafe; # 1% to cluster1, 99% to cluster2
* cluster2-cafe;
}
split_clients $request_id $split0 {
* cluster2-cafe; # All traffic to cluster2
}
# Choose which cluster upstream based on the ratio
map $split_level $upstream {
100 $split100;
99 $split99;
50 $split50;
1.0 $split1;
0 $split0;
default $split50;
}必要な比率(90:10、80:20、60:40など)に合わせて、上記の設定を追加または編集できます。
注:NGINXには、Split Clients moduleストリームコンテキストでTCP接続に使用できるモジュールもあり、HTTP以外のトラフィックに利用できます。このモジュールは、HTTPリクエストではなく、新しいTCP接続に基づいてトラフィックを分割します。
NGINX Plusのキー・バリューストア
次に利用できる機能は、NGINX Plusの「キー・バリュー・ストア」です。これはNGINXの共有メモリゾーン内にあるキー・バリューオブジェクトで、さまざまなデータストレージのユースケースに使用できます。ここでは、前のセクションで説明した分割比率の値を保存するために使用します。NGINX Plusでは、NGINXをリロードせずに任意のキー・バリューレコードを変更できます。そのため、API呼び出しでこの分割値を変更し、動的な分割機能を実現できます。
この例では、次のようになります。
{“cafe.example.com”:90}
このKeyValレコードは次のように解釈されます。
キーはホスト名「cafe.example.com」です。
値は分割比率を示す「90」です。
NGINX構成ファイルに分割比率をハードコーディングする代わりに、キーバリューメモリを使用できます。これにより、NGINXで静的な分割値を変更する際に必要だったNGINXのリロードが不要になります。
この例では、NGINXの分割比率を90:10に設定し、大規模な「Cluster1」に90%、小規模な「Cluster2」に残りの10%を割り当てています。これはキーと値のレコードであるため、NGINX Plus APIを使用して、設定を再読み込みすることなく動的に比率を変更できます。比率を変更すると、Split Clientsモジュールは次のリクエストから新しい比率の値を使用します。
KVレコードを作成し、比率を50/50に設定します:
NGINX PlusにAPIコマンドを送信して、KeyValueストアに新しいレコードを追加します:
curl -iX POST -d '{"cafe.example.com":50}' http://nginxlb:9000/api/8/http/keyvals/split
KVレコードを変更し、比率を90/10に変更します:
HTTP PATCHメソッドを使用してメモリ内のKeyValレコードを更新し、KeyValの分割比率を90に変更します:
curl -iX PATCH -d '{"cafe.example.com":90}' http://nginxlb:9000/api/8/http/keyvals/split
次に、実稼働前テストチームが新しいアプリケーションコードの準備が整っていることを確認したら、大規模な「Cluster1」にデプロイし、比率を100%に変更します。これにより、すべてのトラフィックが直ちに「Cluster1」へ送信され、新しいアプリケーションがトラフィックを中断することなく「本稼働」します。サービス停止、メンテナンス時間、再起動、再読み込み、大量のチケットも必要ありません。この分割比率は、任意のタイミングでAPIを1回呼び出すだけで変更できます。
もちろん、90%から100%へ簡単に移行できるということは、比率を100:0から50:50(さらには0:100)へ容易に変更できるということです。そのため、ホットバックアップクラスターを用意したり、新しいリソースを追加してクラスターを水平にスケールしたりできます。さらに最大限に活用すれば、最新のソフトウェア、ハードウェア、ソフトウェアパッチを使用して新しいクラスターを一から構築し、接続を1つも切断することなく、アプリケーションをデプロイして一定期間をかけてトラフィックを移行することも可能です。
ユースケース
HTTP Split Clientsモジュールを動的なキーバリューストアと組み合わせることで、次のユースケースに対応できます。
- アクティブ/アクティブ負荷分散 – 複数のクラスターに負荷を分散します。
- アクティブ/パッシブ負荷分散 – プライマリ、バックアップ、DRの各クラスターおよびアプリケーションへの負荷分散に使用します。
- A/Bテスト、ブルーグリーンテスト、カナリアテスト – 新しいKubernetesアプリケーションで使用します。
- クラスターの水平スケーリング – 準備が整った段階で、クラスターリソースを追加し、比率を変更します。
- 無停止のクラスターアップグレード – 一方のクラスターをアップグレード、パッチ適用、または修復している間も、もう一方のクラスターを使用できます。
- 即時フェイルオーバー – 一方のクラスターに重大な問題が発生した場合、比率を変更してもう一方のクラスターを使用できます。
設定例
キーと値の設定例を次に示します。
# Define Key Value store, backup state file, timeout, and enable sync
keyval_zone zone=split:1m state=/var/lib/nginx/state/split.keyval timeout=365d sync;
keyval $host $split_level zone=split;以下は、cafe.example.comアプリケーションの設定例です。
# Define server and location blocks for cafe.example.com, with TLS
server {
listen 443 ssl;
server_name cafe.example.com;
status_zone https://cafe.example.com;
ssl_certificate /etc/ssl/nginx/cafe.example.com.crt;
ssl_certificate_key /etc/ssl/nginx/cafe.example.com.key;
location / {
status_zone /;
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_set_header "Connection" "";
proxy_pass https://$upstream; # traffic split to upstream blocks
}
# Define 2 upstream blocks – one for each cluster
# Servers managed dynamically by NLK, state file backup
# Cluster1 upstreams
upstream cluster1-cafe {
zone cluster1-cafe 256k;
least_time last_byte;
keepalive 16;
#servers managed by NLK Controller
state /var/lib/nginx/state/cluster1-cafe.state;
}
# Cluster2 upstreams
upstream cluster2-cafe {
zone cluster2-cafe 256k;
least_time last_byte;
keepalive 16;
#servers managed by NLK Controller
state /var/lib/nginx/state/cluster2-cafe.state;
}アップストリームサーバーのIPアドレスとポートは、NGINX Loadbalancer for Kubernetesによって管理されます。これは、NGINX Plus APIも使用してNGINX Plusを動的に構成する新しいコントローラーです。詳細については、次のセクションを参照してください。
一般的な監視・可視化ツールであるGrafanaを使用して、HTTP分割トラフィックの推移を確認してみましょう。NGINX Prometheus Exporter(njsベース)を使用してNGINX Plusのすべてのメトリクスをエクスポートすると、Grafanaで収集され、グラフ化されます。PrometheusとGrafanaの設定方法については、こちらをご覧ください。
グラフには4台のアップストリームサーバーがあります。内訳は、Cluster1に2台、Cluster2に2台です。HTTP負荷生成ツールを使用してHTTPリクエストを生成し、NGINX Plusに送信します。
以下の3つのグラフでは、グラフの開始時点で分割比率が50:50になっていることがわかります。

その後、12:56:30に比率が10:90に変わります。

その後、13:00:00に90:10へ変更されます。

PrometheusとGrafanaの動作する設定は、NGINX Loadbalancer for Kubernetes GitHubリポジトリで確認できます。
動的HTTPアップストリーム:NGINX Loadbalancer for Kubernetes
NGINX Plus APIとNGINX Loadbalancer for Kubernetesコントローラーを使用すると、静的なNGINX Upstream構成を動的なクラスターアップストリームに変更できます。この無償プロジェクトは、KubernetesコントローラーとしてNGINX Ingress Controllerを監視し、TCP/HTTPロードバランシング用に構成された外部のNGINX Plusインスタンスを自動的に更新します。設計は非常にわかりやすく、インストールと運用も簡単です。このソリューションを導入すると、Kubernetes環境でTCP/HTTPロードバランシングを実装できます。新しいアプリケーションやサービスは即座に検出され、リロードなしでトラフィックを受信できるようになります。
アーキテクチャと処理フロー
NGINX Loadbalancer for KubernetesはKubernetesクラスター内に配置されます。Kubernetesに登録され、NGINX Ingress Controller(nginx-ingress)Serviceを監視します。Ingress Controllerに変更があると、NGINX Loadbalancer for KubernetesはワーカーIPとNodePortのTCPポート番号を収集し、IP:ポートをNGINX Plus API経由でNGINX Plusに送信します。
NGINXのアップストリームサーバーはリロードなしで更新され、NGINX Plusは適切なアップストリームサーバーとKubernetes NodePortにトラフィックを負荷分散します。NGINX Plusインスタンスを追加することで、高可用性を実現できます。
NGINX Loadbalancer for Kubernetesの動作例
以下のスクリーンショットには、デプロイされて稼働中のNGINX Loadbalancer for Kubernetesを示す2つのウィンドウがあります。
- サービスタイプ –
LoadBalancer(対象:nginx-ingress) - 外部IP – NGINX Plusサーバーに接続
- ポート – NodePortは443:30158にマッピングされ、対応するNGINXアップストリームサーバーが設定されます(NGINX Plusのリアルタイムダッシュボードに表示されているとおり)
- ログ – NGINX Loadbalancer for KubernetesからNGINX Plusへのデータ送信が成功していることを示します

注記:この例では、Kubernetesワーカーノードは10.1.1.8と10.1.1.10です
NGINX Plusのセキュリティ機能の追加
Kubernetesで稼働するアプリケーションがオープンインターネットに公開されるケースが増えるにつれ、セキュリティ対策が不可欠になります。NGINX Plusには、階層型の多層防御アーキテクチャの構築に利用できるエンタープライズクラスのセキュリティ機能が備わっています。
クラスターの前段に配置したNGINX Plusでsplit_clients機能を実行しているなら、その構成を活用して、セキュリティの強化に役立つ機能を追加してはいかがでしょうか。ここでは、セキュリティ強化に利用できるNGINX Plusの機能をいくつか紹介します。各機能の設定、テスト、デプロイに役立つドキュメントへのリンクと参照情報も掲載しています。
- IPブロック/許可リスト – 送信元IPアドレスに基づいてアクセスを制御します。Plus APIを使用して、NGINX PlusのKey-Valueストアで動的なIPブロック/許可リストを構成する方法については、NGINX Docsの「IPアドレスの動的な拒否リスト登録」ページにある構成ガイドを参照してください。
- レート制限 – アプリケーション、APIエンドポイント、メディアダウンロードにおけるTCP接続数、HTTPリクエスト数、帯域幅使用量を制御します。NGINXによるレート制限の詳細については、NGINX Docsの「プロキシされたHTTPリソースへのアクセス制限」と、ブログ記事「NGINXおよびNGINX Plusによるレート制限」および「NGINX Plus Key-Value Storeを使用した動的な帯域幅制限」をご覧ください。
- GeoIP2 dynamic module – 送信元IPアドレスに基づいて位置情報メタデータを収集します。詳しくは、NGINX Docsの「地理的位置に基づくアクセス制限」ページをご覧ください。
- JWT and OpenID Connect (OIDC) module – 業界標準のプロトコルを使用してユーザーアクセスを制御します。詳細については、NGINX Docsの「Setting up JWT Authentication」ページをご覧ください。
- NGINX App Protect – 軽量かつ低レイテンシーのWebアプリケーションファイアウォールで、既存の脅威や進化する脅威から保護します。
今すぐ始める
Kubernetesクラスターのエッジにおけるネットワークの課題にお悩みなら、このNGINXマルチクラスターソリューションをぜひお試しください。NGINX Loadbalancer for Kubernetesソフトウェアを実際にお試しいただき、ぜひご意見をお聞かせください。ソースコードはオープンソース(Apache 2.0ライセンス)で、インストール手順はすべてGitHubでご確認いただけます。
フィードバックは、リポジトリにコメントを投稿するか、NGINX Community Slackでメッセージをお送りください。
関連するブログ記事
チュートリアル:NGINXを使用してアプリケーション向けにOpenTelemetryを構成する
OpenTelemetryを使用してNGINXサーバーの状態と健全性をより明確に把握することで、問題のトラブルシューティングを行い、Webアプリケーションのパフォーマンスを向上できます。
AkitaのNGINX Plus認定モジュールでAPIエンドポイントの問題を特定・修正
Akita SoftwareのAPIオブザーバビリティ向け新しいNGINX Plus Certified Moduleを活用して、APIエンドポイントの問題をより迅速に特定し、修正できます。
JavaプロジェクトをスキャフォールディングしてKubernetesネイティブアプリを構築する方法
Red HatのシニアプリンシパルデベロッパーアドボケイトであるDaniel Oh氏が、Javaプロジェクトをゼロから構築するためのひな形を作成し、Kubernetesネイティブアプリケーションとしてビルドする方法を解説します。
F5 NGINXaaS for Azureのご紹介:Microsoft Azureでネイティブに利用できるSaaS型ロードバランシング
NGINXaaS for Azureは、NGINX PlusをAzureネイティブのSaaSとして利用できるサービスです。NGINXの設定を容易にリフト&シフトできるため、クラウド導入とモダンアプリの展開を加速できます。

SELinuxでNGINXおよびNGINX Plusを使用する
Red Hat Enterprise Linux(RHEL)および関連ディストリビューションでSecurity-Enhanced Linux(SELinux)を有効にすると、デフォルト設定によりNGINXとNGINX Plusの一部の操作が制限されます。この記事では、すべての機能を利用できるようにSELinuxの設定を変更する方法について説明します。
NGINX PlusによるAWS Auto Scalingグループの負荷分散
新しいnginx-asg-sync統合ソフトウェアにより、NGINX PlusはAWS Auto Scalingグループの負荷を直接分散できるため、クラウドでの負荷分散がさらに柔軟になります