Kubernetesを使いこなす抽象化の技法 3

KubeVela実践の現在地: 大規模事例に学ぶ設計判断と限界

第3回の今回は、KubeVelaを本番運用する5社の事例をもとに「何をDefinitionに閉じ込めるか」という設計判断と構造的な限界について解説します

石川 雲

6:30

はじめに

第1回ではOAM Specの停滞を整理し、「開発者が何を知らなくて済むべきか」がApplication Modelの核心だと論じました。続く第2回では「Helm」「KubeVela」「Crossplane」「Kro」を4シナリオで並列比較し、KubeVelaを「フルスタック・実装ドリブン」と位置づけました。

では、その「実装ドリブン」の中身は、Productionでどのように動いているのでしょうか。5社の大規模事例から、その答えを探します。

事例で見る
「何をDefinitionに閉じ込めるか」

今回はKubeVelaがProductionで動いている事例を5社、Definitionの中身まで踏み込みます。閉じ込める先はComponentだけではありません。招商銀行はTrait、GuidewireはPolicy / Application of Applicationsまで使い分けています。

先に用語を1つだけ整理します。KubeVelaのApplication CR (core.oam.dev/v1beta1) は、4種類のDefinition CRDを組み合わせて作ります。

  • Component Definition:Workloadを生成する
  • Trait Definition:Workloadにpatchを当てる
  • Policy Definition:Application全体に効く命令
  • WorkflowStep Definition:Apply時の手順

この4種をまとめて「X-Definition」と呼びます。本稿で主に出てくるのはComponent / Trait / Policyの3つです。

本稿を貫く問いは1つです。各社が「何をDefinitionに閉じ込めたか」。その答えが、その組織で「開発者が何を知らなくて済むか」の輪郭を決めます(図1)。

図1:5事例がDefinitionに閉じ込めたもの

Alibaba

KubeVelaはAlibabaチームが作ったOSSです。公式のwebservice.cueはbuilt-in ComponentDefinitionの代表例で、よく参照されます。コードを読む前に、CUEの登場人物だけ押さえておきます。

  • parameterが開発者の入口
  • outputが主リソース1つ
  • outputsが周辺リソース
  • contextはKubeVelaが実行時に注入する値
  • *1 | intは「デフォルト1付きのint」を表すCUE記法
"webservice": {
  attributes: workload: definition: { apiVersion: "apps/v1", kind: "Deployment" }
}
template: {
  output: {                                     // 主リソース (Deployment)
    apiVersion: "apps/v1"
    kind:       "Deployment"
    spec: {
      replicas: parameter.replicas              // parameter を参照
      template: spec: containers: [{
        name: context.name, image: parameter.image,
        ports: [ for p in parameter.ports { containerPort: p.port } ],
      }]
    }
  }
  parameter: {                                  // 開発者が触る入口
    image: string, replicas: *1 | int, ports: [...{port: int}]
  }
}

【出典】github.com/kubevela/kubevela/.../webservice.cue

構造はシンプルです。outputが生成するDeployment、outputsが周辺リソース (ServiceやHPA)。そこにhealthPolicyでReady判定を添えます。ports / env / labels / annotationsはすべてparameterで受け、Liveness / Readinessは必要に応じてCUEで書きます。

Componentに欲しい機能がひととおり揃っているので、後発の組織はまずこれを写経し、自分の文脈に合わせて削るところから始めるのが現実的です。

ByteDance

ByteDanceは「KubeCon EU 2022」で「Crossplane + KubeVela + Agones」を軸にしたゲームプラットフォームを発表しました (kubevela.io)。

実装は非公開のため、公開構成から推定したComponent Definitionの形で示します。

// 推定: 実装ソース非公開、KubeCon EU 2022 公開構成から再構成
"game-server": {
  attributes: workload: definition: { apiVersion: "agones.dev/v1", kind: "GameServer" }
}
template: {
  output: {
    apiVersion: "agones.dev/v1"
    kind:       "GameServer"
    spec: {
      ports: [{ name: "default", containerPort: parameter.port }]
      template: spec: containers: [{ name: context.name, image: parameter.image }]
    }
  }
  parameter: { image: string, port: int, region: string }
  // region は Component 内では未使用。配置先の選択は topology policy / placement 側に渡す想定
}

