初めに
前回の記事では、Crossplane の動作を API Server、Reconcile、status の流れで整理しました。
kubectl apply した YAML は Kubernetes API Server に保存され、Crossplane や Provider の controller がそれを継続的に見て、外部クラウドの状態と合わせていく、という話でした。
今回は、その上に 利用者向けの抽象 API をどう作るかを整理します。
中心になるのは、次の三つです。
XRD
XR
Composition
OCI Object Storage Bucket のような Managed Resource をそのまま利用者に見せることもできます。
ただし、Platform API として使いやすくするなら、利用者には OCI の全 field ではなく、利用者が本当に判断すべき項目だけを見せたい場面があります。
そのための部品が、XRD、XR、Composition です。
この記事のゴール
この記事のゴールは、次の関係を自分の言葉で説明できるようになることです。
XRD
-> 利用者向け API の型とスキーマを定義する
XR
-> 利用者が作成する要求そのもの
Composition
-> XR から Managed Resource などを作るレシピ
全体像は、次のように見ると分かりやすいです。
利用者
|
v
Composite Resource (XR)
|
v
Composition
|
v
Managed Resource
|
v
Provider
|
v
OCI Resource
ここで大事なのは、Composition が直接 OCI API を呼ぶわけではない、という点です。
Composition は、XR の内容から Kubernetes resource 群を作るためのレシピです。
その結果として作られた Managed Resource を、Provider が OCI API と状態合わせします。
なぜ抽象 API が必要なのか
Managed Resource を直接使うと、OCI の設定項目をかなり細かく扱えます。
これは強力ですが、利用者にとって常に分かりやすいとは限りません。
たとえば、開発チームが欲しいものは、次のような要求かもしれません。
team-a 用の bucket がほしい
標準の命名規則に従ってほしい
標準の tag を付けてほしい
必要な IAM や Secret の扱いは platform 側で決めてほしい
一方で、OCI 側の実装には、Object Storage Bucket、namespace、compartment、region、IAM policy、tag、Secret などが関係します。
この差をそのまま利用者に渡すと、利用者 API ではなく、クラウド実装の field 一覧になってしまいます。
Platform API の考え方では、利用者に見せる API と、platform 側で責任を持つ実装を分けます。
利用者が見る API
-> team, tier, region など
platform 側の実装
-> bucket 名、tag、IAM、ProviderConfig、Secret、Managed Resource
XRD、XR、Composition は、この分離を Crossplane 上で表現するための基本部品です。
XRD、XR、Composition を一文で整理する
まずは、三つの役割を短く整理します。
| 部品 | 役割 |
|---|---|
| XRD | 新しい Composite Resource API の型、名前、version、scope、schema を定義する |
| XR | XRD で定義された API を使って、利用者が作成する要求 |
| Composition | XR の要求から、Managed Resource などの実装 resource を作るレシピ |
もう少し具体的に言うと、XRD は API の設計図、XR はその API を使った一つの注文、Composition はその注文を実装へ変換する作り方です。
XRD
AppBucket という API を作る
XR
team-a 用に AppBucket を一つ要求する
Composition
AppBucket から OCI Bucket 用の Managed Resource を作る
この三つを分けて考えると、Crossplane の抽象化がかなり読みやすくなります。
XRD は利用者向け API の型とスキーマを定義する
XRD は CompositeResourceDefinition の略です。
Crossplane の公式ドキュメントでは、XRD は custom API の schema を定義し、ユーザーはその schema に基づいて Composite Resource を作成すると説明されています。
Kubernetes の CustomResourceDefinition に近いですが、Crossplane では Composite Resource 用の API を作るために使います。
たとえば、OCI Bucket を直接見せるのではなく、利用者向けに AppBucket という API を作りたいとします。
概念的には、次のような XRD になります。
apiVersion: apiextensions.crossplane.io/v2
kind: CompositeResourceDefinition
metadata:
name: appbuckets.platform.example.org
spec:
group: platform.example.org
names:
kind: AppBucket
plural: appbuckets
scope: Namespaced
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
team:
type: string
tier:
type: string
enum:
- standard
- premium
region:
type: string
required:
- team
- tier
- region
この例では、利用者に team、tier、region だけを入力してもらう API にしています。
OCI の bucket 名、tag、細かい policy、ProviderConfig の参照などは、ここでは利用者に直接見せていません。
XRD を読むときは、まず次の点を見ると分かりやすいです。
| 見る場所 | 意味 |
|---|---|
spec.group |
API group |
spec.names.kind |
利用者が書く kind
|
spec.names.plural |
API resource 名 |
spec.scope |
namespace 単位か cluster 単位か |
spec.versions[].schema.openAPIV3Schema |
入力できる field、型、必須項目、validation |
注意点として、XRD の group や names は気軽に変えるものではありません。
公式ドキュメントでも、XRD の group や names を変更するには XRD の削除と再作成が必要になると説明されています。
つまり、XRD は単なる YAML ではなく、利用者に公開する API の名前そのものを決める場所です。
scope は Namespaced を基本に考える
Crossplane v2 の XRD では、scope を指定できます。
代表的には、次の二つです。
| scope | 意味 |
|---|---|
Namespaced |
XR は namespace 内に作られる |
Cluster |
XR は cluster scope に作られる |
Platform API としてチームや namespace ごとに分離したい場合は、まず Namespaced を基本に考えると分かりやすいです。
Namespaced にすると、利用者は自分の namespace に XR を作り、RBAC も namespace 単位で設計しやすくなります。
一方で、cluster 全体の設定や platform 全体に関わる API であれば、Cluster が合う場合もあります。
また、古い資料や v1 互換の説明では、Composite Resource Claim、つまり XRC が出てくることがあります。
ただし、Crossplane v2 の新しい namespaced XR では、claims は基本的に使いません。
公式の v2 API でも、claimNames は v2 ではサポートされない扱いになっています。
そのため、新しく設計するなら、まずは Namespaced な XR と RBAC で利用者入口を作る、という見方が自然です。
XR は利用者が作成する要求そのもの
XR は Composite Resource の略です。
XRD によって AppBucket という API が作られると、利用者はその API を使って実際の要求を書けるようになります。
たとえば、次のような YAML です。
apiVersion: platform.example.org/v1alpha1
kind: AppBucket
metadata:
name: demo-bucket
namespace: team-a
spec:
team: team-a
tier: standard
region: ap-tokyo-1
この YAML は、OCI Bucket の全設定ではありません。
利用者が platform に対して出す、より小さく整理された要求です。
ここで利用者が考えるのは、たとえば次のような内容です。
どの team の bucket か
どの service tier か
どの region に置くか
逆に、次のようなことは platform 側に隠せます。
bucket 名の完全な命名規則
共通 tag
ProviderConfig の名前
Secret の置き場所
OCI IAM の細かい設計
Managed Resource の apiVersion や kind
この分離によって、利用者は cloud provider の細部ではなく、自分のアプリケーションやチームの要求に集中できます。
Composition は XR を実装 resource へ変換するレシピ
Composition は、XR をどのような Kubernetes resource 群へ展開するかを定義します。
Crossplane の公式ドキュメントでは、Composition は一つの Composite Resource の要求から複数の Kubernetes resources を作るための template と説明されています。
ここで最初に混乱しやすい点があります。
XRD は apiextensions.crossplane.io/v2 ですが、Composition は現在も apiextensions.crossplane.io/v1 の API を使います。
これは書き間違いではありません。
概念的には、Composition は次のような形になります。
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: appbucket-oci
spec:
compositeTypeRef:
apiVersion: platform.example.org/v1alpha1
kind: AppBucket
mode: Pipeline
pipeline:
- step: patch-and-transform
functionRef:
name: function-patch-and-transform
ここでまず見るべきなのは、compositeTypeRef です。
compositeTypeRef は、この Composition がどの XR の型に対応するかを示します。
上の例では、platform.example.org/v1alpha1 の AppBucket に対応しています。
次に見るのが mode: Pipeline と pipeline です。
現在の Crossplane では、Composition は Function pipeline として処理されます。
各 step が Function を呼び出し、最終的に Crossplane が作成または更新すべき resource 群を組み立てます。
その中に OCI Bucket の Managed Resource が含まれていれば、次の段階で OCI Provider がその Managed Resource を reconcile します。
つまり、流れは次のようになります。
XR
|
v
Composition pipeline
|
v
Managed Resource YAML
|
v
Provider controller
|
v
OCI API
Composition は「OCI を直接操作する処理」ではありません。
XR から Managed Resource などを作るためのレシピ、と見ると理解しやすいです。
XRD、XR、Composition、Managed Resource の関係
ここまでをまとめると、役割は次のように分かれます。
XRD
API の型とスキーマを決める
XR
利用者の要求を表す
Composition
要求を実装 resource へ変換する
Managed Resource
Provider が外部 API と状態合わせする対象
OCI Bucket の例で言うと、次のような分担です。
| 層 | 例 | 誰が主に見るか |
|---|---|---|
| XRD |
AppBucket API の schema |
platform team |
| XR |
team-a の demo-bucket 要求 |
利用者、platform team |
| Composition |
AppBucket から OCI Bucket MR を作るレシピ |
platform team |
| Managed Resource | OCI Object Storage Bucket の Kubernetes 表現 | platform team、debug 時の運用者 |
| OCI Resource | 実際の Object Storage Bucket | OCI 管理者、運用者 |
利用者にとって重要なのは、XR の spec が自分たちの言葉になっていることです。
platform team にとって重要なのは、Composition 側で命名、tag、policy、ProviderConfig、出力の扱いを標準化できることです。
Composite Resource Claim はどう見るか
Crossplane の古い資料や既存環境では、Composite Resource Claim、つまり XRC が出てくることがあります。
XRC は、namespace 側から XR を要求する入口として使われてきた仕組みです。
特に Crossplane v1 系の設計では、namespace に claim を作り、それに対応する XR が作られる、という形がよく出てきます。
ただし、Crossplane v2 では namespaced XR が入ったため、新しく Platform API を設計する場合は、まず XRC ではなく namespaced XR を中心に考えるのが分かりやすいです。
そのため、資料やサンプルを読むときは、次のように切り分けると混乱しにくくなります。
新しく v2 前提で設計する
-> Namespaced XR を中心に見る
既存の v1 系資料や古い platform design を読む
-> XRC が出る可能性がある
XRC を完全に忘れてよい、という意味ではありません。
既存環境を読むときには必要になることがあります。
ただし、最初に学ぶ主線としては、XRD、XR、Composition の三つを先に押さえるほうが理解しやすいです。
利用者入口は「誰に、どの粒度の API を見せるか」で決まる
Platform API を設計するときに大事なのは、最初から全部を抽象化しようとしないことです。
たとえば、OCI Bucket を扱う場合でも、利用者に見せる API の粒度はいくつかあります。
Bucket そのものを見せる
-> OCI の概念に近い
AppBucket として見せる
-> アプリケーション向けに少し抽象化する
TeamStorage として見せる
-> bucket 以外の policy や Secret も含めた能力として見せる
どれが正解かは、組織や利用者によって変わります。
開発チームが OCI に詳しく、細かい field を自分で扱いたいなら、Managed Resource に近い API でもよいかもしれません。
一方で、platform team が標準化や安全な初期値を強く管理したいなら、AppBucket や TeamStorage のような API のほうが合います。
判断するときは、次の問いが役に立ちます。
利用者は誰か
利用者はどの field を判断すべきか
platform team が標準化したい部分はどこか
namespace と RBAC はどう分けるか
削除や変更の責任は誰が持つか
XRD は API の形を固定します。
だからこそ、YAML を書き始める前に、利用者入口の粒度を決めておくことが重要です。
読む順番は XRD、XR、Composition
Crossplane の抽象 API を読むときは、いきなり Composition の中身から入ると迷いやすいです。
おすすめの順番は、次の通りです。
1. XRD
どんな API が定義されているかを見る
2. XR
利用者は何を要求しているかを見る
3. Composition
その要求をどう実装へ変換しているかを見る
4. Managed Resource
実際にどんな resource が作られたかを見る
5. status
READY / SYNCED / atProvider で状態を見る
コマンドとしては、たとえば次のような見方になります。
kubectl get compositeresourcedefinitions.apiextensions.crossplane.io
kubectl get compositions.apiextensions.crossplane.io
kubectl get appbuckets.platform.example.org -n team-a
kubectl describe appbuckets.platform.example.org demo-bucket -n team-a
実際の resource 名は、XRD で定義した group、names、versions によって変わります。
まず XRD を見て API の名前を確認し、その後で XR と Composition を追うと、全体のつながりを失いにくくなります。
まとめ
今回は、Crossplane で Platform API を作るための基本部品として、XRD、XR、Composition を整理しました。
ポイントは、次の三つです。
XRD は API の型とスキーマを定義する
XR は利用者の要求を表す
Composition は実装 resource へ変換するレシピである
Managed Resource は cloud provider の具体的な resource に近い層です。
一方で、XRD と XR は利用者に見せる API の層です。
Composition は、その二つをつなぎます。
この関係を押さえると、Crossplane を「OCI resource を YAML で作る仕組み」としてだけでなく、「組織向けの Platform API を作る仕組み」として見やすくなります。
次は、Composition の中身、特に Patch and Transform や Composition Functions を使って、XR の入力をどのように Managed Resource へ渡すのかを見ていきます。