DUICUO

Crossplane と VCluster を使用して Kubernetes 上に新しいクラスターを迅速に構築する

Crossplaneは、Kubernetes APIを拡張することでクラウドリソースのプロビジョニングに対応するオープンソースのKubernetesプラグインです。Crossplaneを使用すると、コードを一切記述することなく、アプリケーションが正しく動作するために必要なクラウドリソースを宣言的に定義できます。これらのクラウドリソースは、関連するCRDオブジェクトを作成することで直接定義されるため、実質的にTerraformのクラウドネイティブ版と言えます。

VClusterは、軽量な仮想Kubernetesクラスターを通じて柔軟性とコスト削減を実現するツールです。VClusterを使用すると、Kubernetesクラスター内に独立した仮想Kubernetesクラスターを作成できます。これにより、Kubernetesクラスターのコントロールプレーンの作成と保守の複雑さが大幅に軽減されます。

次の表は、名前空間、vcluster、Kubernetes クラスターの使用時の分離レベルと管理の複雑さを比較したものです。

では、Crossplane と VCluster を組み合わせると何が起こるでしょうか? 例を挙げて説明しましょう。

この例では、次の機能を実現したいと考えています。

  • クラスターを作成すると、新しいクラスター環境を開始する要求を受け取ることができます。
  • これらの環境では、Helm を使用してアプリケーションをインストールできるようになります。
  • 新しい環境を要求するチームはクラスターがどこに作成されるかを気にしないため、VCluster を使用するか、クラウド プロバイダーで Kubernetes クラスターを作成すると、エンド ユーザーに同様のエクスペリエンスが提供されるはずです。

ここでは、デモのためにローカル環境でKinDを使用しています。関連リソースのリストは、https://github.com/salaboy/from-monolith-to-k8s/tree/main/platform/crossplane-vcluster で確認できます(事前にkubectl、helm、kindをインストールしておく必要があります)。

上の図に示すように、KinD クラスター(またはその他の Kubernetes クラスター)を作成し、そのクラスターに Crossplane と Crossplane Helm Provider をインストールするだけです。ここではクラウドリソースを作成しないため、他の Crossplane Provider(GCP、AWS、Azure など)を設定する必要はありません。

クロスプレーンをインストールする

次に、KinD を使用して Kubernetes クラスターを作成します。

 $ kind クラスターを作成
クラスター「kind」を作成しています...
✓ ノードイメージの確保 (kindest/node:v1.23.4) 🖼
✓ ノードを準備中 📦
✓ 設定の記述 📜
✓ コントロールプレーンを起動します 🕹️
✓ CNI のインストール 🔌
✓ StorageClass のインストール 💾
kubectlコンテキストを「kind-kind」に設定する
これで、クラスターを次のように使用できるようになります。

kubectl クラスター情報 --context の種類

ご質問、バグ、機能リクエストなどございましたら、ぜひお知らせください! https://kind.sigs.k8s.io/#community 🙂
$ kubectl ノードを取得
名前 ステータス 役割 年齢 バージョン
kind-control-plane コントロールプレーン、マスター 56s v1.23.4 が準備完了

クラスターの準備ができたら、次に示すように、Crossplane と Crossplane Helm Provider を KinD クラスターにインストールできます。

 $ kubectl ns クロスプレーンシステムを作成します
namespace/crossplane-system を作成しました
$ helm install crossplane --namespace crossplane-system crossplane-stable/crossplane

名前: クロスプレーン
最終デプロイ日時: 2022年8月9日(火) 15:20:22
名前空間: クロスプレーンシステム
ステータス: 展開済み
改訂: 1
テストスイート: なし
注記:
リリース: クロスプレーン

チャート名: クロスプレーン
チャート説明: Crossplane は、プラットフォーム チームが複数のベンダーのインフラストラクチャを組み立て、アプリケーション チームが使用できる高レベルのセルフサービス API を公開できるようにするオープン ソースの Kubernetes アドオンです。
チャートバージョン: 1.9.0
チャートアプリケーションバージョン: 1.9.0

Kube バージョン: v1.23.4

インストール後、次の 2 つの Pod が crossplane-system 名前空間で実行されます。

 $ kubectl get pods -n クロスプレーンシステム
名前 準備完了 ステータス 再起動 年齢
crossplane-c9b9fc9f9-4hn47 1/1 ランニング 0 11m
crossplane-rbac-manager-56c8ff5b65-8lgrp 1/1 実行中 0 11分

