単一Kubernetesクラスターを共有する際の問題
開発チーム全員が同じKubernetesクラスターを共有したことがある方なら、その苦労はよくわかるはずです。誰かが誤って他人のネームスペースを削除してしまう。リソースクォータの設定ミスで別の開発者のデプロイが壊れる。新人がClusterRoleを誤って適用して、チームの半数がデプロイできなくなる——そんなことが起きます。
よくある解決策は「クラスターを分ける」か「ネームスペースで分離する」かの二択です。どちらも実際のコストが伴い、すべてのチームにとって最適とは言えません。
3つのアプローチを比較する
1. 完全に分離したクラスター(開発者ごとに1クラスター)
各開発者が専用クラスターを持つ方法です。ローカル環境(kind、minikube)またはクラウドでプロビジョニングします。
- 完全な分離:他の人が干渉できない
- 自由度が高い:任意のCRDをインストール、クラスターレベルの設定を変更できる
- コストが高い:クラウドクラスターは費用がかかり、ローカルでも4〜8GBのRAMを消費する
- 起動が遅い:実際のクラスターのプロビジョニングには秒単位ではなく分単位の時間がかかる
2. ネームスペースによる分離(全員が1つのクラスターを使用)
各開発者(またはチーム・環境)が専用ネームスペースを持ち、RBACルールで操作範囲を制限します。
- リソース効率が良い:コントロールプレーンを全員で共有できる
- 高速:ネームスペースは数秒で作成できる
- 分離が不完全:クラスターレベルのリソース(CRD、ClusterRole、ノード)は共有されたまま
- RBACの複雑さ:過剰な権限付与なしに適切なパーミッションを設定するのは難しい
- 開発者にcluster-adminを与えられない:CRDやClusterRoleが必要なHelmチャートをインストールできない
3. vclusterによる仮想クラスター
vclusterは、ホストクラスターのネームスペース内で完全に機能するKubernetes APIサーバーを動かします。開発者からは完全なadminアクセス権を持つ本物のクラスターに見え、ホストクラスター側からはネームスペース内のいくつかのPodとして見えます。
- 軽量:各vclusterは実際のクラスターより大幅に少ないリソースで動作する
- 高速:新しい仮想クラスターは60秒以内に起動できる
- 完全な分離:各vclusterが独自のAPIサーバー、etcd(またはSQLite)、コントロールプレーンを持つ
- cluster-adminアクセス:開発者はCRDのインストール、ClusterRoleの作成など何でもできる——ホストには影響しない
- ホストレベルのワークロード:実際のPodはホストクラスターのノード上で動作する(vclusterが同期する)
vclusterのメリットとデメリット
vclusterが得意なこと
- 開発用サンドボックス:数秒で分離された環境を立ち上げ、作業が終わったら削除できる。プラットフォームチームがクリーンアップする手間がない。
- CI/CDパイプライン:パイプライン実行ごとに専用クラスターで結合テストを実行できる。実行間で状態が漏れない。
- マルチテナントSaaS:実際のクラスターをプロビジョニングするコストなしに、顧客ごとに仮想クラスターを提供できる。
- トレーニング環境:受講者がインフラを危険にさらすことなく、クラスターレベルの設定を自由に試せる。
- OperatorやCRDのテスト:CRDを自由にインストール・アンインストールできる——ホストには一切影響しない。
vclusterの制限事項
- ノードレベルのアクセス:すべての実ノードで動作するDaemonSetが必要なアプリの場合、vclusterの同期処理が複雑になることがある。
- ホストネットワーキング:LoadBalancerサービスやNodePortは、vclusterから外部へトラフィックを公開するために追加設定が必要になる。
- ストレージ:PersistentVolumeはホストに同期されるため通常は問題ないが、ホストのStorageClassサポートに依存する。
- リソースオーバーヘッド:各vclusterはコントロールプレーンに少量のオーバーヘッドを追加する(約100〜200MB RAM)。10クラスター程度なら問題ないが、100以上になるとキャパシティ計画が必要になる。
始める前に推奨される準備
ホストとなるKubernetesクラスターが必要です。ローカル開発ならkindやk3dが最適です。本番グレードのvclusterホスティングには、任意のマネージドクラスター(EKS、GKE、AKS)が使えます。
また以下も必要です:
- ホストクラスターに接続するよう設定された
kubectl helmv3以上(vclusterは内部でHelmを使用)vclusterCLI(以下でインストール方法を説明)
特に推奨したい点として、仮想コントロールプレーンにk3sを使用する(軽量セットアップ向けのvclusterデフォルト)と、etcdの代わりにSQLiteを使う組み合わせがあります。開発用サンドボックスのユースケースでは十分すぎるほどで、フルのetcdを使った場合と比べてメモリ使用量を約40%削減できます。
実装ガイド
ステップ1:vcluster CLIをインストールする
# Linux / macOS
curl -L -o vcluster "https://github.com/loft-sh/vcluster/releases/latest/download/vcluster-linux-amd64"
chmod +x vcluster
sudo mv vcluster /usr/local/bin/
# インストールの確認
vcluster version
ステップ2:最初の仮想クラスターを作成する
# 「vcluster-dev」ネームスペースに「dev-sandbox」という名前のvclusterを作成する
vcluster create dev-sandbox --namespace vcluster-dev
# このコマンドの動作:
# 1. ネームスペースが存在しない場合は作成する
# 2. vclusterコントロールプレーン(APIサーバー+シンカー)をデプロイする
# 3. vclusterが準備完了になるまで待機する
# 4. kubectlコンテキストを新しいvclusterに自動的に切り替える
コマンドが完了すると、すでに仮想クラスターに接続された状態になっています。kubectl get nodesを実行するとノードが表示されます——vclusterが生成した仮想ノードの表現です。
kubectl get nodes
# NAME STATUS ROLES AGE VERSION
# vcluster-dev-sandbox Ready <none> 30s v1.28.0
ステップ3:vcluster内にアプリをデプロイする
# 仮想クラスター内にnginxをデプロイする
kubectl create deployment nginx --image=nginx:alpine
kubectl expose deployment nginx --port=80 --type=ClusterIP
# 動作確認
kubectl get pods
kubectl get svc
次に、ホストクラスターに切り替えて、vclusterが実際に作成したものを確認してみましょう:
# ホストクラスターのコンテキストに戻る
vcluster disconnect
# ホスト上のvclusterネームスペースを確認する
kubectl get pods -n vcluster-dev
# 表示されるもの:vclusterコントロールプレーンPod+nginxのPod(vclusterから同期済み)
vcluster内で宣言されたワークロードは、実際のPodとしてホストに同期されます。vcluster APIサーバーは開発者にはネイティブリソースとして見せますが、実際にはホストのノード上でスケジューリングされています。これがvclusterの仕組みの核心です。
ステップ4:開発者にvclusterへのアクセスを付与する
# vclusterのkubeconfigをエクスポートする
vcluster connect dev-sandbox --namespace vcluster-dev --print > dev-sandbox-kubeconfig.yaml
# このファイルを開発者に共有する
# 他のkubeconfigと同様に使用できる:
export KUBECONFIG=./dev-sandbox-kubeconfig.yaml
kubectl get pods
ステップ5:環境ごとに複数のvClusterを作成する
# 開発者ごとに1つ作成する
vcluster create dev-alice --namespace vcluster-alice
vcluster create dev-bob --namespace vcluster-bob
# または環境ステージごとに作成する
vcluster create staging --namespace vcluster-staging
vcluster create qa --namespace vcluster-qa
# 実行中のvclusterを一覧表示する
vcluster list
# NAME NAMESPACE STATUS CONNECTED
# dev-alice vcluster-alice Running
# dev-bob vcluster-bob Running
# staging vcluster-staging Running
ステップ6:values.yamlでvclusterをカスタマイズする
デフォルト設定を超えるカスタマイズには、Helm valuesファイルを使用します:
# vcluster-values.yaml
controlPlane:
distro:
k3s:
enabled: true
statefulSet:
resources:
requests:
memory: 128Mi
cpu: 50m
limits:
memory: 512Mi
cpu: 500m
syncer:
extraArgs:
- "--sync-all-nodes" # ノードのラベルとテイントをvclusterに同期する
# 作成時にカスタム値を適用する
vcluster create dev-sandbox \
--namespace vcluster-dev \
--values vcluster-values.yaml
ステップ7:作業完了後にvclusterを削除する
# vclusterを削除してネームスペースをクリーンアップする
vcluster delete dev-sandbox --namespace vcluster-dev
すべてが完全に削除されます——ホスト上に残留するCRDも、古くなったClusterRoleも一切ありません。ネームスペース分離と比べてみてください。あちらのクリーンアップでは、ネームスペース境界の外で作成されたクラスタースコープのリソースを探し回ることになりがちです。
実際の運用結果
本番環境では、CI/CDの結合テスト環境として具体的にこのパターンを活用してきました。各パイプラインジョブがvclusterを作成し、フルのテストスイート(CRDをインストールするHelmチャートを含む)を実行し、完了後にクラスターを削除します。数ヶ月間、数千回のパイプライン実行を経ても、ホスト上にテスト関連のリソース漏れは一切発生していません。
k3s+SQLiteで8つのvclusterを同時実行したところ、全コントロールプレーン合計で約1.2GBのRAMを消費しました。ほとんどのマネージドプロバイダーにおける単一の実クラスターのコントロールプレーンは、それ以上のメモリを使用します。
クイックリファレンス
# よく使うコマンド
vcluster create <name> --namespace <ns> # 作成して接続する
vcluster list # vclusterの一覧を表示する
vcluster connect <name> --namespace <ns> # 既存のvclusterに再接続する
vcluster disconnect # ホストクラスターに切り替える
vcluster delete <name> --namespace <ns> # 完全に削除する
共有クラスターの混乱に悩んでいるチームには、vclusterを試してみる価値があります。実際のクラスターのコストなしに本物の分離が得られ、そのトレードオフは開発サンドボックス、テストパイプライン、マルチテナント構成のいずれにおいても十分に成立します。

