Platform Engineering時代のApplication Model設計
最終回となる今回は、KubeVela・Crossplane・Kroの問題点を整理し、Platform Engineering時代のApplication Modelに必要な4条件と設計構成を提唱します。
6:30
はじめに
本連載は今回で最終回です。 第1回から第5回まで、KubernetesにおけるApplication Modelを、歴史、比較、実装の順に調べてきました。
第1回ではOpen Application Model(OAM)の登場と停滞を取り上げ、第2回ではHelm、KubeVela、Crossplane、Kroを同じシナリオで比較しました。 第3回、第4回、第5回では、KubeVelaのDefinition、Crossplane 2.0のFunctionパイプラインとクラウドリソース管理、KroのResource GraphとCRD生成を実際に動かして確認しました。
どのツールでも、短い入力からDeployment、Service、Ingress、HPA、NetworkPolicyなどを生成できます。組織が、サービスの作成から運用までの標準的な手順であるGolden Path(ゴールデンパス)を用意すれば、開発者はKubernetesのリソースを1つずつ記述せずにサービスを追加できます。Golden Pathで提供する操作なら、通常のリリースや設定変更も開発チームが自分たちで進められます。
ここまでは、すでに実現できていると言えるでしょう。 一方、運用中のApplicationに影響する共通定義の変更を事前に確認し、問題があれば適用を止めたり戻したりする機能は不足しています。PlatformチームがPlatform APIと共通定義を保守できることも必要です。 最終回の今回では連載で扱ったツールの問題点を確認し、Platform Engineering時代のApplication Modelに必要な条件と、筆者が考える構成を提唱します。
結論:この連載で扱ったツールの比較と問題点
Platform APIを公開した後も、共通定義の更新、差分の確認、ロールバックを続ける必要があります。
- Helm:同じ記述の反復が多く、条件分岐が増えるほどTemplateを読み解くのが難しくなります。Go Templateは値の置換には使えますが、複雑な条件から複数のリソースを組み立てる定義には向きません。Kubernetes外のサービスを継続的に管理するには、別のControllerやIaCも必要です。HelmだけではApplication全体を管理できません。
- KubeVela:Definitionを変更しにくい点が問題です。少し機能を加えるだけでも、Parameter、
output、outputs、Traitとの組み合わせを含むCUEを広く修正することになります。Definitionを変更しにくいまま、Policy、Workflow、Multi-cluster Deliveryなど、稼働開始後の変更や運用を扱うDay-2 OperationsをKubeVela固有の仕組みへ集めたため、Platformチームが保守する範囲も広がりました。 - Crossplane:Kubernetesとクラウドリソースを同じControl Planeで継続的に管理でき、CompositionRevisionではXR単位の固定、段階的な適用、ロールバックも行えます。Crossplaneだけでは、Application Modelは完成しません。開発者向けのPlatform API、Composition、Function、Application全体の状態を表示する処理は、利用する組織が作る必要があります。
crossplane renderも作成予定のリソースを出力するだけで、稼働中のリソースとの差分と更新操作を示すPlanにはなりません。 - Kro:本連載で確認したv0.9.3では、RGDを変更するとInstanceは最新のGraphRevisionを使います。GraphRevisionはRGDの履歴とコンパイル結果を保存しますが、利用者がInstanceごとに利用するVersionを選ぶための機能ではありません。共通定義を一部のInstanceへ先に適用し、問題が起きたときに以前のVersionへ戻すことができません。
開発者によるサービス固有設定の変更と、Platformチームによる共通定義の更新を、Application単位で段階的に適用し、その履歴を残す機能は、4つのツールのいずれにも揃っていません。
Platform Engineering時代のApplication Modelの条件
Platform Engineeringでは、同じApplicationを開発者とPlatformチームがそれぞれ変更します。 開発者が扱うのはImageやCPU、Memory、Databaseなど、サービス固有の設定です。Platformチームは、Backupやログ保存の標準設定、リソースの生成処理、共通機能の実装を保守します。
私が考えるPlatform Engineering時代のApplication Modelでは、開発者がApplication Definitionを使ってリソースを作成、変更、運用でき、Platformチームがリソースの生成処理と共通定義を更新できます。 各Applicationへ適用した設定と実装も記録します。
このApplication Modelを実現するには、次の4条件が必要です。
- Application全体の管理:コンテナ、Database、外部公開、接続権限などを1つのApplicationとして扱い、作成と接続、更新、廃止まで管理できること。
- 開発者のセルフサービス:Golden Pathに含まれる作成や変更を開発者自身で完了できること。Golden Pathに収まらない要件にも、Schemaで確認できる入力を追加して対応できること。
- 共通定義の変更管理:利用した実装とバージョンをApplication単位で記録し、変更前に対象と差分を確認できること。一部のApplicationへ適用でき、以前の構成へ戻せること。別の実装へ移るための情報も出力できること。
- 現在の状態と修正担当の表示:適用された設定と現在の状態を確認できること。障害時に、利用者が直す入力と、Platform側で対応する担当が分かること。
本稿では、この4条件を満たし、同じプロダクト機能に必要なリソースをApplication単位で管理する構成を提唱します。
Applicationの範囲とリソースの所有者
コンテナと、その稼働に必要なリソース
設計例に使うpayment-apiは外部公開するAPIで、専用Databaseと共有Cacheを利用します。payment-apiを稼働させるにはコンテナの実行環境、外部から通信を受ける設定、Databaseへの接続、監視設定を用意します。 具体的なリソースや設定は、次のとおりです。
- コンテナを実行するDeploymentと、Podへの接続先を提供するService
- 外部公開に使うLoad Balancer、Target Group、DNSレコード、TLS証明書
- 永続データを保存するDatabaseと、一時データに使うCache
- DatabaseやCloud APIへの接続権限を定めるIAM PolicyとWorkload Identity
- 通信を制御するNetworkPolicyやSecurity Group
- ログ、メトリクス、トレース、Dashboardなどの監視設定
これらを別々のリポジトリと申請フローで管理していると、開発者は複数のPRを作り、インフラの作成を待ってから接続先を設定します。廃止時には、同じサービスのために作ったリソースを探し直す作業も必要です。 リソースの作成順序と接続先を同じ定義に書いておけば、リポジトリごとのPRや接続先の手作業が不要になり、Application単位で進捗と状態を確認できます。
そこで、同じプロダクト機能を提供するリソースと依存関係を、グラフとして宣言します。 各リソースをノード、接続や作成順序の依存を辺として表します。 本稿では、これをApplication Resource Graphと呼びます。
Applicationに含める範囲と更新頻度
Applicationへ含めるのは、同じプロダクト機能のために作られ、Applicationの運用チームが稼働状況を確認し、廃止を決めるリソースです。 payment-apiのコンテナ、専用Target Group、専用Databaseは、この基準で同じApplicationに含めます。
ただし、コンテナイメージとDatabaseの構成では、更新する時期が異なります。 リリースのたびにコンテナを更新しても、Databaseは変更せず使い続ける場合があります。 更新頻度の違いは、同じApplicationから除外する理由にはなりません。
同じApplicationに含めても、更新単位まで同じにする必要はありません。Application Resource Graphには依存関係を持たせ、Application Statusには各リソースの状態をまとめます。更新や再試行の対象もリソース単位です。
共有リソースの所有者
複数のApplicationで使うLoad BalancerやCacheは、専用Databaseとは管理方法が異なります。 どれか1つのApplicationに所属させると、そのApplicationの削除が、ほかの利用者へ影響するおそれがあります。
共有リソースはApplicationから独立して管理し、所有者と廃止条件を定めます。Applicationは共有リソースを参照するだけなので、payment-apiを削除してもShared Cacheは残り、削除するのはpayment-apiからの接続と参照だけです。共有リソースの廃止時期は、その所有者が決めます。
| 管理単位 | 対象の例 | 主な所有者 | Application削除時の扱い |
| Application | Workload、専用Target Group、専用Database | Applicationの運用チーム | リソースごとの廃止手順を開始 |
| 共有リソース | 共有Load Balancer、Cache、Network | 共有リソースの管理者またはPlatformチーム | 接続や参照を外し、共有リソースは残す |
| Platform | Cluster、共通Controller、Admission Policy | Platformチーム | Applicationの削除では変更しない |
Platform APIと内部実装
開発者が編集するApplication Definition
次のApplication Definitionで、開発者がpayment-apiに必要な機能を指定します。
apiVersion: platform.example.io/v1
kind: Application
metadata:
name: payment-api
spec:
workload:
image: ghcr.io/example/payment-api:v1.8.0
exposure:
class: public-standard
database:
class: production-standard
cache:
class: shared-standard開発者がApplicationを定義する方法は、Platform APIと従来型のIaCの2つです。
- Platform APIを使う方法:開発者は組織が用意したStandard Classを選び、サービス固有の値だけを記述します。上のYAMLはこの方法の例です。Platformは
classを基に、コンテナの実行環境、外部公開、Database、Cacheへの接続、IAM権限、通信制御、監視設定を組み立てます。このPlatform APIをGolden Pathの一部として提供します。 - 従来型のIaCを使う方法:開発者は、利用するリソースとすべての設定値をIaCへ直接記述します。Golden Pathに収まらない要件を扱えますが、インフラの詳細、設定間の整合、更新時の差分を開発チームが管理します。
どちらを使う場合も、作成したリソースをApplicationに関連付け、状態と変更履歴をApplication単位で確認できるようにします。 Platform APIの利用を強制せず、標準化できる部分だけをPlatformが管理します。
機能ごとに分けるCapability
Platform APIは必要な機能をまとめて受け取ります。一方、Platformチームが1つの実装ですべてを扱うと、Databaseの変更がWorkloadや外部公開のテストにまで影響します。そこで、Workload、外部公開、Databaseなど、機能ごとに入力、生成するリソース、状態の報告、テストを切り離す単位としてCapabilityを定義します。
| Capability | 主な実装内容 | 実現先の例 |
| Workload | コンテナ、Probe、Scaling、Pod設定 | Deployment、HPA |
| Exposure | 公開範囲、Route、TLS、Health Check | Gateway API、Ingress、ALB、DNS |
| Database | Databaseの種類、可用性、Backup、接続情報 | RDS、Cloud SQL、Database Operator |
| Cache | 容量、可用性、共有か専用かの選択 | ElastiCache、Redis Operator |
| Observability | ログ、メトリクス、トレース、Dashboard、Alert | Datadog、Prometheus、OpenTelemetry |
| Release | Rollout、環境間の反映、停止条件 | Argo Rollouts、GitOpsパイプライン |
第3回のKubeVelaでは、Component、Trait、Policy、WorkflowStepに定義を分けました。 複数のComponentで機能を再利用できますが、同じ機能が複数のDefinitionへ分かれるため、変更時には関係するDefinitionをすべて確認する必要があります。 第5回のKroが採ったのは、公開APIとResource Graphを1つのResourceGraphDefinition(RGD)へまとめる構成でした。Traitのように機能を後から加える場合は、別の仕組みが必要です。
Platform APIの項目と、Platformチームが保守するCapabilityの分け方を一致させる必要はありません。 開発者はspec.databaseを編集し、PlatformチームはDatabase Capabilityだけを改修してテストします。 各Capabilityには、保守担当と保証範囲を明記します。
Capability間の接続と実行順序
Capability間の接続は、Applicationを管理する処理の役割です。例えば、Databaseの作成後に接続先を取得し、Workloadへ渡します。ここで行う作業は次のとおりです。
- 入力から利用するCapabilityを決定し、依存関係を組み立てる
- 実行時に確定した値を、必要なCapabilityへ渡す
- 作成、更新、削除の順序を調整する
- 各Capabilityの状態を、Application全体の状態として報告する
- 使用したバージョンと、適用前の確認や移行に使う出力を記録する
各リソースのReconcileは、そのリソースを担当するControllerに任せます。Application全体を管理する処理は、DatabaseやNetworkを直接Reconcileしません。
各Capabilityへの入力はCRとして渡せます。CRの形式は利用するControllerに合わせて選びます。 接続情報の形式や依存条件を維持できれば、Databaseの実装を変更してもWorkload側の内部処理まで書き換えずに済みます。
担当者ごとの変更権限
実装を分けるときは、誰が何を変更できるかも決めます。 開発チームはApplication Definitionと、Platformが公開したTyped Extensionの入力を編集します。Capabilityの型と実装はPlatformチームが管理し、組織のGuardrailsを強制するPolicyはSREやSecurityの担当者が管理します。
変更権限が異なる定義はApplication Definitionから分け、それぞれの担当者だけが変更できる場所で管理します。Applicationの入力はSchemaとValidationで確認し、許可していない設定の上書きは受け付けません。
標準設定から個別拡張までの入力設計
Standard Classと個別設定
Applicationごとに必要な設定は異なります。Platform APIではStandard Classを選び、必要な場合だけ個別設定や追加機能を指定できるようにします。Standard ClassはGolden Pathで提供する組織標準の構成で、次の条件に合うApplicationはClassを選ぶだけで利用できます。
- 共通の技術スタック:Go BackendとNext.js Frontendを組み合わせたFull Stack、TypeScript BackendとCDNで配信するStatic Websiteなど、Platformが用意した構成に一致すること。
- 共通のインフラ構成:DatabaseとCacheにはManaged ServiceのEndpointを使い、WorkerをPodで実行する構成やDatabaseまでKubernetesで管理する構成など、用意されたパターンを利用できること。
- 標準構成で扱える負荷:Platformが定めた最小のCPUとMemoryから開始でき、想定する負荷が標準構成で扱える範囲に収まること。
- 共通の運用条件:Backup保持日数、PITRの有効化と復旧、Logの保存日数・保存先・調査について、組織の標準設定と手順を使えること。
Standard Classを指定した場合も、変更を許可した項目では利用者が指定した値を採用します。
次の例では、Databaseにproduction-standardというStandard Classを指定しています。
database:
class: production-standardStandard Classの構成と運用条件を利用しながら、一部の値だけを変えたいApplicationもあります。 Database EngineやInstance Classを指定する必要がある場合は、Platformが変更を許可した具体設定を公開します。
次の例は、Aurora PostgreSQLとInstance Class、Backup保持日数を指定した構成です。
database:
class: production-standard
implementation:
engine: aurora-postgresql
instanceClass: db.r7g.large
backupRetentionDays: 14Standard Classが前提とする構成や運用条件が合わない場合は、別のStandard Classか従来型のIaC定義を使います。標準構成を維持したまま、既存の項目では指定できない新機能や特殊なリソースを追加する場合は、型と入力規則を持つTyped Extensionを使います。
Capabilityごとの提供内容
入力が簡潔でも、Platformが何を用意するのかは明示する必要があります。DatabaseのClassを選んだときに、接続用Secretまで用意されるのか、削除時にSnapshotを残すのかによって、利用者の作業は変わります。
この「Platformがどこまで面倒を見るのか」という責任境界を曖昧にしないための取り決めがCapability Contractです。 各Capability Contractには、次の情報を含みます。
- 入力:利用者が指定できる値、Standard Classによるデフォルト値、上書きを許可する範囲
- 生成対象:作成するリソース、既存リソースとの接続、利用者へ渡すEndpointやSecret
- 運用条件:可用性、Backup保持日数、PITR、Logの保存先と保存日数、監視と調査の方法
- 更新と削除:設定変更時に更新される対象、再作成の有無、削除時のSnapshotやデータの扱い
- 状態と担当:利用者へ返す状態、障害時に確認する項目、Platform側の保守担当
- 互換性:Contractのバージョン、互換性のない変更の扱い、利用中のApplicationを移行する方法
例えば、Databaseのproduction-standardを選んだ場合、Database本体だけでなく、接続用のSecret、BackupとPITR、削除時のSnapshot、障害時の調査方法までがContractの対象です。 入力できる型と値はSchemaとValidationで確認します。 運用条件、削除時の扱い、障害対応は文書とRunbookに記載し、実装と一緒にバージョンを管理します。
新機能の追加とTyped Extension
Application Modelを運用していると、現在のAPIでは表現できない機能が必要になることがあります。 例えば、payment-apiから外部サービスへPrivate接続したい場合、既存のworkload、exposure、databaseでは要求を表せません。 この一件のために共通のPlatform APIへ接続先固有のFieldを追加すると、APIの更新と互換性の確認が必要になり、使わないApplicationにもFieldが残ります。
新機能を共通のPlatform APIのリリースから独立して追加するためにTyped Extensionを使います。 新機能に専用の型を用意し、Applicationから参照します。Private接続の例では、SpecializedNetworkBindingを次のように定義します。
apiVersion: platform.example.io/v1
kind: SpecializedNetworkBinding
metadata:
name: payment-private-link
spec:
targetService: external-payment-service
class: private-standardApplication側に追加するのは、作成したExtensionへの参照だけです。
resources:
- ref:
apiVersion: platform.example.io/v1
kind: SpecializedNetworkBinding
name: payment-private-link新機能の追加に必要なものは、次のとおりです。Capabilityの保守担当が用意します。
- ExtensionのSchemaと、入力値のValidation
- 生成するリソースと、既存のCapabilityへ接続する処理
- Extensionの作成・変更権限に関するGuardrailsと、それを実装するPolicy
- 状態の表示、障害時の担当、更新と削除の手順
- Extensionのバージョンと、互換性を維持する期間
これらを用意すると、新機能を必要とするApplicationだけが入力を追加できます。開発者は型とValidationのあるAPIを使い、Platformチームは実装と変更権限を管理します。
追加後は、同じ機能を必要とするApplicationがほかにもあるかを確認します。複数のApplicationで使うようになれば、Capabilityの正式APIやStandard Classへ組み込みます。特定のサービスだけが使うなら、担当者、Contract、廃止条件を定めたTyped Extensionとして保守します。 Platform側で保守しない一度限りの構成はTyped Extensionにせず、第2節で述べた従来型のIaC定義で管理します。
Application Modelのバージョン管理
実際に作られるResourceは、Application Definitionだけでは決まりません。Platform API、Standard Class、Capabilityの実装、Policy、共有リソースにもVersionがあります。例えば、production-standardの設定が変われば、Application Definitionが同じでも作られるResourceは変わります。そのApplicationへ適用したVersionを後から確認できるようにします。
利用した構成をApplication Resolutionに記録する
利用者がすべてのVersionを手動で指定する必要はありません。Applicationを解釈するときに使ったPlatform API、Standard Class、各Capabilityの実装、Policy、参照した共有Resourceの識別子またはVersionをPlatformがまとめて保存します。この記録がApplication Resolutionです。
Application全体を1つのApplication Version 42だけで管理する方式と異なり、CapabilityごとにVersionを確認し、切り替えることができます。Application Resolutionは本稿で付けた名称であり、既存ツールのAPI名ではありません。
ただし、共有ControllerやProviderの旧Versionを動かし続けるには複数Versionを並行稼働させ、適用先を分ける必要があります。また、Resolutionを以前の状態へ戻しても、共有Networkの現在の設定やDatabase内のデータまでは元に戻りません。
新しいApplication Resolutionを段階的に適用する
Applicationの作成時には、その時点で動作を確認した共通定義と実装を選び、具体的なVersionをApplication Resolutionへ記録します。共通定義が更新されても、既存ApplicationのResolutionは自動では変わりません。
既存Applicationを新しいResolutionへ移す操作がPromotionです。Platformは採用する共通定義のVersionを選び、対象Applicationの新しいResolutionを作成します。適用対象は開発環境、Application名、Applicationのグループなどで指定し、RenderとPlanで差分を確認してから開発環境、一部の本番、全体の順に広げます。
例えば、DatabaseのBackup保持期間を7日から14日へ延ばす場合は、新しいproduction-standard@4を用意します。この例で変更するのはStandard Classだけで、Databaseの実装は維持します。
最初の対象はpayment-apiです。新しいResolutionを作り、Databaseの再作成や停止が発生しないことをPlanで確認します。問題がなければ一部の本番Applicationへ対象を広げ、最後に全体へ適用します。
問題が見つかった場合はPromotionを止め、戻せる変更だけを以前のResolutionへ戻します。Database Engine Upgradeのように実データが変わる処理には、別の復旧手順やデータ移行手順が必要です。Security上の緊急変更でも新旧のResolution、対象Application、Planと適用の結果は記録に残します。
ResourceごとにLifecycleを管理する
Resourceごとの成否を保持する
payment-apiの作成では、DatabaseのProvisioningが完了した後にWorkloadのPod起動だけが失敗することがあります。原因がImageの指定ミスやHealth Checkの設定なら、直すべきなのはWorkloadです。
ここでApplication全体へ一律のRollbackを適用すると、正常に作成されたRDSまで削除や再作成の対象になります。Databaseの作成をやり直せば待ち時間が増え、接続先が変わる可能性もあります。データを持たないWorkloadとデータを保持するDatabaseでは、失敗を閉じ込める範囲も再試行の単位も異なります。
Application全体の進捗はまとめて管理しながら成功したResourceの状態は維持し、失敗したCapabilityだけを再試行できるようにします。
Application Statusには、Application全体がPartiallyReadyであることに加えて、DatabaseとPublic EndpointはReady、WorkloadはFailedであることを表示します。開発者はWorkloadの入力を修正して再試行でき、Platformチームも正常なDatabaseを調査対象から外せます。
Capabilityごとに独立して更新する
Applicationを構成するResourceは変更の頻度も影響も異なります。WorkloadのImageはリリースのたびに更新しますが、その変更に合わせてDatabaseやLoad Balancerまで処理する理由はありません。変更対象をCapability単位で特定し、Workload CapabilityだけをReconcileします。ほかのResourceと、そのVersionは現在の状態を維持します。
Resourceごとの廃止手順
Applicationを削除するときは、Resourceごとに廃止手順を実行します。
Application本体を先に削除する場合は、BackupをApplicationとは別のResourceとして管理し、その所有者と保持期限を記録します。保持または削除の処理後に、管理対象から外れたResourceが残っていないことを確認します。
共有リソースはApplication削除の対象外とし、そのApplicationからの参照だけを外します。共有リソースの廃止は、参照がなくなった時点で所有者が定めたPolicyに従って決めます。
Render、Plan、Status、Export
Static Renderで適用前の最終構成を確認する
Static Renderは、Application Definitionを実環境へ適用せず、作成予定のResourceと適用値を出力する機能です。Renderでは、利用者が選んだClassと指定値にStandard Classのデフォルト値、Capability実装の設定、組織のPolicyを反映します。
例えば、payment-apiの利用者がDatabaseにproduction-standardを選び、Backup保持期間だけを30日に変更したとします。利用者が書いていない項目を含むRender結果は、次のような値です。
database:
engine: aurora-postgresql # Standard Classのデフォルト値
backupRetentionDays: 30 # 利用者による上書き
pointInTimeRecovery: enabled # Standard Classのデフォルト値
encryption: enabled # 組織のGuardrails
logDestination: central-logs # Standard Classのデフォルト値Static Renderは、第1節で定義したApplication Resource GraphへResolutionとPolicyを反映し、Deployment、Service、Load Balancer、DatabaseなどのResourceへ展開します。この結果がRendered Resource Graphです。Database Endpointのように適用後まで決まらない値は、生成するResourceと利用するResourceの関係で示されます。
利用者のYAMLが同じでも、Standard ClassやCapabilityの実装が変われば適用される構成は変わります。Planは新旧ResolutionのRender結果から共通定義による変更を算出します。さらに、新しいRender結果と現在の実Resourceを比較し、Driftを含む差分から適用時に作成、変更、削除するResourceを示します。
PlanでApplicationへの影響とResource差分を確認する
Planでは、Applicationに起きる変化と、生成するResourceの差分を一緒に示します。開発者は停止や再作成の有無を確認できます。Platform、SRE、Securityの担当者は、YAMLやクラウドリソースの差分まで調べます。
Plan
Applicationへの影響
- Public Endpoint: なし
+ Public Endpoint: 追加
- TLS: 無効
+ TLS: 有効
- Database接続権限: なし
+ Database接続権限: 付与
- Workload: 現在のPodを継続
+ Workload: 新しい設定で再起動
Database: 変更なし、再作成なし
Resourceの差分
- Deployment annotation: rollout/version=v41
+ Deployment annotation: rollout/version=v42
+ TargetGroupBinding/webを作成
+ SecurityGroupRule/database-accessを作成
- IAM Policy: database connectionなし
+ IAM Policy: database connectionあり
Database Resource: 変更なし本番へ適用する前に、新旧ResolutionのRender差分と、新しいRender結果と実Resourceの差分を1つのPlanにまとめます。影響を受けるApplication、再作成や停止の有無、データ変更、Rollbackの可否を示します。
StatusにはApplicationへの影響、原因、修正方法を含める
開発者向けのStatusには、Controllerの内部処理ではなく、Applicationへの影響を表示します。
- 外部公開やDatabase接続など、現在利用できる機能
- 作成済みのResourceと、まだ作成されていないResource
- 現在どのCapabilityがReadyか
- 失敗した場合、どの入力を直せばよいか
Platform、SRE、Securityの担当者には、生成Manifest、Resource Graph、Version、Policyに加えて、最終値がStandard Class、利用者入力、Policyのどれから決まったのかまで表示します。
Application PublicEndpoint is not ready.
Cause:
TargetGroupBinding/web is not Ready.
TargetGroup health check GET /health returned HTTP 404.
Action:
Change spec.exposure.healthCheck.path,
or verify that the container exposes the configured endpoint.内部Resourceの名前と失敗理由だけでは、開発者は自分の入力を直すべきか、Platformチームへ依頼すべきかを判断できません。Statusには原因になったResourceとともに、開発者が入力を直すのか、Platform担当者へ依頼するのかを表示します。
Exportには移行に必要な情報を含める
生成ManifestやCloud Resourceの設定は、適用前の確認、監査、復旧、別実装への移行に使います。移行に備え、Application Resolution、生成したResourceと依存関係、Cloud ResourceのPhysical ID、Importに必要な値をExportできるようにします。Application Definitionは、移行後も利用者が編集する入力として残します。
提唱するApplication Modelの全体構成
| 条件 | 対応する構成 |
| Application全体の管理 | Application DefinitionとApplication Resource Graphで対象と依存関係を表し、Application、共有リソース、Platformの所有範囲を分ける。Resourceごとに作成、更新、保持、削除を管理する |
| 開発者のセルフサービス | Standard Class、具体設定、Typed Extensionを使い分け、Capability Contractで入力と提供内容を示す |
| 共通定義の変更管理 | Capabilityごとに実装を分け、Application Resolutionで利用した構成を記録する。RenderとPlanで影響を確認し、PromotionとRollbackを行う。別実装への移行情報はExportする |
| 現在の状態と修正担当の表示 | Application Statusに、Applicationへの影響、原因となったResource、入力を直す利用者または対応するPlatform担当者を表示する |
Application全体の所有範囲、開発者が操作できる入力、Platformチームが保守する実装、適用した構成と現在の状態を1つにつなげることで、開発者はインフラの詳細を知らずにサービスを運用でき、Platformチームは共通定義を安全に変更できます。この分業を継続できることが、Platform Engineering時代のApplication Modelに必要な構成です。
まとめ:Platform Engineering時代のApplication Model
Application Modelは、Platform Engineering以前から運用の中にあります。Helmは、Applicationに必要なKubernetes ResourceをChartにまとめ、利用者が変更できる項目をValuesで公開する、身近で簡単なApplication Modelです。サービスの技術スタックや運用条件がそろっている間は、この形でGolden Pathを提供できます。
要件の異なるサービスを1つのChartで扱うと、Valuesと条件分岐が増えます。Kubernetes外のResource、運用条件、サービスごとの例外まで扱おうとすれば、1つのChartでは管理しきれません。Templateの複雑さに加えて、Applicationに含めるResource、開発者が変更できる項目、Platformが共通化する運用手順、共通定義の更新方法も決める必要があります。Application Modelの設計によって、開発チームが扱う設定とPlatformチームが保守する実装の範囲が変わります。
本連載で扱ったKubeVela、Crossplane、Kroは、Helmより広い範囲を管理できます。Application全体の所有関係、共通定義を変更したときの影響確認、段階適用、障害時の説明に必要な機能がすべてそろうツールはありません。ツールを選んだあとも、開発者に何を公開し、Platformが何を提供するかは組織が決めます。そのため、既存ツールの機能から選ぶのではなく、Platform Engineering時代のApplication Modelに必要な条件から考え直しました。
今回の設計では、最初に「誰のための抽象か」を決めました。Application Modelは、開発者の入力を短くするだけの構文でも、インフラ担当者の作業だけを自動化する仕組みでもありません。開発者はインフラの実装詳細を知らずに日常の変更を完了でき、Platformチームは共通定義の影響を確認してから段階的に適用できます。両者が同じApplicationへ継続して変更を加えられることが、Platform EngineeringにおけるApplication Modelの本質です。
少なくとも本連載で確認した範囲では、本稿で挙げた条件をすべて満たすツールはありません。新しいKubeVela開発チームが進める改善と、Kro、Crossplaneがこれから実装する機能には、その差を埋める可能性があります。筆者も利用者として待つのではなく、必要な機能をOSSコミュニティへ提案し、設計と実装に参加します。KubeVela、Kro、Crossplaneに関わる開発者とともに、本稿で示したApplication Modelを実際に使える形へ近づけていきます。
この記事をシェアしてください