次に、Crossplane Helm Provider をインストールする必要があります。これは、crossplane kubectl プラグインを使用して直接実行できます。

 $ kubectl crossplane プロバイダーをインストール crossplane/provider-helm:v0.10.0
provider.pkg.crossplane.io/crossplane-provider-helm が作成されました

さらに、Crossplane Helm プロバイダーをインストールするときは、プロバイダーが Helm Charts をインストールできるように、プロバイダーが新しい ClusterRoleBinding を作成するための適切な ServiceAccount を提供する必要があることに注意することが重要です。

 $ SA=$(kubectl -n crossplane-system get sa -o name | grep provider-helm | sed -e 's|serviceaccount\/|crossplane-system:|g')
$ エコー $SA
クロスプレーンシステム:クロスプレーンプロバイダーヘルム-3d2f09bcd965
$ kubectl クラスターロールバインディング プロバイダー-helm-admin-binding --clusterrole cluster-admin --serviceaccount="${SA}" を作成します
clusterrolebinding.rbac.authorization.k8s.io/provider-helm-admin-binding が作成されました

次に、以下に示すように ProviderConfig オブジェクトを作成し、Helm プロバイダーのインストールを宣言します。

 # helm-provider-config.yaml
apiバージョン: helm.crossplane.io/v1beta1
種類: プロバイダー構成
メタデータ:
名前: デフォルト
仕様:
資格:
出典: InjectedIdentity

---
# SA=$(kubectl -n crossplane-system get sa -o name | grep provider-helm | sed -e 's|serviceaccount\/|crossplane-system:|g')
# kubectl クラスターロールバインディングを作成します。プロバイダー-helm-admin-binding --clusterrole cluster-admin --serviceaccount="${SA}"

上記のリソース リストを適用するだけです。

 $ kubectl apply -f helm-provider-config.yaml
providerconfig.helm.crossplane.io/default が作成されました

Crossplane のインストールはこれで完了です。最後に、Kubernetes クラスターに接続するための vcluster コマンドラインツールのインストールもお勧めします。インストール手順については、https://www.vcluster.com/docs/getting-started/setup のドキュメントをご覧ください。

クロスプレーンコンポジションを使用した VCluster の作成

CrossplaneとCrossplane Helm Providerが準備完了しました。次はCrossplane Compositionを見てみましょう。Crossplaneは、管理対象リソースをコンポジションするためのメカニズムを提供し、ユーザーは宣言的に独自の抽象化を作成できます。

  • 複合リソース(XR):複合リソースは、管理対象リソースから構成されるカスタムリソースであり、インフラストラクチャの詳細を抽象化できます。CompositeResourceDefinition(XRD)は、新しいタイプの複合リソースを定義します。XRDはクラスター全体で有効であり、名前空間固有のXRを作成するには、対応するXRDで複合リソース宣言(XRC)を提供できます。
  • コンポジション:コンポジションは、XR を構成するリソース、つまり XR を作成したときに何が起こるかを指定します。XR は複数のコンポジションを持つことができます。例えば、CompositeDatabase XR の場合、1 つのコンポジションを使用して AWS RDS インスタンス、セキュリティグループ、および MySQL データベースを作成できます。別のコンポジションでは、GCP CloudSQL インスタンスと PostgreSQL データベースを定義できます。
  • 構成: 構成は XRD であり、Crossplane CLI を使用して OCI イメージ レジストリに公開でき、宣言型構成リソースを作成して Crossplane クラスターにインストールできる要素のパッケージです。

ここでのCrossplane Composition(XR)は、新しい環境リソースを作成する際に実行する必要がある操作を定義します。このオブジェクトは以下の操作を実行します。

  • Helm Provider のインストール時に設定した Helm Provider Config を使用して、VCluster Helm Chart をインストールします。この Chart をインストールすると、新しい VCluster を作成できます。とても簡単ですね。
  • VCluster をインストールすると、VCluster APIServer に接続するためのトークンを含む Kubernetes Secret オブジェクトが作成されます。この Secret を使用して 2 つ目の Helm Provider Config を設定し、新しく作成したクラスターに Helm Chart をインストールできます。
  • 2 番目の Helm プロバイダー Config を使用して、作成された VCluster にアプリケーションをインストールできます。

次に、これがどのように実現されるかを見てみましょう。まず、新しい環境リソースを作成できるように、Crossplane CompositionとEnvironment CRDをクラスターに適用する必要があります。

まず、環境の複合リソースを定義します。対応するリソースリストは以下のとおりです。このオブジェクトは、Kubernetes クラスターの CRD に相当します。

 # 環境リソース定義.yaml
