IKS MZ構成時のIngressとLoadBalancer+GLBの方式選択の考察

IBM Cloud Kubernetes Service (IKS) [1]では、NodePort, Ingress, LoadBalancer を利用して、アプリケーションをインターネット上に公開できます。その上に、IKSクラスタのノードを複数ゾーンに展開して、データセンターレベルの障害に対応できる構成を組むことができます。

ゾーンは、十分に離れた住所に存在し、設備として完全に独立したデータセンターを表現しています。これを利用することで、データセンターの火災や設備の障害、送電網や通信網の障害などに対処して、サービスの継続性を達成することができます。

さらに、Cloud Internet Service (CIS) [2] を併用することで、複数のデータセンターでのグローバルロードバランシング(GLB)を構成することができます。これによりデータセンターの障害に対して、インターネット上のクライアントからのリクエストを、自動的に健全なデータセンターへルーティングすることができます。

そこで、本メモでは、Kubernetesクラスタのノードを、複数ゾーン（データセンター）に展開して、高い可用性を得るために適切なシステム構成を検討します。


## Ingress によるマルチゾーン構成

Ingress[3]は、KubernetesがAPIを規定する機能の一つで、IKSでは、Ingressリソースと呼ばれています。その実態であるIngressコントローラーの実装方法はクラウドベンダーやソフトウェア製品に依存しており、OSSとしては、NGINX Ingress Controller [4]が良く知られています。一方、IKSでは、Application Load Balancer（ALB) [5] という呼称で実装されています。使用時の注意点としては、NGINXイングレスコントローラーとALBには互換性がありません。そのために、NGINXイングレスコントローラーのアノテーションを、IKSのIngressリソースに設定しても動作しません。

IBM Cloud のマルチゾーン使用時に、Ingressを利用する場合の利点と課題を以下に簡潔に記述します。

#### Ingressをマルチゾーンで使用することの利点

* IKSクラスタ構成時に、自動付与されるDNS名とTLS証明書を利用できる。
* マルチゾーン構成では、自動的にGLBが構成される。
* GLBはゾーンを監視して、障害検知時はDNSのアドレス解決から除外する。
* 自動付与されるDNS名にサブドメインを設定して、SSL/TLS暗号通信が可能。
* Ingressにユーザー独自のカスタムドメインやTLS証明書を設定できる。
* Ingressのセッション・パーシステンスやセッション・アフィニティ機能で、セッション情報を保持するポッドへ振分けられる