この再構成が概ね正しいとします。WorkloadをDeploymentからAgonesのGameServerに向けるだけで、開発者が触る入力はimage / port / regionくらいまで減ります。汎用に振るAlibabaとは反対に、必要なものだけへ絞り込む。同じKubeVelaでも、ここまで方向が分かれます。

招商銀行(CMB)

招商銀行はKubeVela公式blog 2022-04-01で事例を公開しました (kubevela.io)。金融規制で外部registryに到達できない環境で、Vela CLI / Core / Addonを別々のオフラインバンドルで搬入する3部構成です。

// 推定: 実装ソース非公開、KubeVela 1.2 公式 blog の手順から再構成
// Trait Definitionの patch ブロック
patch: spec: template: spec: {
  containers: [{
    name:  context.name
    image: "registry.internal.bank.local/" + parameter.image
  }]
  imagePullSecrets: [{ name: "internal-registry-cred" }]
}

公開手順から推測すると、構成は次のとおりです。

開発者のApplication YAMLはpublic registryのimageを書いたままでよく、内部registryへの付け替えとimagePullSecretsの注入はDefinition層に寄せます。

金融のように規制の効く現場では、registryの所在を開発者に意識させません。それをDefinition側だけで実現できることが、そのまま運用要件になります。

Guidewire

GuidewireはKubeVela現在のmaintainerです。Brian Kane氏は「KubeVela is critical to our internal efforts and adoption」と述べ、Guidewire系メンバーは7名以上がactiveです。中でもAnoop Gopalakrishnan氏は、後述するKubeVela 2.0構想の提案者です。

Guidewireの公開記事は、KubeVela ComponentでCrossplane Compositionを包み、インフラの複雑さを開発者から隠す構成を紹介しています (guidewire engineering blog)。これに関連して、運用でよく効くのがKubeVela標準のapply-once Policyです。spec.replicasだけをKubeVelaの書き戻し対象から外すと、HPAとのreconcile競合を避けられます。

policies:
  - name: apply-once
    type: apply-once
    properties:
      enable: true
      rules:
        - selector: { resourceTypes: ["Deployment"] }
          strategy: { path: ["spec.replicas"] }

apply-once配下に入れたspec.replicasは、HPAが後から書き換えてもKubeVelaが上書きし返しません。マルチテナントでは親Applicationがtenant-application Componentを通して子Applicationを生成し、OCM (Open Cluster Management) のManagedClusterラベルセレクタで配置先を決めるパターンもBrian Kane氏がSlackで紹介しています。

# 推定: Brian Kane 氏 Slack の構造から再構成
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata: { name: tenant-fleet }
spec:
  components:
    - name: tenant-a
      type: tenant-application                         # 子Applicationを生成するComponent
      properties:
        clusters: ["managed-cluster-a", "managed-cluster-b"]
        appSpec: { image: ..., replicas: 3 }
    # ... tenant-b 以降も同じ要領で配置先と appSpec だけ差し替える
  policies:
    - name: ocm-placement
      type: topology
      properties:
        clusterLabelSelector: { env: prod }            # OCM placement で配置先を絞る

fleet (多数のクラスタ群) を扱うなら、Application単体では足りません。Application of Applications型へ組み替える必要が出てきます。これがGuidewire事例の示唆です。

CyberAgent

ここからは筆者の当事者観察です。所属するCyberAgentのAmeba Platformチームでは、ブログを中心としたメディアサービスAmebaの多数のbackendが同じ基盤の上で動いています。2021年からKubeVelaベースのApplication Model抽象を運用してきました。

中心Component Definitionはapi / web / workerの3つで、Alibabaの汎用webserviceとは性格が大きく違います。

apiはbackend中心のアプリの想定機能をほぼ1枚に詰め込んだComponent版「スーパーアプリ」と呼べる形です。Istioサイドカー注入、各種ヘルスチェック、ConfigMap / Secret読み込み、Service / ServiceMonitor / CronJob同居、複数port。backendで日常的に出てくるこうした分岐が、ほぼ全部parameterの条件で表現されます。

webはフロントエンド寄りのワークロード前提で、CDNや静的アセット配信周りのparameter設計がapiとは異なります。

workerはHTTPリスナーを持たないバッチ・非同期処理用で、Service / Ingress系のoutputsが省かれ、CronJobやQueue consumerのパターンに寄せた構造です。

これら3つを使い分けることで、開発者は自分のアプリの形 (受信形・配信形・常駐ワーカー形) でComponentを選ぶだけになります。