apiバージョン: apiextensions.crossplane.io/v1
種類: 複合リソース定義
メタデータ:
名前: environment.fmtok8s.salaboy.com
仕様:
グループ: fmtok8s.salaboy.com
名前:
種類: 環境
複数形:環境
クレーム名:
種類: クラスター
複数形:クラスター
バージョン:
- 名前: v1alpha1
提供:true
参照可能: true
スキーマ:
オープンAPIV3スキーマ:
タイプ: オブジェクト
プロパティ:
仕様:
タイプ: オブジェクト
プロパティ: {}

XRDコンポジションリソースを宣言したら、次はコンポジションオブジェクトを定義します。リソースマニフェストファイルの内容を以下に示します。このコンポジションオブジェクトは複数のリソースを定義し、それらは上記のXRDオブジェクトで宣言されたEnvironmentオブジェクトに関連付けられます。

 # コンポジション.yaml
apiバージョン: apiextensions.crossplane.io/v1
種類: 作曲
メタデータ:
名前: environment.fmtok8s.salaboy.com
仕様:
writeConnectionSecretsToNamespace: クロスプレーンシステム
複合タイプ参照:
apiバージョン: fmtok8s.salaboy.com/v1alpha1
種類: 環境
リソース:
- 名前: vcluster-helm-release
ベース:
apiバージョン: helm.crossplane.io/v1beta1
種類: リリース
メタデータ:
注釈:
crossplane.io/external-name: # パッチ適用済み
仕様:
ロールバック制限: 3
プロバイダー:
名前空間: # パッチ適用済み
チャート:
名前: vcluster
リポジトリ: https://charts.loft.sh
バージョン: "0.10.2"
値:
同期者:
extraArgs: [] # パッチ適用済み
# - --out-kube-config-server=https://cluster-1.cluster-1.svc
プロバイダー構成参照:
名前: デフォルト
パッチ:
- fromFieldPath: メタデータ名
toFieldPath: spec.forProvider.namespace
ポリシー:
fromFieldPath: 必須
- fromFieldPath: メタデータ名
toFieldPath: metadata.annotations[crossplane.io/外部名]
ポリシー:
fromFieldPath: 必須
- fromFieldPath: メタデータ名
toFieldPath: メタデータ名
変換します:
- 型: 文字列
弦:
形式: "%s-vcluster
- タイプ: CombineFromComposite
組み合わせる:
変数:
- fromFieldPath: メタデータ名
戦略: 文字列
弦:
fmt: "--out-kube-config-secret=%s-secret"
toFieldPath: spec.forProvider.values.syncer.extraArgs[0]
- タイプ: CombineFromComposite
組み合わせる:
変数:
- fromFieldPath: メタデータ名
- fromFieldPath: メタデータ名
戦略: 文字列
弦:
形式: "--out-kube-config-server=https://%s.%s.svc"
toFieldPath: spec.forProvider.values.syncer.extraArgs[1]
- タイプ: CombineFromComposite
組み合わせる:
変数:
- fromFieldPath: メタデータ名
- fromFieldPath: メタデータ名
戦略: 文字列
弦:
形式: "--tls-san=%s.%s.svc"
toFieldPath: spec.forProvider.values.syncer.extraArgs[2]
- 名前: helm-providerconfig
ベース:
apiバージョン: helm.crossplane.io/v1alpha1
種類: プロバイダー構成
仕様:
資格:
出典: シークレット
シークレットRef:
名前: # パッチ適用済み
名前空間: # パッチ適用済み
キー: config
パッチ:
- fromFieldPath: メタデータ名
toFieldPath: spec.credentials.secretRef.name
変換します:
- 型: 文字列
弦:
形式: vc-%s
- fromFieldPath: メタデータ名
toFieldPath: spec.credentials.secretRef.namespace
- fromFieldPath: metadata.uid
toFieldPath: メタデータ名
- 名前: helm-provider-vcluster
ベース:
apiバージョン: helm.crossplane.io/v1beta1
種類: プロバイダー構成
仕様:
資格:
出典: シークレット
シークレットRef:
名前空間: #patched
キー: config
パッチ:
- fromFieldPath: メタデータ名
toFieldPath: メタデータ名
- fromFieldPath: メタデータ名
toFieldPath: spec.credentials.secretRef.namespace
ポリシー:
fromFieldPath: 必須
# このProviderConfigは上記のVClusterの接続シークレットを
# 資格情報は秘密です。
- fromFieldPath: "metadata.name"
toFieldPath: spec.credentials.secretRef.name
変換します:
- 型: 文字列
弦:
fmt: "%s-secret"
準備チェック:
- タイプ: なし
- 名前: 会議チャートvcluster
ベース:
apiバージョン: helm.crossplane.io/v1beta1
種類: リリース
メタデータ:
注釈:
crossplane.io/外部名: カンファレンス
仕様:
プロバイダー:
チャート:
名前: fmtok8s-conference-chart
リポジトリ: https://salaboy.github.io/helm/
バージョン: "v0.1.1"
名前空間: 会議
プロバイダー構成参照:
名前: #パッチ済み
パッチ:
- fromFieldPath: メタデータ名
toFieldPath: spec.providerConfigRef.name

