APC 技術ブログ

株式会社エーピーコミュニケーションズの技術ブログです。

株式会社 エーピーコミュニケーションズの技術ブログです。

[Cluster API] AKS on K8sクラスタを立ててみよう

こんにちは、ACS事業部の谷合です。
事業部内の有志でCluster APIを触ってまして、とりあえずAKSにCluster APIリソースをデプロイしてAKS on K8sクラスタができることを確認できたのでご紹介します。

Cluster APIとは

KubernetesのSIG Cluster Lifecycleのsubprojectであり、ホストKubernetesにKubernetesクラスタAPIのリソースを作成し、そのリソースに沿ったクラスタを自動でプロビジョニング可能とするツールです。宣言的にKubernetesクラスタを管理できることからKubernetes as a Service(以降KaaS)などのKubernetesクラスタ払い出し自動化分野で使われることが期待されます。 また、弊社はMicrosoft Partnerでありますが、Microsoftからも以下の資料のようにCluster APIに注目している旨の記事が提供されています。GitOpsでKubernetesクラスタAPIのリソースマニフェストをホストKubernetesにデプロイし、自動でクラスタ払い出しの仕組みはとても面白いですね。 cloudblogs.microsoft.com

以下のCluster API公式ドキュメントでもユースケースごとに「現時点でのプロジェクトの優先順位」が公表されており、 Managed Cluster、KaaSの順で優先度が設定されているようです。

cluster-api.sigs.k8s.io

Cluster APIコンセプト

以下のようにnamespceごとに異なるProviderをデプロイし、各Providerが協調しながらClusterを払い出します。
各ProviderはControllerとして実装されており、CRD経由でCustomResourceを提供することでクラスタのコンポーネントを宣言的に管理しています。

このProviderについてこのセクションで触れてみます。

Infrastracture

クラスタノードの実行に必要な前提条件をすべて提供します。
例えば、VM、ネットワーク、ロードバランサー、ファイアウォールルールなどです。
主要なクラウドサービス向けのプロバイダーが公開されています。

Bootstrap

ノードのブートストラップに使用されるブートストラップデータを生成します。
kubeadmなどを使ったBootstrap手段が提供されます。

Control plane

Control planeを作成します。 以下のリソースをインスタンス化して作成するとのことです。

  • etcd
  • Kubernetes APIサーバー
  • Kubernetes コントローラーマネージャー
  • Kubernetes スケジューラ
  • クラウドコントローラーマネージャー
  • クラスタDNS(CoreDNSなど)
  • サービスプロキシ(例:kube-proxy)

Azure用であれば、以下のCluster API Provider Azureというものが提供されており、多様な設定が可能となっています。 capz.sigs.k8s.io

Kubernetes払い出し

今回は以下の手順に沿って作業します。 cluster-api.sigs.k8s.io なお、AKSで作業を行うため、ドキュメント内のInstall clusterctlの手順からスタートします。

clusterctlインストール

まず、clusterctlコマンドをインストールします。

curl -L https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.4.1/clusterctl-linux-amd64 -o clusterctl
sudo install -o root -g root -m 0755 clusterctl /usr/local/bin/clusterctl
clusterctl version

Feature Gateの有効化

export CLUSTER_TOPOLOGY=true

管理クラスターを初期化

初期化を行い、Cluster APIリソースをデプロイします。

サービスプリンシパル作成

作成後に出力される結果から、appIdとpasswordを控えておいてください。

export AZURE_SUBSCRIPTION_ID=$(az account show -o tsv --query id)
export AZURE_TENANT_ID=$(az account show -o tsv --query tenantId)
az ad sp create-for-rbac --role contributor --scopes="/subscriptions/${AZURE_SUBSCRIPTION_ID}" --display-name "capi-sp"

出力例