/ 社内 api Component Definition (構造抜粋、annotation キーは仮名化)
"api": { attributes: workload: definition: { apiVersion: "apps/v1", kind: "Deployment" } }
template: {
  output:  { apiVersion: "apps/v1", kind: "Deployment", spec: { ... } }
  outputs: {
    if parameter.expose      { service:        { ... } }
    if parameter.monitoring  { servicemonitor: { ... } }
  }
  parameter: {
    image: string, tenant: string, owner: string
    replicas: *2 | int, ports: [...int]
    istio: *true | bool, expose: *false | bool, monitoring: *false | bool
    healthCheck: { kind: "http" | "exec" | "tcp", ... }
    // envFrom / resources など省略
  }
}

設計判断としては、開発者にComponentの選択肢を増やさず、1枚のapiに全部詰めて分岐をparameterで出す方向です。Alibabaの汎用webserviceが「誰でも使える機能テンプレ」だとすれば、Amebaのapiは「Amebaのbackend文脈に特化した内製スーパーアプリComponent」です。

開発者が触るリポジトリ側は、Componentのparameterを埋めるだけです。中身はすべてCUEで、環境差分をbaseとoverlayに分けます。ディレクトリの切り方をkustomizeに似せているのは、見た目で構造を把握しやすいからで、kustomize自体を使っているわけではありません。

service-a/
├── base.cue              # type: api, image, owner, ports ...
└── overlays/
    ├── stg.cue           # base を読み込み replicas / monitoring を上書き
    └── prod.cue          # base を読み込み replicas / expose / monitoring を上書き

base.cueがapi Componentを呼び出すApplicationの定義、overlays/<env>.cueが環境ごとの差分です。overlayをbaseにunifyしてApplication CRを生成し、ArgoCDがsyncします。開発者はbaseに「アプリの定義」を、overlayに「環境で変わる値」だけを書けば済みます。

このアプローチは強力ですが、コストもあります。api Definition自身は数百行規模に膨らみ、分岐ロジックがCUEで重なります。このDefinitionのメンテナはCUEのassertやunification (複数の定義を1つに重ね合わせる評価) の挙動を頭に入れて読まなければなりません。筆者がDevelopers Blog 2025-12-18 (developers.cyberagent.co.jp) で書いたとおり、「開発者が基盤の違いを意識せずに開発できる」ことと引き換えに「その負担をプラットフォームチームが引き受けてきた」という側面があります。その結果、Definitionの内部にはAmeba固有のロジックが厚く積み上がります。

5社を「何をDefinitionに閉じ込めたか」の軸で並べると、それぞれの輪郭が見えてきます。

事例Definitionの代表Definitionに閉じ込めた中身開発者から見える表面
Alibabawebserviceparameter / output / outputs / healthPolicyの四段を一枚に網羅全機能をparameterで受ける汎用Component
ByteDancegame-server (推定)Agones GameServerへの変換、マルチリージョン情報image / port / region3項目
招商銀行private registryTraitimageの自動書き換え、imagePullSecrets注入public registry参照のまま書ける
Guidewiretenant-applicationapply-once PolicyOCM placementHPAとの競合回避、親子Applicationfleet規模のテナント運用とHPA共存
CyberAgentapiwebworkerIstio・ヘルスチェック・ServiceMonitorCronJobparameter分岐に圧縮アプリの「形」を選ぶだけ

同じKubeVelaを使っても、5社の答えはこれだけ振れます。違いを生んでいるのは「どの種別のDefinitionに、何を、どこまで閉じ込めるか」という設計判断です。

事例を踏まえて、どう組むか

では、その設計判断を1から下すとき、何を決めれば良いのでしょうか。事例と筆者の当事者経験を重ねると、決めるべきことは3つに絞れます。Componentの粒度Definitionの配置と所有Deliveryの委譲先です。事例がいちばんはっきり差を見せるのは粒度の軸です。配置はCyberAgentの構成が、DeliveryはGuidewireのfleet運用が手がかりになります。

Componentの粒度をどこに取るか

最初の、そして一番効く判断がComponentの粒度です。汎用に全部入りで振るか、業務文脈に特化させるか。事例はこの軸の上にきれいに散らばります (図2)。汎用の端がAlibabaのwebservice、特化の端がByteDanceのgame-serverです。どこに置くかで、開発者に見せる量と、Definition内部に抱え込む複雑さが決まります。
 

図2:Componentの粒度と5事例の位置