Crossplane で使用する VCluster Chart パッケージに 3 つのパラメータを設定します。

  • 53 行目では、`fmt: "--out-kube-config-secret=%s-secret"` を設定します。これは、VCluster で Secret オブジェクトを作成し、その中に kubeconfig をホストして、それを取得して新しく作成された APIServer に接続する必要があるためです。
  • 62行目では、`kubeconfig` がクラスター内から新しい APIServer URL を参照する必要があるため、`fmt: "--out-kube-config-server=https://%s.%s.svc"` を設定しています。デフォルトでは、生成された `kubeconfig` は `https://localhost:8443` を参照します。
  • 71 行目の構成「fmt: "--tls-san=%s.%s.svc"」は、APIServer が接続を受け入れるホストのリストに新しいサービス アドレスを追加する必要があることを示しています。

次に、上記の 2 つのオブジェクトを直接適用できます。

 $ kubectl apply -f コンポジション.yaml
composition.apiextensions.crossplane.io/environment.fmtok8s.salaboy.com が作成されました
$ kubectl apply -f 環境リソース定義.yaml
compositeresourcedefinition.apiextensions.crossplane.io/environments.fmtok8s.salaboy.com が作成されました

クラスターの複合要素と CRD が利用可能になると、新しい環境リソースの作成を開始し、実行前に現在どの VCluster が利用可能かを確認できます。

 $ vclusterリスト

名前 名前空間 ステータス 接続済み 作成日 年齢
エントリが見つかりません

まだVClustersは存在しないはずです。これで新しい環境を作成できます。例えば、`dev`環境を定義するには、以下のように`Environment`オブジェクトを宣言するだけです。

 # 環境リソース.yaml
apiバージョン: fmtok8s.salaboy.com/v1alpha1
種類: 環境
メタデータ:
名前: 開発環境
仕様: {}

オブジェクトを直接適用します。

 $ kubectl apply -f 環境リソース.yaml
environment.fmtok8s.salaboy.com/dev-environment が作成されました
$ kubectl 環境を取得する
名前 準備 構成 年齢
dev-environment False environment.fmtok8s.salaboy.com 57秒
$ kubectl 環境の説明 dev-environment
名前: 開発環境
名前空間:
ラベル: crossplane.io/composite=dev-environment
注釈: <なし>
APIバージョン: fmtok8s.salaboy.com/v1alpha1
種類: 環境
……
イベント:
タイプ 理由 年齢 送信元 メッセージ
---- ------ ---- ---- -------
通常の PublishConnectionSecret 76s defined/compositeresourcedefinition.apiextensions.crossplane.io 接続の詳細が正常に公開されました
通常のSelectComposition 19秒(76秒に7倍)defined/compositeresourcedefinition.apiextensions.crossplane.io 構成が正常に選択されました
通常の ComposeResources 18 秒 (76 秒のうち 7 倍) defined/compositeresourcedefinition.apiextensions.crossplane.io リソースが正常に構成されました

これで、作成した環境を他のKubernetesリソースと同じように扱えるようになりました。`kubectl get environments` を使って直接リストを表示したり、description を使って詳細情報を確認したりすることも可能です。

ここで VCluster を再度確認して正常であれば、新しいリソースが見つかります。

 $ vclusterリスト

名前 名前空間 ステータス 接続済み 作成日 年齢
dev-environment dev-environment 実行中 2022-08-09 17:44:07 +0800 CST 56分38秒

VClusterは、APIServer(デフォルトでK3sを使用)、CoreDNSインスタンス、Syncerを新しい名前空間dev-environmentにインストールします。これにより、ユーザーはkubectl経由でVCluster API Serverとやり取りできるようになります。通常のクラスターと同様に、VClusterはこれらのリソースをワークロードのスケジューリングを担当するホストクラスターと同期し、名前空間をKubernetesクラスターとして機能させます。