The output includes credentials that you must protect. Be sure that you do not include these credentials in your code or check the credentials into your source control. For more information, see https://aka.ms/azadsp-cli
{
  "appId": "d3029603-0320-4f4f-af59-1ecb75065ada",
  "displayName": "capi-sp",
  "password": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "tenant": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

環境変数設定

AZURE_CLIENT_IDとAZURE_CLIENT_SECRETには、前の作業で控えておいたappIdとpasswordを入れます。

export AZURE_CLIENT_ID=<appId>
export AZURE_CLIENT_SECRET=<password>
export AZURE_SUBSCRIPTION_ID_B64="$(echo -n "$AZURE_SUBSCRIPTION_ID" | base64 | tr -d '\n')"
export AZURE_TENANT_ID_B64="$(echo -n "$AZURE_TENANT_ID" | base64 | tr -d '\n')"
export AZURE_CLIENT_ID_B64="$(echo -n "$AZURE_CLIENT_ID" | base64 | tr -d '\n')"
export AZURE_CLIENT_SECRET_B64="$(echo -n "$AZURE_CLIENT_SECRET" | base64 | tr -d '\n')"
export AZURE_CLUSTER_IDENTITY_SECRET_NAME="cluster-identity-secret"
export CLUSTER_IDENTITY_NAME="cluster-identity"
export AZURE_CLUSTER_IDENTITY_SECRET_NAMESPACE="default"

kubectlシークレット作成

上記で設定した環境変数を使用し、シークレットを作成します。

kubectl create secret generic "${AZURE_CLUSTER_IDENTITY_SECRET_NAME}" \
--from-literal=clientSecret="${AZURE_CLIENT_SECRET}" \
--namespace "${AZURE_CLUSTER_IDENTITY_SECRET_NAMESPACE}"

初期化

clusterctl init --infrastructure azure

出力例

Fetching providers
Installing cert-manager Version="v1.11.0"
Waiting for cert-manager to be available...
Installing Provider="cluster-api" Version="v1.0.0" TargetNamespace="capi-system"
Installing Provider="bootstrap-kubeadm" Version="v1.0.0" TargetNamespace="capi-kubeadm-bootstrap-system"
Installing Provider="control-plane-kubeadm" Version="v1.0.0" TargetNamespace="capi-kubeadm-control-plane-system"
Installing Provider="infrastructure-docker" Version="v1.0.0" TargetNamespace="capd-system"

Your management cluster has been initialized successfully!

You can now create your first workload cluster by running the following:

clusterctl generate cluster [name] --kubernetes-version [version] | kubectl apply -f -

初期化を行うことで、以下のようにAzure用のAPIが追加されていることが確認可能となります。

kubectl api-resources -o name | grep azure
azureidentities.aadpodidentity.k8s.io
azureidentitybindings.aadpodidentity.k8s.io
azurepodidentityexceptions.aadpodidentity.k8s.io
azureclusteridentities.infrastructure.cluster.x-k8s.io
azureclusters.infrastructure.cluster.x-k8s.io
azureclustertemplates.infrastructure.cluster.x-k8s.io
azuremachinepoolmachines.infrastructure.cluster.x-k8s.io
azuremachinepools.infrastructure.cluster.x-k8s.io
azuremachines.infrastructure.cluster.x-k8s.io
azuremachinetemplates.infrastructure.cluster.x-k8s.io
azuremanagedclusters.infrastructure.cluster.x-k8s.io
azuremanagedcontrolplanes.infrastructure.cluster.x-k8s.io
azuremanagedmachinepools.infrastructure.cluster.x-k8s.io

払い出すターゲットクラスタyaml生成

環境変数設定

export AZURE_LOCATION=<リージョン>
export AZURE_CONTROL_PLANE_MACHINE_TYPE="Standard_D2s_v3"※VMサイズ
export AZURE_NODE_MACHINE_TYPE="Standard_D2s_v3"※VMサイズ
export AZURE_RESOURCE_GROUP="<ResourceGroupName>"

クラスタyaml生成

clusterctl generate cluster capi-quickstart \
  --kubernetes-version v1.27.0 \
  --control-plane-machine-count=3 \
  --worker-machine-count=3 \
  > capi-quickstart.yaml

(オプション)ノード数を1にし、Clusterリソースのlocationをjapaneastにする

sed -i -e 's/location: centralus/location: japaneast/g' -e 's/replicas: 3/replicas: 1/g' capi-quickstart.yaml 

yamlファイルは以下のようになります。

クラスタyaml適用

kubectl apply -f capi-quickstart.yaml

出力例

cluster.cluster.x-k8s.io/capi-quickstart created
azurecluster.infrastructure.cluster.x-k8s.io/capi-quickstart created
kubeadmcontrolplane.controlplane.cluster.x-k8s.io/capi-quickstart-control-plane created
azuremachinetemplate.infrastructure.cluster.x-k8s.io/capi-quickstart-control-plane created
machinedeployment.cluster.x-k8s.io/capi-quickstart-md-0 created
azuremachinetemplate.infrastructure.cluster.x-k8s.io/capi-quickstart-md-0 created
kubeadmconfigtemplate.bootstrap.cluster.x-k8s.io/capi-quickstart-md-0 created
azureclusteridentity.infrastructure.cluster.x-k8s.io/cluster-identity created

クラスタ確認

プロビジョニングには数分かかるため、数分後に以下のコマンドでクラスタが確認可能となります。

kubectl get kubeadmcontrolplane 
NAME                            CLUSTER           INITIALIZED   API SERVER AVAILABLE   REPLICAS   READY   UPDATED   UNAVAILABLE   AGE     VERSION
capi-quickstart-control-plane   capi-quickstart   true                                 1                  1         1             5m36s   v1.26.3

クラスタアクセス

kubeconfig生成

clusterctl get kubeconfig capi-quickstart > .kube/capi-quickstart.kubeconfig

クラスタアクセス

この時まだ、CNIがインストールされていないため、ノードはNotReadyとなっています。

export KUBECONFIG=.kube/capi-quickstart.kubeconfig
kubectl config use-context=<コンテキスト>
kubectl get node -owide
NAME                                  STATUS     ROLES           AGE     VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
capi-quickstart-control-plane-q45qm   NotReady   control-plane   2m34s   v1.26.3   10.0.0.4      <none>        Ubuntu 22.04.2 LTS   5.15.0-1034-azure   containerd://1.6.19
capi-quickstart-md-0-rmbpv            NotReady   <none>          34s     v1.26.3   10.1.0.4      <none>        Ubuntu 22.04.2 LTS   5.15.0-1034-azure   containerd://1.6.19

CNIインストール

今回はCalicoをインストールします。

kubectl --kubeconfig=.kube/capi-quickstart.kubeconfig \
  apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.24.1/manifests/calico.yaml

# taint削除
# ノードはWorkerNodeとします。
kubectl taint node capi-quickstart-md-0-rmbpv node.cloudprovider.kubernetes.io/uninitialized-
kubectl taint node capi-quickstart-md-0-rmbpv node.cluster.x-k8s.io/uninitialized-

Node確認

kubectl get node
NAME                                  STATUS   ROLES           AGE   VERSION
capi-quickstart-control-plane-q45qm   Ready    control-plane   22m   v1.26.3
capi-quickstart-md-0-rmbpv            Ready    <none>          20m   v1.26.3

管理クラスタ側で再度確認すると、以下のようにクラスタが起動していることが確認できます。

$ kubectl get kubeadmcontrolplane 
NAME                            CLUSTER           INITIALIZED   API SERVER AVAILABLE   REPLICAS   READY   UPDATED   UNAVAILABLE   AGE   VERSION
capi-quickstart-control-plane   capi-quickstart   true          true                   1          1       1         0             28m   v1.26.3

Azureリソース確認

クラスタを払い出すと、以下のようにAzureリソースも作成されます。
この時、Control PlaneとWorkerそれぞれにVM, NIC, Disk, NSGが作成されます。
また、別でLB, Route Table, VNet, Public IPも作成されます。

名前                                         種類                                場所
capi-quickstart-control-plane-skgrq          仮想マシン                          Japan East
capi-quickstart-control-plane-skgrq-nic      ネットワーク インターフェイス         Japan East
capi-quickstart-control-plane-skgrq_etcddisk ディスク                            Japan East
capi-quickstart-control-plane-skgrq_OSDisk   ディスク                            Japan East
capi-quickstart-controlplane-nsg             ネットワーク セキュリティ グループ    Japan East
capi-quickstart-md-0-wcr72                   仮想マシン                          Japan East
capi-quickstart-md-0-wcr72-nic               ネットワーク インターフェイス         Japan East
capi-quickstart-md-0-wcr72_OSDisk            ディスク                            Japan East
capi-quickstart-node-nsg                     ネットワーク セキュリティ グループ    Japan East
capi-quickstart-node-routetable              ルート テーブル                     Japan East
capi-quickstart-public-lb                    ロード バランサー                   Japan East
capi-quickstart-vnet                         仮想ネットワーク                    Japan East
pip-capi-quickstart-apiserver                パブリック IP アドレス              Japan East
pip-capi-quickstart-node-subnet-natgw        パブリック IP アドレス              Japan East

ここまでくると、通常のKuberntestクラスタとして自由に遊べるようになります。
yaml適用でクラスタ払い出しできるなんて、便利!!!!!!

Azure Service Operatorとの違い

実は、ClusterAPIを使わずともAKS上にKubernetesクラスタ(AKS)を立てることは可能です。
これについて、Microsoftは以下のように述べています。
クラスタのテストや、設定項目の多様さはClusterAPIに分がありそうですね。
ただ、最新AKSを使えるというのはAzure Service Operatorの大きなメリットとなりそうです。
ケースバイケースで使い分けるといいでしょう。

Both are valid options to provision AKS clusters. The benefit of using CAPZ is it has several elements of testing to ensure that provisioning this specific type of IaC configuration for an AKS cluster will work. Also, it enables a consistent CAPI cluster YAML definition across cloud providers. The advantage of ASO is that it enables provisioning of whatever features are available in AKS the moment it comes out, whereas today CAPZ needs time to add and test available AKS features to fit into the requirements needed to be consistent with the cluster API framework. CAPZ does bi-weekly patch releases and major releases every two months.

なお、Azure Service Operatorは以前以下のポストで検証をしています。 techblog.ap-com.co.jp

さいごに

いかがでしたでしょうか?
Kubernetesを宣言的に管理できるというのは非常に面白みがあります。
今回はAKS on K8sクラスタを試してみましたが、次回はAKS on AKSも試してみたいと思います。
AKS on AKSは以下のドキュメントに記載ありますので、もしご興味あればご覧ください。
また、自由度も高く、なんとProviderの自作までできちゃいます!!!
次回以降でProvider自作にチャレンジしたいと思います。 capz.sigs.k8s.io

前述したMicrosoftの記事内でも言及されていますが、Cluster APIはPlatform Engineeringと非常に相性がいいです。
弊社でもPlatform Engineeringは注目して、啓蒙活動にも力を入れているため、Cluster APIの調査は継続していきたいと思います。

The other big benefit this pattern provides is a foundation for platform engineering in an organization.

ACS事業部のご紹介

私達ACS事業部はAzure・AKSなどのクラウドネイティブ技術を活用した内製化のご支援をしております。
www.ap-com.co.jp また、一緒に働いていただける仲間も募集中です!
今年もまだまだ組織規模拡大中なので、ご興味持っていただけましたらぜひお声がけください。 www.ap-com.co.jp

本記事の投稿者: 谷合純也
AKS/ACAをメインにインフラ系のご支援を担当しています。
junya0530さんの記事一覧 | Zenn