粒度を決める前に、Component Definitionの構成要素を押さえておきます。Component Definitionはparameter / output / outputs / healthPolicy / customStatusの5要素でできています(図3)。parameterは入力スキーマ、outputは主リソース、outputsは周辺リソース、healthPolicyはReady判定、customStatusはUI / CLI向けの状態表示です。

図3:Component Definitionの5要素

parameter設計では、必須項目は型のみ宣言 (image: string)、デフォルトを許す項目は*default | typeの形 (replicas: *2 | int)、検証ロジックはCUEの制約構文 (port: >0 & <65536) で書きます。原則は「1 Component Definition = 1 workload + 周辺リソース」です。

汎用に振ると利用者の幅は広がりますがparameterが膨らみ、業務文脈へ特化させると開発者の見える面は減りますがDefinition内部のロジックが厚くなります。どちらを選ぶかは、利用者の幅と、プラットフォームチームが引き受けられる複雑さの兼ね合いで決まります。

Definitionをどこに置き、誰が持つか

粒度が決まると、次はDefinition群をどこに置き、誰がメンテするかです。CyberAgentの事例で見たbase / overlayは1サービス単位の話でしたが、プラットフォーム全体では、再利用するDefinitionと環境ごとの差分を分けて並べる構造が必要です。Amebaではdefinition/の下をmodule/とenvs/の2つに分け、どちらもX-Definitionの種別 (component / trait / workflow / policy) で切っています。

Definition/
├── module/             # 再利用する Definition 本体を種別ごとに置く
│   ├── component/     # api / web / worker
│   ├── trait/
│   ├── workflow/
│   └── policy/
└── envs/               # 環境ごとの差分を、同じ種別構成で重ねる
    ├── dev/
    │   ├── component/
    │   ├── trait/
    │   ├── workflow/
    │   └── policy/
    ├── stg/
    └── prd/

module/が再利用するDefinitionの本体、envs/<dev|stg|prd>/が環境ごとの差分です。どちらも種別 (component / trait / workflow / policy) でディレクトリを切ります。種別ごとに導入時期や責任オーナーが分かれることが多く、環境差分も同じ種別構成で重ねるので、「どの環境の、どの種別を、誰が触るか」が一目で分かります。

ただしComponent / Trait / Policy / WorkflowStepは評価コンテキストが種別ごとに違うため、module/で共有できるヘルパーにも限界があります (この点は後述の章で詳述します)。

Deliveryをどこに委譲するか

最後の判断は、組み立てたApplication CRをProductionにどう届けるかです。Guidewireの事例で、多数のクラスタへfleetとして配るためにApplication of Applicationsを組んだのも、この判断にあたります。ここで効くのは、Deliveryが一枚岩ではないという視点です。届けるまでには3つの段階があります(図4)。

  • 前準備:Applicationが前提とするインフラ (DBやネットワークなど) を用意する段階。TerraformやCrossplaneの領域
  • 本体のデプロイ:KubeVela Application自体をクラスタへsyncする段階
  • デプロイ後の処理:syncの後に走るcanary昇格、監視連動、通知などの段階

図4:全部KubeVelaという理想と現実的な分担

段階ごとに「KubeVelaに任せる」か「外部ツールに分離する」かを選びます。両極は、全部をKubeVelaのWorkflowに集約する派と、全部を専用ツールに分離する派です。

筆者は基本的に分離を推します。前準備はTerraform / Crossplaneに、本体のデプロイはArgoCDに委ねます。ArgoCDのdrift detection / rollback / multi-cluster RBACは現時点で最も成熟しており、事故時の回復経路が一番厚いからです。

ここでArgoCDとKubeVelaの責務境界をはっきりさせておきます。ArgoCDがgitと同期するのは、KubeVela Application CRという1枚のマニフェストです。そのApplication CRを実際のDeployment / Serviceなどのリソースへ展開し、以後それらを管理し続けるのはKubeVela controllerです。つまりArgoCDは「Application CRをgitと一致させる」層、KubeVelaは「Application CRを実リソースのマニフェストへ展開して保つ」層、という二層の分担になります。

