Azure Kubernetes Fleet Manager( Preview ) で MultiClusterService L4 負荷分散を試す

<img width="600" alt="fleet_manager_title.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117986/362eaa5e-999b-1462-00d9-94b33f29353c.png">
<br>
<img width="600" alt="fleet_demo.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117986/d6949162-4825-823a-a8f8-8906c5ebe177.png">
<br>
<img width="600" alt="fleet_demo_mcs_10frps.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117986/d3222680-a769-b1ac-3ee8-1e70d06fefdd.gif">

# 0.はじめに
[Microsoft Ignite 2022 でも取り上げられ](https://news.microsoft.com/ignite-2022-book-of-news/ja/#a-251-azure-kubernetes-fleet-manager-simplifies-cluster-management-and-organization)、先日パブリックプレビューとなりました、[Azure Kubernetes Fleet Manager](https://learn.microsoft.com/ja-jp/azure/kubernetes-fleet/overview) を試します。
Fleet Manager は複数の Kubernetes クラスターの一元管理や、複数クラスタをまたいだワークロードの実行等がおこなえるサービスです。

:::note info
実行結果等を含めて本記事は、執筆時点（2022/11/30〜12/12）での内容となります
:::

# 1. 前提条件
今回 Fleet のメンバーとなる、AKS クラスタは、後述する `MultiClusterService` を利用するため、[Azure CNI](https://learn.microsoft.com/ja-jp/azure/aks/configure-azure-cni) の利用と同一 VNet 上に[クラスターサブネット](https://learn.microsoft.com/ja-jp/azure/aks/configure-azure-cni#plan-ip-addressing-for-your-cluster)を別にした形で以下の通り、既に作成済みとします。

|AKS名|リソースグループ|CNI|VNet|クラスターサブネット|K8s<br>version|ノードプール|ノードサイズ|リージョン|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|demo-aks01|demo_aks01|Azure CNI|10.224.0.0/12|10.224.0.0/16|1.23.12|手動： 1台|Standard_DS2_v2|eastus|
|demo-aks02|同上|同上|同上<br>（同一のVNet）|10.225.0.0/16|1.23.12|同上|同上|同上|


# 2. 事前準備
https://learn.microsoft.com/ja-jp/azure/kubernetes-fleet/quickstart-create-fleet-and-members

こちらのクイックスタートのドキュメントを参考に進めます。
+ 機能の有効化と extension のインストール
+ Fleet の作成 と メンバーの追加
+ `hub` AKS への Kubectl 接続用に ロールをアサイン

## 2.1 機能の有効化と extension のインストール
以下の az コマンドで Fleet を作成するサブスクリプション、メンバーとなる AKS クラスターが配置されているサブスクリプションごとに、機能を有効にします。（今回は単一のサブスクリプションを利用）
また、つづいて Fleet 用の Azure CLI の extension をインストールします。

``` bash
$ az feature register --namespace Microsoft.ContainerService --name FleetResourcePreview
Once the feature 'FleetResourcePreview' is registered, invoking 'az provider register -n Microsoft.ContainerService' is required to get the change propagated
{
  "id": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXXXXXXXXXX/providers/Microsoft.Features/providers/Microsoft.ContainerService/features/FleetResourcePreview",
  "name": "Microsoft.ContainerService/FleetResourcePreview",
  "properties": {
    "state": "Registering"
  },
  "type": "Microsoft.Features/providers/features"
}
$ az extension add --name fleet
The installed extension 'fleet' is in preview.
```

## 2.2. Fleet の作成 と メンバーの追加 
今回は、Azure Portal から Fleet の作成と、メンバーとなる AKS 追加します。
以下設定で作成します。
+ リソースグループ: demo_aks_fleetmng
+ Fleet 名: aks-fleet01
+ デプロイするリージョン: eastus
    + リージョンは Japan east / west ともに選択可能
+ メンバー
    + demo-aks-01
    + demo-aks-02
        + なお、メンバーは、Fleet 作成時には指定せずに、作成後に、追加、削除も可能
        
<img width="600" alt="fleet_demo_image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117986/8f0d60c4-651c-e725-4a3a-0e0039b3cc8f.png">
<br>
<img width="600" alt="fleet_create01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117986/24b232e8-7403-3532-760e-91c703fa84e3.png">
<br>
<img width="600" alt="fleet_create021.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117986/009c915b-b680-6376-f7fd-eaabfa02067c.png">
<br>
<img width="600" alt="fleet_create022.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117986/9f17551c-ba55-2cd1-fcde-f09e2431b3fb.png">
<br>

作成後の Portal 画面はとてもシンプルです。
<img width="600" alt="fleet_p01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117986/718b9899-cca4-14d6-5a0a-f690104ea30f.png">
<br>
fleet メンバー([リソースグループ名]-[ AKS 名])を確認
<img width="600" alt="fleet_p02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117986/96d51af9-e2b4-ce26-b6d6-7251714f4a1d.png">
<br>

:::note 
Tips1： Fleet( `hub` ) の AKS について
Fleet の作成が終わると、`FL_[Fleetリソースグループ名]_[Fleet名]_[リージョン]`というリソースグループが自動的に作成され、その中に `hub` とよばれる特殊な AKS クラスタが作成されていることが確認できます。
<img width="600" alt="FL_RG.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117986/598b53fd-186c-98bb-feb3-3d1f359c0762.png">

なお、AKS リソースの実態は`MC_FL_[Fleetリソースグループ名]_[Fleet名]_[リージョン]`リソースグループの中に作成されます。
<img width="600" alt="MC_FL_RG.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117986/ed649175-3f96-f2ca-a360-272b3fc2cb5c.png">

また、ノードプールは Standard_D4s_v4 (1 個のインスタンス)となっています。
後ほど説明しますが、こちらの`hub` AKS へ K8s の `namespace` を作成し、`deployment`などをメンバーへ 伝搬させることができます。
ただし、こちらは Fleet メンバーへの 伝搬と管理が目的の特殊な AKS のため、例えば、 `deployment`を apply しても `pod`等は起動されず、CPU やメモリ等のリソースを無駄に消費することが無いようになっています。
:::

## 2.3. `hub` AKS への Kubectl 接続用に ロールをアサイン

https://learn.microsoft.com/ja-jp/azure/kubernetes-fleet/quickstart-create-fleet-and-members#optional-access-the-kubernetes-api-of-the-fleet-resource-cluster

kubectl より、Fleet manager の Kubernetes API（`hub` AKS） へアクセスするためにロールを割り当てます。 
サブスクリプションとリソースグループ、作成した Fleet 名を環境変数として設定し
組み込みロール（Azure Kubernetes Fleet Manager RBAC クラスター管理者）を azure ログインアカウントへ割り当てます。
 
``` bash
$ SUBSCRIPTION_ID=XXXXXXXX-XXXX-XXXX-XXXXXXXXXXXX
$ GROUP=demo_aks_fleetmng
$ FLEET=aks-fleet01
$ export FLEET_ID=/subscriptions/${SUBSCRIPTION_ID}/resourceGroups/${GROUP}/providers/Microsoft.ContainerService/fleets/${FLEET}
$ echo $ FLEET_ID
/subscriptions/XXXXXXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/demo_aks_fleetmng/providers/Microsoft.ContainerService/fleets/aks-fleet01
$ export IDENTITY=$ (az ad signed-in-user show --query "id" --output tsv)
export ROLE="Azure Kubernetes Fleet Manager RBAC Cluster Admin"
az role assignment create --role "${ROLE}" --assignee ${IDENTITY} --scope ${FLEET_ID}
{
  "canDelegate": null,
  "condition": null,
  "conditionVersion": null,
  "description": null,
  "id": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/demo_aks_fleetmng/providers/Microsoft.ContainerService/fleets/aks-fleet01/providers/Microsoft.Authorization/roleAssignments/857ce606-0ea2-4350-8f7b-fff99dfeb325",
  "name": “YYYYYYYYYYYYYYYYYYY”,
  "principalId": “ZZZZZZZZZZZZZZZZZ”,
  "principalType": "User",
  "resourceGroup": "demo_aks_fleetmng",
  "roleDefinitionId": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXXXXXXXXXX/providers/Microsoft.Authorization/roleDefinitions/YYYYYYYYYYYYYYYYYYY",
  "scope": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/demo_aks_fleetmng/providers/Microsoft.ContainerService/fleets/aks-fleet01",
  "type": "Microsoft.Authorization/roleAssignments"
}
```

az コマンドで fleet メンバー([AKS リソースグループ名]-[AKS 名])を確認
``` bash
$ az fleet member list --resource-group demo_aks_fleetmng --fleet-name aks-fleet01 -o table
 
ClusterResourceId                                                                                                                         Name                   ProvisioningState    ResourceGroup
----------------------------------------------------------------------------------------------------------------------------------------  ---------------------  -------------------  -----------------
/subscriptions/XXXXXXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/demo_aks01/providers/Microsoft.ContainerService/managedClusters/demo-aks01  demo-aks01-demo-aks01  Succeeded            demo_aks_fleetmng
/subscriptions/XXXXXXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/demo_aks01/providers/Microsoft.ContainerService/managedClusters/demo-aks02  demo-aks02-demo-aks01  Succeeded            demo_aks_fleetmng
```

`az fleet get-credentials`コマンドで、fleet ( `hub` AKS )のクレデンシャルを取得し 
`kubectl get memberclusters` コマンドでも、fleet メンバー([AKS リソースグループ名]-[AKS 名])を確認をします。

``` bash
$ az fleet get-credentials --resource-group demo_aks_fleetmng --name aks-fleet01
Merged "hub" as current context in /Users/XXXX/.kube/config
$ kubectl config current-context 
hub
$ kubectl get memberclusters
NAME                    JOINED   AGE
demo-aks01-demo-aks01   True     7h14m
demo-aks02-demo-aks01   True     5h42m
```

:::note 
Tips2: `kubelogin` について
`hub` AKS への kubectl 接続には、ロールをアサインしたアカウントでの Azure ログイン認証が必要となります。

``` bash
$ kubectl get memberclusters
Unable to connect to the server: getting credentials: exec: executable kubelogin not found

It looks like you are trying to use a client-go credential plugin that is not installed.

To learn more about this feature, consult the documentation available at:
      https://kubernetes.io/docs/reference/access-authn-authz/authentication/#client-go-credential-plugins
$ 
```

ただし上記の通り、`kubelogin not found`とエラーが出てしまう場合は
[https://github.com/Azure/kubelogin](https://github.com/Azure/kubelogin)を参考に`kubelogin`をインストールします。
なお、Azure CloudShell を利用する場合は既にインストール済みなので不要です。

以下は Mac の場合に brew でインストールする例

``` bash
$ brew install Azure/kubelogin/kubelogin
Running `brew update --auto-update`...
==> Auto-updated Homebrew!
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
（中略）
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
$ 
```

無事にインストールできると、以下のような感じで、ブラウザでのデバイスログインを求められますのでロールをアサインしたユーザーでログインします。
``` bash
$ kubectl version
To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code XXXXXXXXX to authenticate.
```

``` bash
〜 ブラウザでログイン後のつづき 〜
WARNING: This version information is deprecated and will be replaced with the output from kubectl version --short.  Use --output=yaml|json to get the full version.
Client Version: version.Info{Major:"1", Minor:"25", GitVersion:"v1.25.2", GitCommit:"5835544ca568b757a8ecae5c153f317e5736700e", GitTreeState:"clean", BuildDate:"2022-09-21T14:33:49Z", GoVersion:"go1.19.1", Compiler:"gc", Platform:"darwin/amd64"}
Kustomize Version: v4.5.7
Unable to connect to the server: context deadline exceeded (Client.Timeout exceeded while awaiting headers)
$ 
```
:::

# 3. 複数 AKS クラスタを跨ぐ `MultiClusterService`の L4 負荷分散を試す
準備ができたので、以下を参考に、[kuard](https://github.com/kubernetes-up-and-running/kuard) （ Kuberentes up and running demo ）のデモアプリを使った、複数の AKS クラスタを跨ぐマルチクラスター間での L4 負荷分散を以下の流れでためしていきます。
+ `MultiClusterService`の前提条件
+ `hub` AKS へデモアプリをデプロイする
+ `ClusterResourcePlacement`により、Fleet メンバーへ伝搬させる
+ `MultiClusterService`の適用
+ `MultiClusterService`による L4 負荷分散の検証

https://learn.microsoft.com/ja-jp/azure/kubernetes-fleet/architectural-overview#multi-cluster-load-balancing

https://learn.microsoft.com/ja-jp/azure/kubernetes-fleet/l4-load-balancing

https://github.com/Azure/AKS/tree/master/examples/fleet/kuard

## 3.1. `MultiClusterService`の前提条件
`MultiClusterService`による L4 負荷分散の前提条件は以下の通り（[詳細はこちら](https://learn.microsoft.com/ja-jp/azure/kubernetes-fleet/l4-load-balancing#prerequisites)）です。
+ 対象 AKS クラスタが 同一の Fleet Manager のメンバーとなっている
+ 対象 AKS クラスタが Azure CNI を利用している
+ 対象 AKS クラスタが同一 VNet または、VNet ピアリング接続されている

また、Kubectl コマンドにて各 AKS クラスタへの操作ができることを前提とします。
+ `hub` およびメンバーの AKS クラスタのクレデンシャル（kubeconfig）が取得できている
+ `kubectl` コマンドおよび、`kubelogin`プラグイン（ Tips2 参照）がインストールされている

## 3.2. `hub` AKS へデモアプリをデプロイする
まずは、kubeconfig の接続先（ current-context ）を `hub` AKS に設定し、
`kubectl config use-context hub`

デモアプリをデプロイする k8s `namespace` を作成します
`kubectl create ns kuard-demo`

``` bash
$ kubectl config get-contexts 
CURRENT   NAME         CLUSTER      AUTHINFO                                                  NAMESPACE
          demo-aks01   demo-aks01   clusterUser_demo_aks01_demo-aks01                         
          demo-aks02   demo-aks02   clusterUser_demo_aks01_demo-aks02                         
*         hub          hub          clusterUser_FL_demo_aks_fleetmng_aks-fleet01_eastus_hub   
$ kubectl config use-context hub
Switched to context "hub".
$ 
$ kubectl create ns kuard-demo
namespace/kuard-demo created
$ kubectl get ns
NAME                                 STATUS   AGE
default                              Active   22d
fleet-member-demo-aks01-demo-aks01   Active   21d
fleet-member-demo-aks02-demo-aks01   Active   21d
hello-world                          Active   21d
kuard-demo                           Active   1m33s
kube-node-lease                      Active   22d
kube-public                          Active   22d
kube-system                          Active   22d
$ 
```

つづいて、kuard のデモアプリを `hub` aks へデプロイします。
`kubectl apply -f https://raw.githubusercontent.com/Azure/AKS/master/examples/fleet/kuard/kuard-export-service.yaml`

apply する[マニフェストファイル](https://raw.githubusercontent.com/Azure/AKS/master/examples/fleet/kuard/kuard-export-service.yaml)の内容は以下の通り
``` yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: kuard
  namespace: kuard-demo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: kuard
  template:
    metadata:
      labels:
        app: kuard
    spec:
      containers:
        - name: kuard
          image: gcr.io/kuar-demo/kuard-amd64:blue
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: 250m
              memory: 256Mi
---
apiVersion: v1
kind: Service
metadata:
  name: kuard
  namespace: kuard-demo
  labels:
    app: kuard
spec:
  ports:
    - port: 8080
  selector:
    app: kuard
---
apiVersion: networking.fleet.azure.com/v1alpha1
kind: ServiceExport
metadata:
  name: kuard
  namespace: kuard-demo
```

実行結果の例は以下の通りです。
+ 特徴的なのは、`deployment` で `replicas: 2` と設定されているのにも関わらず READY 状態が `0/2` と `pod` が起動していないことがわかります。また、`serviceexport`も機能していません。
+ これは Tips1 にも記載の通り、`hub` AKS ノードの CPU やメモリのリソースを無駄に消費させないためのものとなります。

``` bash
$ kubectl apply -f https://raw.githubusercontent.com/Azure/AKS/master/examples/fleet/kuard/kuard-export-service.yaml
deployment.apps/kuard created
service/kuard created
serviceexport.networking.fleet.azure.com/kuard created
$ kubectl get all -n kuard-demo
NAME            TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
service/kuard   ClusterIP   10.0.148.120   <none>        8080/TCP   4m13s

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/kuard   0/2     0            0           4m13s
$ kubectl get serviceexport kuard -n kuard-demo
NAME    IS-VALID   IS-CONFLICTED   AGE
kuard                              21d
```

## 3.3. `ClusterResourcePlacement`により、Fleet メンバーへ伝搬させる
つづいて、`hub` AKS 内のデモアプリのリソースを、メンバーの AKS クラスタへ 伝搬させるために
`Kind: ClusterResourcePlacement`の以下のマニフェストファイル`kuard-crp.yaml`を作成し `hub` AKS へ apply します。
こちらは `hub` AKS 内の K8s namespace `kuard-demo` の内容を  Fleet メンバーの AKS クラスタのうち、条件として `clusterSelectorTerms` で指定した `eastus` にデプロイされている AKS にへ 伝搬します。

``` kuard-crp.yaml
apiVersion: fleet.azure.com/v1alpha1
kind: ClusterResourcePlacement
metadata:
  name: kuard-demo
spec:
  resourceSelectors:
    - group: ""
      version: v1
      kind: Namespace
      name: kuard-demo
  policy:
    affinity:
      clusterAffinity:
        clusterSelectorTerms:
          - labelSelector:
              matchLabels:
                fleet.azure.com/location: eastus
```

apply 結果の例
``` bash
$ kubectl apply -f kuard-crp.yaml
clusterresourceplacement.fleet.azure.com/kuard-demo created
$ kubectl get clusterresourceplacements.fleet.azure.com 
NAME          GEN   SCHEDULED   SCHEDULEDGEN   APPLIED   APPLIEDGEN   AGE
kuard-demo    1     True        1              True      1            3m10s
$ 
```

つづいて、Fleet メンバーの AKS へ 伝搬されていることを確認します。
kubeconfig の接続先（ `current-context` ）を`demo-aks01`,`demo-aks02`にそれぞれ切り替えて確認します。

以下確認結果
`hub` AKS で`Kind: ClusterResourcePlacement`で設定したとおり、k8s `namespace` `kuard-demo` 内のリソース含めてメンバーへ伝搬されていることが確認できます。また、`pod`や`serviceexport`も正常に機能しています。

``` bash
$ kubectl config use-context demo-aks01
Switched to context "demo-aks01".
$ kubectl get all -n kuard-demo
NAME                        READY   STATUS    RESTARTS   AGE
pod/kuard-7788d9bc5-8f8fz   1/1     Running   0          9d
pod/kuard-7788d9bc5-nqztl   1/1     Running   0          9d

NAME            TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
service/kuard   ClusterIP   10.0.171.245   <none>        8080/TCP   21d

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/kuard   2/2     2            2           9d

NAME                              DESIRED   CURRENT   READY   AGE
replicaset.apps/kuard-7788d9bc5   2         2         2       9d
$ kubectl get serviceexport kuard -n kuard-demo
NAME    IS-VALID   IS-CONFLICTED   AGE
kuard   True       False           9d
$ 
$ kubectl config use-context demo-aks02
Switched to context "demo-aks02".
$ kubectl get all -n kuard-demo
NAME                        READY   STATUS    RESTARTS   AGE
pod/kuard-7788d9bc5-bzsnb   1/1     Running   0          9d
pod/kuard-7788d9bc5-hcdzp   1/1     Running   0          9d

NAME            TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)    AGE
service/kuard   ClusterIP   10.0.153.57   <none>        8080/TCP   21d

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/kuard   2/2     2            2           9d

NAME                              DESIRED   CURRENT   READY   AGE
replicaset.apps/kuard-7788d9bc5   2         2         2       9d
$ kubectl get serviceexport kuard -n kuard-demo
NAME    IS-VALID   IS-CONFLICTED   AGE
kuard   True       False           9d
$ 
```

:::note 
Tips3： kubeconfig context の切り替えについて
複数の Kubernets クラスタへの接続 context を切り替えたい場合
[kubectx](https://github.com/ahmetb/kubectx) を利用すると便利です。
`kubectl config get-contexts` や `kubectl config use-context`のコマンドをそれぞれ、`kubectx`と`kubectx [context名]`に置き換えられます
色が異なっているのが`current context`です。

<img width="400" alt="kubectx.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117986/1d726694-9f4e-31e2-767b-30a2d8ea6622.png">
<br>
:::

## 3.4. `MultiClusterService`の適用
Fleet メンバーのいずれにか(今回は `demo-aks01` )に、`MultiClusterService`を適用し、事前に`servicexport`されているエンドポイント間を L4 負荷分散します。

`kubectl apply -f https://raw.githubusercontent.com/Azure/AKS/master/examples/fleet/kuard/kuard-mcs.yaml`

``` kuard-mcs.yaml
apiVersion: networking.fleet.azure.com/v1alpha1
kind: MultiClusterService
metadata:
  name: kuard
  namespace: kuard-demo
spec:
  serviceImport:
    name: kuard
```

以下、実行結果の例
``` bash
$ kubectl config use-context demo-aks01
Switched to context "demo-aks01".
$ kubectl apply -f https://raw.githubusercontent.com/Azure/AKS/master/examples/fleet/kuard/kuard-mcs.yaml
multiclusterservice.networking.fleet.azure.com/kuard created
$ kubectl get MultiClusterService -n kuard-demo
NAME    SERVICE-IMPORT   EXTERNAL-IP       IS-VALID   AGE
kuard   kuard            XXX.XXX.XXX.XXX   True       9d
$ kubectl get all -n fleet-system
NAME                       TYPE           CLUSTER-IP    EXTERNAL-IP      PORT(S)          AGE
service/kuard-demo-kuard   LoadBalancer   10.0.20.159   XXX.XXX.XXX.XXX  8080:31125/TCP   9d
$ 
```
*:上記で`EXTERNAL-IP`は`XXX.XXX.XXX.XXX`へマスクしています

`MultiClusterService` の `EXTERNAL-IP`：8080 へブラウザよりアクセスし kuard デモアプリが表示されることを確認します。
また、デモアプリでは、`pod名`と`podのIPアドレス`が確認できます。
<img width="600" alt="fleet_demo_kuard_web.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117986/3efa4c09-a5d4-be58-ed57-b44e072bb8df.png">
<br>

## 3.5. `MultiClusterService`による L4 負荷分散の検証
つづいて、複数クラスタを跨いで L4 負荷分散されることを確認します。

それぞれの AKS クラスタ上で動作しているデモアプリの`pod 名`と`pod の IP アドレス`を確認します。

```
$ kubectl config use-context demo-aks01
Switched to context "demo-aks01".
$ kubectl get po -o wide -n kuard-demo
NAME                    READY   STATUS    RESTARTS   AGE   IP             NODE                                NOMINATED NODE   READINESS GATES
kuard-7788d9bc5-8f8fz   1/1     Running   0          9d    10.224.0.104   aks-agentpool-35471025-vmss000003   <none>           <none>
kuard-7788d9bc5-nqztl   1/1     Running   0          9d    10.224.0.43    aks-agentpool-35471025-vmss000003   <none>           <none>
$ kubectl config use-context demo-aks02
Switched to context "demo-aks02".
$ kubectl get po -o wide -n kuard-demo
NAME                    READY   STATUS    RESTARTS   AGE   IP            NODE                                NOMINATED NODE   READINESS GATES
kuard-7788d9bc5-bzsnb   1/1     Running   0          9d    10.225.0.60   aks-agentpool-33918313-vmss000003   <none>           <none>
kuard-7788d9bc5-hcdzp   1/1     Running   0          9d    10.225.0.29   aks-agentpool-33918313-vmss000003   <none>           <none>
$ 
```

上記を表にまとめると

|AKS 名|pod 名|pod の<br>IP アドレス|IP アドレスの<br>2オクテット目|
|:-:|:--|:--|:-:|
|`demo-aks01`|kuard-7788d9bc5-8f8fz|10.**224**.0.104|**224**|
|`demo-aks01`|kuard-7788d9bc5-nqztl|10.**224**.0.43|**224**|
|`demo-aks02`|kuard-7788d9bc5-bzsnb|10.**225**.0.60|**225**|
|`demo-aks02`|kuard-7788d9bc5-hcdzp|10.**225**.0.29|**225**|

IP アドレスの2オクテット目に注目すると、どちらの AKS クラスタで動いているか簡易に判別できることがわかります。
+ `demo-aks01` の`podのIPアドレス`： 10.224.0.XXX
    + 2オクテット目が **224**
+ `demo-aks02` の`podのIPアドレス`： 10.225.0.XXX
    + 2オクテット目が **225**

そこで、1秒毎に`curl`コマンドを発行し、`pod 名`と`pod の IP アドレス`を確認します。

確認用の`curl`コマンドは以下

``` bash
watch -n 1 "curl -s XXX.XXX.XXX.XXX:8080 | grep hostname | sed 's/var pageContext = //g' | jq | sed 's/XXX.XXX.XXX.XXX/xxx.xxx.xxx.xxx/g'"
```
*:上記で`EXTERNAL-IP`は`XXX.XXX.XXX.XXX`へマスクしています。

<img width="600" alt="fleet_demo_mcs_10frps.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117986/d3222680-a769-b1ac-3ee8-1e70d06fefdd.gif">
<br>

以下の通り、複数クラスタを跨いで L4 負荷分散されること確認できました。
`curl`リクエスト毎に上記 json 出力結果の 
+ `pod 名`(=`hostname`)と`pod の IP アドレス`(=`addrs`)が変化している
    + 複数`pod`間で L4 負荷分散されている
+ `pod の IP アドレス`(=`addrs`)の2オクテット目が、**224, 225** と変化している
    + 複数の AKS クラスタを跨いで L4 負荷分散されている

# 4. ロードマップ
ロードマップの最新状況については以下 Github 上で公開されています

https://github.com/Azure/AKS/projects/3

# 5. さいごに
今回、Azure Kubernetes Fleet Manager を試してみた感想ですが、
特に複雑な部分はないと思いますので、普段 AKS を触っている方達は特に抵抗なく利用できるのではと思います。
パブリックプレビュー直後ということもあり、現在提供されている機能の多くは、例えば同一のリポジトリを複数クラスタから参照する GitOps の活用や、Azure の各種負荷分散機能の組み合わせにて代替可能な部分も多いと思いますが、個人的にはとても興味深いサービスだと思いますので、今後のロードマップによる機能拡充にも期待しています。

# 6. 参考URL
https://news.microsoft.com/ignite-2022-book-of-news/ja/#a-251-azure-kubernetes-fleet-manager-simplifies-cluster-management-and-organization

https://learn.microsoft.com/ja-jp/azure/kubernetes-fleet/quickstart-create-fleet-and-members

https://learn.microsoft.com/ja-jp/azure/kubernetes-fleet/architectural-overview#multi-cluster-load-balancing

https://learn.microsoft.com/ja-jp/azure/kubernetes-fleet/l4-load-balancing

https://github.com/Azure/kubelogin

https://github.com/Azure/AKS/tree/master/examples/fleet/

https://github.com/kubernetes-up-and-running/kuard

https://github.com/ahmetb/kubectx

https://github.com/Azure/AKS/projects/3