Crossplane と Crossplane Helm Provider を設定したら、新しい Helm Release を作成し、Helm Chart をインストールすることで、新しい VCluster を簡単に作成できます。

シークレット内に作成された正しいkubeconfigを使用してVClusterを作成したら、新しく作成されたVClusterにアプリケーションをインストールするための2つ目のHelmプロバイダーを設定できます。上記のコンポジションオブジェクトの95行目に定義されているhelm-provider-vclusterが、このプロバイダーの説明です。

次に、コンポジション内で、会議アプリケーション用の Helm Chart パッケージの使用を構成しました。

すべての設定を完了し、新しい環境を作成したら、VCluster に接続してアプリケーションがインストールされているかどうかを確認します。

 $ vcluster connect dev-environment --server https://localhost:8443 --bash

デフォルトの対話型シェルは zsh になりました。
zsh を使用するようにアカウントを更新するには、`chsh -s /bin/zsh` を実行してください。
詳細については、https://support.apple.com/kb/HT208050 をご覧ください。
bash-3.2$ kubectl get ns
名前 ステータス 年齢
デフォルトアクティブ32m
kube-system アクティブ 32m
kube-public アクティブ 32分
kube-node-lease アクティブ 32 分
会議 アクティブ 23分
bash-3.2$ kubectl get pods -n 会議
名前 準備完了 ステータス 再起動 年齢
conference-fmtok8s-frontend-7cd5db8669-pv944 1/1 実行中 0 23分
conference-fmtok8s-email-service-768bc88cbb-sklrg 1/1 実行中 0 23分
conference-postgresql-0 1/1 実行中 0 23分
conference-fmtok8s-c4p-service-7f56d7bd9d-2vjtx 1/1 実行中 2 (19分前) 23分
conference-redis-master-0 1/1 実行中 0 23分
conference-redis-replicas-0 1/1 実行中 0 23分
conference-fmtok8s-agenda-service-7db66c9568-xsh5m 1/1 実行中 2 (16分前) 23分

ご覧のとおり、アプリケーションはこのクラスターに正常にインストールされており、これらのアプリケーションは実際には元の KinD クラスターの dev-environment 名前空間の下にデプロイされています。

 $ kubectl get pods -n 開発環境
名前 準備完了 ステータス 再起動 年齢
conference-fmtok8s-agenda-service-7db66c9568-xsh5m-x-08f9332627 1/1 実行中 2 (18分前) 25分
conference-fmtok8s-c4p-service-7f56d7bd9d-2vjtx-x-co-fc2c58eaec 1/1 実行中 2 (21分前) 25分
conference-fmtok8s-email-service-768bc88cbb-sklrg-x--c5d9594434 1/1 実行中 0 25分
conference-fmtok8s-frontend-7cd5db8669-pv944-x-confe-2832ac1bef 1/1 実行中 0 25分
conference-postgresql-0-x-conference-x-dev-environment 1/1 実行中 0 25分
conference-redis-master-0-x-conference-x-dev-environment 1/1 実行中 0 25分
conference-redis-replicas-0-x-conference-x-dev-environment 1/1 実行中 0 25分
coredns-76dd5485df-6cbl7-x-kube-system-x-dev-environment 1/1 実行中 0 34分
dev-environment-0 2/2 実行中 0 63分

VCluster は単純に名前空間を分離し、その使用エクスペリエンスは Kubernetes クラスターと基本的に同じになります。

要約

これは、CrossplaneとVClusterを併用してKubernetesクラスタ環境を迅速に構成し、そこにアプリケーションをインストールすることで開発者の生産性を向上させる方法を示す簡単な例です。もちろん、最適化の余地は数多くあります。例えば、以下のような点です。

  • VClusterにArgoCDをインストールし、環境パラメータとして提供されるGitHub URLを使用すると、GitOpsが有効になり、VCluster上でkubectlを使用する必要がなくなります。コンポジションを使用すると、ArgoCDリソースを作成し、ユーザーの介入なしにリポジトリとクラスターを構成できます。
  • 開発者が Knative Functions、Knative Serving、Eventing 機能を利用してアプリケーションを設計できるように、VCluster に Knative をインストールします。
  • VCluster が使用するクラウド リソース (GCP、AKS、EKS など) の選択は、環境パラメータによって決まります。
  • 同様に、Crossplane もローカル KinD クラスターでテスト・使用されています。GCP、AWS、Azure などの実際のクラウドリソースにも接続できます。