8
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Microsoft Azure TechAdvent Calendar 2022

Day 14

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

Last updated at Posted at 2022-12-14
fleet_manager_title.png
fleet_demo.png
fleet_demo_mcs_10frps.gif

0.はじめに

Microsoft Ignite 2022 でも取り上げられ、先日パブリックプレビューとなりました、Azure Kubernetes Fleet Manager を試します。
Fleet Manager は複数の Kubernetes クラスターの一元管理や、複数クラスタをまたいだワークロードの実行等がおこなえるサービスです。

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

1. 前提条件

今回 Fleet のメンバーとなる、AKS クラスタは、後述する MultiClusterService を利用するため、Azure CNI の利用と同一 VNet 上にクラスターサブネットを別にした形で以下の通り、既に作成済みとします。

AKS名 リソースグループ CNI VNet クラスターサブネット K8s
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 同上 同上 同上
(同一のVNet)
10.225.0.0/16 1.23.12 同上 同上 同上

2. 事前準備

こちらのクイックスタートのドキュメントを参考に進めます。

  • 機能の有効化と extension のインストール
  • Fleet の作成 と メンバーの追加
  • hub AKS への Kubectl 接続用に ロールをアサイン

2.1 機能の有効化と extension のインストール

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

$ 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 作成時には指定せずに、作成後に、追加、削除も可能
fleet_demo_image.png
fleet_create01.png
fleet_create021.png
fleet_create022.png

作成後の Portal 画面はとてもシンプルです。
fleet_p01.png


fleet メンバー([リソースグループ名]-[ AKS 名])を確認
fleet_p02.png

Tips1: Fleet( hub ) の AKS について
Fleet の作成が終わると、FL_[Fleetリソースグループ名]_[Fleet名]_[リージョン]というリソースグループが自動的に作成され、その中に hub とよばれる特殊な AKS クラスタが作成されていることが確認できます。
FL_RG.png

なお、AKS リソースの実態はMC_FL_[Fleetリソースグループ名]_[Fleet名]_[リージョン]リソースグループの中に作成されます。
MC_FL_RG.png

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

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

kubectl より、Fleet manager の Kubernetes API(hub AKS) へアクセスするためにロールを割り当てます。
サブスクリプションとリソースグループ、作成した Fleet 名を環境変数として設定し
組み込みロール(Azure Kubernetes Fleet Manager RBAC クラスター管理者)を azure ログインアカウントへ割り当てます。

$ 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 名])を確認

$ 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 名])を確認をします。

$ 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

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

$ 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を参考にkubeloginをインストールします。
なお、Azure CloudShell を利用する場合は既にインストール済みなので不要です。

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

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

無事にインストールできると、以下のような感じで、ブラウザでのデバイスログインを求められますのでロールをアサインしたユーザーでログインします。

$ kubectl version
To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code XXXXXXXXX to authenticate.
〜 ブラウザでログイン後のつづき 〜
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 ( Kuberentes up and running demo )のデモアプリを使った、複数の AKS クラスタを跨ぐマルチクラスター間での L4 負荷分散を以下の流れでためしていきます。

  • MultiClusterServiceの前提条件
  • hub AKS へデモアプリをデプロイする
  • ClusterResourcePlacementにより、Fleet メンバーへ伝搬させる
  • MultiClusterServiceの適用
  • MultiClusterServiceによる L4 負荷分散の検証

3.1. MultiClusterServiceの前提条件

MultiClusterServiceによる L4 負荷分散の前提条件は以下の通り(詳細はこちら)です。

  • 対象 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

$ 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 するマニフェストファイルの内容は以下の通り

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

実行結果の例は以下の通りです。

  • 特徴的なのは、deploymentreplicas: 2 と設定されているのにも関わらず READY 状態が 0/2pod が起動していないことがわかります。また、serviceexportも機能していません。
  • これは Tips1 にも記載の通り、hub AKS ノードの CPU やメモリのリソースを無駄に消費させないためのものとなります。
$ 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 結果の例

$ 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 内のリソース含めてメンバーへ伝搬されていることが確認できます。また、podserviceexportも正常に機能しています。

$ 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
$ 

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

kubectx.png

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

以下、実行結果の例

$ 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-IPXXX.XXX.XXX.XXXへマスクしています

MultiClusterServiceEXTERNAL-IP:8080 へブラウザよりアクセスし kuard デモアプリが表示されることを確認します。
また、デモアプリでは、pod名podのIPアドレスが確認できます。
fleet_demo_kuard_web.png

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 の
IP アドレス
IP アドレスの
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-aks01podのIPアドレス: 10.224.0.XXX
    • 2オクテット目が 224
  • demo-aks02podのIPアドレス: 10.225.0.XXX
    • 2オクテット目が 225

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

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

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-IPXXX.XXX.XXX.XXXへマスクしています。

fleet_demo_mcs_10frps.gif

以下の通り、複数クラスタを跨いで L4 負荷分散されること確認できました。
curlリクエスト毎に上記 json 出力結果の

  • pod 名(=hostname)とpod の IP アドレス(=addrs)が変化している
    • 複数pod間で L4 負荷分散されている
  • pod の IP アドレス(=addrs)の2オクテット目が、224, 225 と変化している
    • 複数の AKS クラスタを跨いで L4 負荷分散されている

4. ロードマップ

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

5. さいごに

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

6. 参考URL

8
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?