![Ingress-MZ.PNG](https://qiita-image-store.s3.amazonaws.com/0/42829/3fc05df4-c0b7-e303-948d-a84517d9a0e3.png)



#### マルチゾーン構成時 Ingressの課題

Ingressを利用する場合の課題は、以下２つになる。

* GLBのDNSとの連動は、IKS用ドメインのみに機能して、カスタムドメインに対して連動しない。 GLBは、ゾーンのIPアドレスを監視しており、ゾーン障害時にはDNSアドレス解決から除外するが、Ingressに設定したカスタムドメインでは、その機能が働かない。
* SSL/TLSの暗号終端処理がALBに集中するため、アプリケーションの応答性能に悪影響が考えられる。ALBは、ゾーンに一つだけ活性化されるため、ノード数やポッド数を多く必要とするワークロードに対しては、ALBに過度な負荷がかかることになる。

Ingressは、IKSクラスタに自動付与されるドメインで、アプリケーションを公開する場合、手間とコストがかからず、有用な方法である。しかし、カスタムドメイン使用や高度なスケーラビリティを必要とする場合には、CISのGLBとIKSのロードバランサーを検討する必要がある。



## CISｰGLB の組み合わせ対応

Ingressを利用しないで、CISのグローバルロードバランサー(以下GLB)と組み合わせ可能な構成は、以下の３つである。それぞれ利点と課題があるため、それらを列挙する。

* NodePort
* LoadBalancer 1.0
* LoadBalancer 2.0

GLBは、次の機能を提供します。

* 複数のゾーンに配置されたIPアドレスを代表するサブドメイン名をDNSで解決できるようにする。
* ゾーンに配置されたIPアドレスに、クライアントからのリクエストを分配することができる。
* 分配先のゾーンのIPアドレスに対してヘルスチェックをおこない、その応答が無い場合は、DNSのアドレス解決から、該当のIPアドレスを削除する。
* ヘルスチェックは60秒間隔でおこない、DNSのTTL時間は短く設定されるため、ヘルスチェックで異常を検知してから有効化される時間は短い。

GLB利用条件には以下があります。

* カスタム（独自）ドメインを持っている必要があります。
* レジストラーやDNSプロバイダーは、CISへドメイン管理の代行委任が必要です。



### NodePort + GLB

NodePortによってIKSクラスタのノードのIPアドレス上のポートを開いて、インターネットに対して、アプリケーションを公開できます。そして、GLBと併用することで、複数のデータセンター上のノードに、リクエストを分配できます。ALBやLBなどに割り当てるポータブルIPについて、考慮する必要もなく、シンプルな構成を組むことができます。

しかし、この組み合わせは次の課題があります。

* ノード数の変更に対して、ノードのIPアドレスの登録や削除を、GLBの管理画面で手作業で実施する必要がある。
* NodePortのポート番号を変更する機能はないため、そのまま公開する必要がある。

このような課題から、IKSのクラスタ変更にたいして、GLBの操作が必要となります。


## LoadBalancer + GLB

GLBに加えて、IKSのロードバランサー(以下LB)を設定する必要があるため、構築時の設定項目は増えますが、運用が始まってからの作業を軽減することができます。

LBは、各ゾーンごとのノード群を代表するIPアドレスを保持して、IKSクラスタのノード数の増減に対して、振分け先の変更を自動で対応します。そのため、GLBの分配先のノード、すなわち、起点ノードに、各ゾーンのLBのIPアドレスを設定することで、ノード数の変更に対して、GLBの設定変更は必要ありません。そのような機能から、以下の利点が生まれます。

#### 利点

* IKSのノード数の増減にたいして、CISの設定変更は不要です。
* それぞれのゾーンのLBが持つIPアドレスに対して、ヘルスチェックを行います。もしゾーンに障害があるとDNSから自動削除して、復旧するとDNSのエントリを復活させます。
* Ingressでは出来なかったカスタムドメインでのGLBが利用できます。

反対に課題は、構築作業が増えること、CISの利用料金、ドメイン料金、TLS証明書料金が追加になる点です。
それから、セッション情報を持つポッドへ継続して振り分けるセッション・パーシステンスやセッション・アフィニティと呼ばれる機能は、ロードバランサーに無いことです。このようなレイヤー７の機能が必要な場合は、Ingressを利用する必要があります。
GLBにはセッション・アフィニティの機能があり、ウェブ管理画面からONにすることで利用できます。しかし、LBにはその機能が無いため、セッション情報はRedisなどのキャッシュに保持する必要があります。

## LoadBalancer 1.0 vs 2.0

IKSのロードバランサーは、外部のロードバランサーと連動するものではなく、KeepAlivedによってポータブルIPをノードにバインドして、ポッドの機能で、着信したリクエストの転送するものです。これは、LoadBalancer v1.0 と v2.0 で同じです。

![LB-MZ.PNG](https://qiita-image-store.s3.amazonaws.com/0/42829/6b40f0e1-b712-fc55-2018-07687fa28967.png)

しかし、この二つのバージョンには次のような違いがあります。

#### LoadBalancer 1.0

* iptables の機能で、パブリックIPアドレスを、クラスタ内部のネットワークアドレスに変換して、ポッドに転送します。
* リクエスト分散のアルゴリズムは選択できず、ランダムです。
* ポッドからの応答は、再び振分け元のノードに戻され、再びパブリックIPアドレスに戻され、クライアントへ応答します。
* このため、ロードバランサーのポッドが存在するノードにトラフィックが集中します。

#### LoadBalancer 2.0

* LinuxカーネルのIPVS[6]を利用して、パケットを転送します。このため、iptablesに比べ、処理性能が向上します。
* リクエスト分散のアルゴリズムを選択できるようになります。
* パブリックIPのパケットを、内部ネットワークのIPパケットでカプセル化して、目的のノード上のポッドに転送します。
* 転送先のポッドでは、パブリックIPアドレスをTCP/IPのヘッダーから判別することもできます。
* ポッドからの応答は、ダイレクトサーバーリターン（DSR）になります。そのため、LoadBalancerのポッドにパケットが戻ることなく、直接ノードから応答が送信されるため、トラフィックの集中がおこりません。

このようなロードバランサーの構造上の違いから、今後 LoadBalancer 2.0 を積極的に利用していくことが望ましいと考えられます。

ただし、LoadBalancer 2.0を利用するためには、チケットからネットワーク設定変更のリクエストを上げる必要があります。[7]
この理由は、IBM Cloud ではネットワークの不正な利用を防止するために、送信元の経路情報が無いパケットを廃棄するuRPF[8]の機能が有効になっているため、カプセル化されて転送されたパケットの応答を、DSRで直接送信するため、uRPFが働いて、パケットを廃棄してしまうためです。

![LB2-MZ.PNG](https://qiita-image-store.s3.amazonaws.com/0/42829/c955c07e-1a13-900a-bb94-0916cd4eb23b.png)



## マルチゾーン構成ベストプラクティス

IKSクラスタのノードを複数データセンターに配置する場合に、IKSのIngressで構築するケースと、同IKSのLBにGLBを組み合わせて構成する、２つのケースが候補として挙がります。

それぞれに長所と短所があり、選択の条件を箇条書きにすると、以下のようになりました。


#### IKS-Ingressを選択した良いケース

* マルチゾーンの高可用性が必要である。
* 独自のドメインである必要が無く、ドメイン確保やサーバー証明書費用を抑えたい。
* ゾーン障害に対して、自動的に振分け先から削除されなければならない。
* 非常に多くの端末からのアクセスも無く、スケールアップの要求が無い。
* 開発環境や一時利用環境などに利用したい。
* コストを低く抑えたい。


#### IKS-LB + GLB の組み合わせが適するケース

* マルチゾーンの高可用性が必要である。
* 独自ドメインの利用が必須である。
* ゾーン障害に対して、自動的に振分け先から削除されなければならない。
* SSL/TLSの暗号化処理が特定のポッドに集中することを避けなければならないほど、クライアント数が多く、通信量が大きい。
* ドメイン名やTLS証明書の更新のコストが発生しても良い。


## シングルゾーン構成のケース

シングルゾーンで構成する場合は、複数ゾーンを代表するDNS名を持つ必要もなく、そのため、CISのGLBを使用する必要はありません。もちろん、WAFやDDOS攻撃対策としては有効ですが、必須ではないかもしれません。

IKS-Ingress または IKS-LB　の選択の動機は、カスタムドメインの暗号化処理をIngressコントローラーが受け持つか、または、ポッドが受け持つかの、判断となります。

IKS-Ingressを利用する場合、Ingressコントローラーに相当するALBでTLS暗号通信の終端を担うことになり、ALBに負荷が集中することになります。このALBは、IKSクラスタ内のポッドで実行され、負荷集中が性能上の課題となる場合、IKSｰLBを選択して、暗号の終端処理をアプリケーションのポッド、または、サイドカーコンテナに受け持たせ、負荷を分散するようにします。



## 参考資料

* [1] IBM Cloud Kubernetes Service概説,https://cloud.ibm.com/docs/containers?topic=containers-container_index&locale=ja#container_index
* [2] Cloud Internet Service,https://cloud.ibm.com/catalog/services/internet-services
* [3] Ingress,https://kubernetes.io/docs/concepts/services-networking/ingress/
* [4] NGINX Ingress Controller,https://kubernetes.github.io/ingress-nginx/
* [5] Application Load Balancer, https://cloud.ibm.com/docs/containers?topic=containers-ingress#planning
* [6] IPVS, https://en.wikipedia.org/wiki/IP_Virtual_Server
* [7] ロード・バランサー 2.0 の前提条件,https://cloud.ibm.com/docs/containers?topic=containers-loadbalancer#ipvs_provision
* [8] uRPF, https://www.infraexpert.com/study/aclz22.html