ただし、デプロイ後の処理だけはKubeVelaに残すのが現実解だと考えます。本体のデプロイをArgoCDに委ねる場合、運用では複数のKubeVela Applicationを1つのArgoCD Applicationにまとめがちです。その1つのArgoCD Applicationのsync後フックは、束ねた全appへ一律にかかります。「このappのこのバージョンがcanaryでどう振る舞ったか」のようなapp固有のシグナルは、もう扱えません。そのシグナルを持っているのはKubeVelaだけです。そのため、canary昇格や段階的rolloutのようなデプロイ後処理はKubeVela側 (Workflow / WorkflowRun) に残します。

KubeVelaの限界

先の3つの判断(粒度・配置・Delivery)で実際に組んでみると、選んだ判断の先で壁に当たります。ここまで「製品としてのKubeVela」を支えてきた仕組みの裏側です。

壁には深さの違う2種類があります。1つはCUEツールの未成熟やエコシステムの追従途上のように、時間と実装が埋めていく成熟途上の壁。もう1つは2019年の設計思想に根ざした、機能を足しても消えない構造的な壁です。後者は本連載の論点、OAMが「誰のための抽象か」を見失った宿題に直結します。

  • 構造的な壁: 合成可能性の断片化、Workflowの副作用
  • 成熟途上の壁: 開発デバッグ体験、エコシステム連携

合成可能性の断片化

粒度の判断では、Componentを「汎用に振るか、業務特化に振るか」で選びました。しかし「小さなComponentやTraitを組み合わせて1つの大きな抽象を作る」という第三の道は、KubeVelaでは最初から構造的に塞がれています。これが一番深い壁です。

ここで言う合成可能性 (Composability) とは、異なる抽象を組み合わせて1つの大きな抽象を作れる性質のことです。

まず、現場のギャップです。KubeVelaを書き始めるとすぐ「Componentの中で他のComponentを呼びたい」「TraitとPolicyで同じヘルパー関数を共有したい」が直接書けないことに気づきます。「Production-ready microservice = webservice + scaler + topology + canary」を1つの抽象にまとめたくても、Application YAML側で毎回4種類を並べ直すことになります。

次に、providerの非対称があります。ここはバージョン差も大きいので断定は避けますが、少なくとも筆者の運用では、Definition種別ごとに利用できるprovider / context / patch semanticsが揃わず、共通ヘルパーを作るときの障害になりました。メンテナのBrian Kane氏も、種別によって使えるproviderが違う点を「This was tripping me up only a few days ago」とSlackで認めています (Slack)。

原因は単純です。4種類をそれぞれ別のCRDで包んでいるので、合成可能性が構造のレベルで分断されます。種別を跨いだ型参照や合成は、言語レベルで成立しません。

そして、核心にあるのは思想の問題です。2019年のOAM設計はDeveloper / App Operator / Infra Operatorの3役分業を前提に、ComponentとTraitを「誰が書くか」(役割) で分けました。PolicyとWorkflowStepは後から足された概念です。この役割由来の境界は、いまもDefinitionの種別境界として残っています。

一方で現在のKubeVelaは、docsもSDKも「プラットフォームチームがX-Definition全体を書く」前提に寄っており、実際には1人が4種類すべてを書きます。つまり、役割で割った当初の境界が、いまの実装者には再利用・合成の壁になっています。「種別を跨いだ参照ができない」「providerが非対称」は、その症状です。

対比として、同じCUEを使ったMercariのk8s-kit (第1回参照) は#Application / #Pipeline / #Ingressを「何を表現するか」で分け、型間の相互参照で200+ servicesのコードを最大で約90% 削減したと報告されています(図5)。

図5:KubeVelaとMercari、分け方の違い

同じCUEでも、何で分けるかという設計判断ひとつでここまで変わります。言語機能の差ではありません。Mercariは自社構築コストを払える組織前提の極端解なので等価交換はできませんが、合成可能性を成立させる別解として参照できます。

Workflowの副作用

もう1つの構造的な壁が、Workflowです。DeliveryをKubeVela単体に寄せ、Application Workflowに副作用付きの処理を書くと、正面から踏みます。

KubeVelaにはWorkflowに関わる仕組みが2つあります。1つはApplication CRの「spec.workflow」 (Application Workflow) です。spec.workflowを省くと、CRに定義したComponentをApplyするデフォルトのWorkflowが走ります。Componentを更新すれば自動でApplyされる、という利点です。ただし、このWorkflowはApplication controllerのreconcile loopで評価され、Application specや参照するDefinitionの更新を契機に再評価されます。

もう1つはkubevela/workflowの独立CRDである「WorkflowRun」です。終了状態 (Succeeded / Failed) を持ち、完了済stepの再実行を抑制できます。

筆者は2024年9月にこの違いを実害として踏みました。Application Workflowに書いていたCDN Cache Purge stepがDefinition更新のreconcileを契機に意図せず再実行され、CDN cacheが2度purgeされてoriginへのヒットが急増しました。メンテナの回答は「kubevela/workflowのWorkflowRunを使えば、完了済stepは再実行されない」でした (Slack)。

原因は、Application reconcileが冪等性を仮定しているのに対し、副作用付きstepは1回性を要求する、というずれです。これはGuidewireの事例で見たapply-once Policy (HPAとのreconcile競合への手当て) と地続きです。どちらも「reconcileが前提を仮定している」点で共通します。対処はシンプルです。副作用付きの処理を独立CRDのWorkflowRunに切り出し、Application Workflowには冪等な操作だけを残せば、Definition更新の再評価でも同じstepは二度走りません。

ここまでの2つ、合成可能性とWorkflowは設計思想に根ざす構造的な壁で、機能を足しても消えません。残る2つは性格が違います。時間と実装が埋めていく成熟途上の壁です。

開発デバッグ体験

Componentを業務文脈へ特化させるほど効いてくるのが、書きながらのデバッグコストです。CUEのエラーメッセージはKubeVela文脈に翻訳されず、「parameter.replicas is not int」とだけ言われて、どのDefinitionのどの行か追うのに時間がかかります。vela def vetで踏み込めない領域もあり、IDE / LSP (エディタ統合) サポートも弱いままです。

vela def renderで出力YAMLは見られますが、毎回CLIを回す形で、エディタ内のリアルタイム補完までは届きません。複雑な分岐を含むComponent Definition (CyberAgentのapiのように分岐が多い形) では、書きながらの試行錯誤コストが他の言語 (GoやTypeScript) に比べて明らかに高くつきます。後述するdefkit (Go SDK) は、この開発体験のコストを下げる現実的な逃げ道です。

エコシステム連携の追従途上

Deliveryで外部CD (ArgoCDやFluxCD) を選ぶと、周辺ツールの追従の遅れに突き当たります。KubeVela Application CRをArgoCDでsyncするパスは確立していますが、ArgoCD Image Updaterは標準的なDeployment / Helm chartを前提にしています。KubeVela Application CRではpropertiesが入れ子になるので、そこへimage tagを当てるには追加実装や運用ルールが要りがちです。FluxCDの内部依存は、後述のNative Helm Component (KEP PR #6974、実装 #7080 が2026-04にmerged) で解消方向です。要するに、周辺ツールがまだKubeVela抽象に追いついていないだけです。

成熟途上の2つは、2026年のロードマップで対処が進んでいます。構造的な2つにも、KubeVelaは手を打とうとしています。

今後の期待:深めるか、広げるか

KubeVelaの打ち手は、1つの方向にまとまっていません。Definition層を深める方向と、KubeVelaの守備範囲をCluster Infrastructureへ広げる方向の2つに割れています。そして、この2つは組織の投資先としては両立しません。どちらかを選ぶことになります。

深める方向

一方は、Definition層そのものを直しにいく動きです。進行中の取り組みは3本あり、先ほどの限界4つのうち3つに対応します。残るWorkflow副作用だけは直接対処が未提案で、「KubeVelaの限界」の項で示したWorkflowRunへの運用回避に頼るしかありません。

限界種類対処にあたるロードマップ
合成可能性の断片化構造的ComponentLayering / Declarative Addons(KEP PR #6993#6996が採択済み、実装はこれから)Definition種別の根を変えずに上位レイヤーで合成可能性を補う方向
Workflow副作用構造的直接対処の取り組みは未提案 (「KubeVelaの限界」の項で示したとおりWorkflowRunに逃がすしかない)
開発デバッグ体験成熟途上defkit(next branch docs)DefinitionGoで書くSDKで、CUE自体ではなく言語選択肢を増やす形の迂回解
エコシステム連携成熟途上NativeHelm Component(KEP PR #6974実装 #70802026-04merged)FluxCD addon依存が断ち切れる

成熟途上の2つは、これでほぼ埋まる見込みです。構造的な合成可能性に手を伸ばすのがComponent LayeringとDeclarative Addonsです。粒度の節で触れた「小さな部品を組み合わせて大きな抽象を作る」第三の道を、Definition種別の根を変えずに上位レイヤーから開こうとする試みです。

広げる方向

もう一方の、射程が最も長い動きが KubeVela 2.0 構想です。Anoop氏が2026-04-03にSlackで「Bringing KubeVela's abstraction model to cluster infrastructure itself. All using OAM principles, but for clusters.」と発言し (Slack)、続けて PR #7087 "Cluster Infrastructure Abstraction" としてKEP化されました。

範囲はcluster lifecycle、composable infrastructure layers、fleet rolloutsに及びます(図6)。ただし呼称はSlack発言が初出で公式docsには未掲載、Anoop氏自身も「implementation might still drift」と注記しており、構想段階の用語です。

図6:KubeVela 2.0が広げる範囲

こちらは、KubeVelaの守備範囲そのものをApplicationからCluster Infrastructureへ広げる動きです。Definition層を深めるのとは逆を向いています。ただしprovisioningそのものはCrossplane / Terraform / CAPIなどのbackendに委譲する設計で、KubeVelaが全てを直接実装するわけではありません。

どちらに賭けるか

筆者は「深める」方に組織のリソースを向けるべきだと考えます。根拠は「KubeVelaの限界」の項で引いた線をそのまま延ばしたものです。

深める方向は、構造的な壁を正面から直しにいきます。つまり合成可能性の断片化と、その根にある「役割で割る思想」です。これは本連載がずっと追ってきた「誰のための抽象か」というOAMの宿題そのものです。

実利もあります。合成可能性が解ければ、粒度の議論で見た「特化Componentほど内部ロジックが厚くなる」保守コストを、小さな部品の組み合わせに分散できます。

一方、広げる方向は、その宿題を未解決のまま守備範囲だけを広げます。「KubeVelaの限界」の項で見たWorkflowの副作用やaddonの境界の曖昧さを、Cluster Infrastructureという別レイヤーで再生産しかねません。

しかもMultiCluster領域はマルチクラスタ管理に特化したOCM / Karmadaが既に成熟しており、KubeVelaが踏み込んでも差別化は薄いままです。Definition層の合成可能性こそ、KubeVela固有の、まだ誰も解いていない宿題です。

ただ、ロードマップを牽引するAnoop氏自身は広げる側 (KubeVela 2.0) の旗振り役で、コミュニティのモメンタムはむしろ広げる方にあります。それでも、自分たちの組織が広げる賭けに乗る必要はありません。「Cluster InfrastructureまでKubeVelaに寄せるか、Definition層の品質に集中させるか」を問い直すと、選択は変わってくるはずです。

興味深いのは、この「広げる」が他のツールの動きと交差することです。KubeVela 2.0がAppからCluster Infraへ広げるのに対し、Crossplane 2.0はInfraからAppへ広げてきました。実際、KubeVela 2.0を牽引するGuidewire自身は社内でCrossplaneを併用しており、KubeConのセッションでもCrossplaneとの連携強化に触れていました。両者が中央で出会う兆候は、すでにメンテナの足元から出ています。2026年のApplication Model地図の見どころになりつつあります。

まとめ

KubeVelaはApplication Modelを「製品」として育てる試みで、Productionスケールに到達しました。組織はComponent Definitionなどの引き出しを使い分け、「開発者が何を知らなくて済むか」を作り込みます。事例から抽出したparameter粒度の設計やoutput / outputsの分岐といった作法は、自分の組織でも再利用できます。

ただし、2019年の思想はTemplateをDeveloper / App Operator / Infra Operatorの三役で分けました。一方、いまのPlatform Engineeringでは、プラットフォームチーム1人が4種類すべてを書きます。この間に構造的なギャップが残ります。これからのApplication Modelは、再利用の単位を「誰が書くか」から「何を表現するか」へ置き直す必要がある、というのが本稿の教訓です。

2026年のロードマップは、Definition層を深める方向と、Cluster Infrastructureへ広げる方向に割れています。筆者は前者、Definition層の合成可能性を上げる方に組織のリソースを向けることを推します。

次回は、逆方向のアプローチであるCrossplane 2.0を深掘りします。KubeVelaがApplicationからインフラへ守備範囲を広げるのに対し、CrossplaneはインフラからApplicationへ広げてきました。両者がどこで重なるのか。それが次回のテーマです。

この記事をシェアしてください

人気記事トップ10

人気記事ランキングをもっと見る

企画広告も役立つ情報バッチリ! Sponsored