Claude CodeでCrossplaneのCompositionを書く手順
Claude CodeにXRDとCompositionを書かせ、crossplane composition renderでクラスタを使わずローカル検証する手順をまとめます。
Crossplaneのcompositionは、複数のKubernetesリソースを1つのカスタムAPIとしてまとめる仕組みです。Claude Codeに書かせると、スキーマ定義(XRD)とリソース生成のロジック(Composition)を分けて進められます。この記事では、両者の役割分担と、クラスタを使わずローカルで検証するコマンドまでを扱います。
Crossplaneのcompositionとは
Compositionとは、複数のKubernetesリソースをまとめて作るためのテンプレートです。公式ドキュメントは、仮想マシン・ストレージ・ネットワークポリシーをまとめて1つの解決策にする例を挙げています。Crossplaneではこの「まとめられる側」の新しいAPIをXR(composite resource)と呼び、XRのスキーマをXRD(CompositeResourceDefinition)で定義します。
XRDとCompositionの役割
XRD
どんなフィールドを持つAPIかを決めます。spec.imageのような入力欄と、statusに返す出力欄を宣言します。
Composition
そのAPIのXRが作られたときに、何を作るかを決めます。Deploymentなどの定義と、XRの値を流し込むパッチを持ちます。
同じXRD(同じ種類のXR)に対して複数のCompositionを用意し、用途ごとに使い分けることもできます。Helmチャートが1つのテンプレートでYAMLを展開するのに対し、Crossplaneではスキーマ(XRD)と生成ロジック(Composition)が別オブジェクトです。
前提条件
このガイドはCrossplaneの公式チュートリアルに沿っています。必要なのは次の2つです。
- 2GB以上のRAMを持つKubernetesクラスタ
- クラスタにインストール済みのCrossplane v2
ローカルでの検証だけなら、後述のcrossplane composition renderコマンドがDocker Engineを使ってその場で結果を確認できるため、クラスタへの適用は最後の1回で済みます。クラスタへ実際に接続してリソースを操作させたい場合は、Kubernetes MCPサーバーでClaudeからクラスタを操作するで扱っているMCP経由の接続が選択肢になります。本記事はファイルとしてXRDとCompositionを書く作業に絞ります。
ステップ1: XRDで新しいAPIのスキーマを定義する
Kubernetesでは、利用者が定義したAPIリソースをカスタムリソース(custom resource)と呼びます。Crossplaneは、そのうちcompositionで作られるものを特にコンポジットリソース(composite resource、XR)と呼びます。XRDはこのXRのスキーマを定義するオブジェクトです。
次はAppという名前のXRを定義するXRDの例です。spec.imageを必須の文字列フィールドとして公開し、statusにreplicasとaddressを持たせています。
apiVersion: apiextensions.crossplane.io/v2
kind: CompositeResourceDefinition
metadata:
name: apps.example.crossplane.io
spec:
scope: Namespaced
group: example.crossplane.io
names:
kind: App
plural: apps
versions:
- name: v1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
image:
type: string
required:
- image
status:
type: object
properties:
replicas:
type: integer
address:
type: stringClaude Codeへは、フィールドと型を指定して依頼すると迷いなく書けます。
「example.crossplane.ioグループにAppというXRDを作って。specにimage(必須の文字列)、statusにreplicas(整数)とaddress(文字列)を持たせて」
apiVersionはapiextensions.crossplane.io/v2です。次のステップで書くCompositionはapiextensions.crossplane.io/v1を使うため、Claude Codeが既存のCompositionからXRDをコピーして書くと、このAPIバージョンの食い違いをそのまま持ち込みがちです。
kubectl apply -f xrd.yaml
kubectl get compositeresourcedefinition apps.example.crossplane.ioESTABLISHED列がTrueになれば、KubernetesはこのXRD経由でAppへのAPIリクエストを受け付け始めています。
Crossplane CLI v2.5.0にはbetaのコマンドcrossplane xrd generateがあり、XRまたはSimpleSchemaの定義からXRDを生成できます。ヘルプにはbeta機能が将来のリリースで変わりうると書かれているため、生成結果はステップ1のYAMLと見比べてから使います。
ステップ2: CrossplaneのComposition関数を選ぶ
Compositionは単体では何も作りません。「XRが作成・更新されたときに何をするか」を決めるのはComposition関数です。公式ドキュメントは6つの言語を挙げています。
| 言語 | 向いている用途 |
|---|---|
| templated YAML | 向いている用途Helmチャートに慣れている場合 |
| YAML | 向いている用途ループや条件分岐のない小さな静的構成 |
| YAML+CEL | 向いている用途YAMLで書きつつCEL式でリソース間を接続。依存関係の解決は自動 |
| Python | 向いている用途動的なロジックが必要。標準ライブラリを全て使える |
| KCL | 向いている用途動的なロジックが必要。高速でサンドボックス化されている |
| Pythonic | 向いている用途動的なロジックが必要。低レベルAPIをPythonクラスで隠したい場合 |
Claude Codeに書かせる場合、フィールドのパッチを列挙するだけのYAML(patch-and-transform)は差分が一目で追え、Claude Codeが書いたパッチのどこが変わったかをレビューしやすい構成です。Helm風のテンプレート構文で慣れた書き方をそのまま使いたい場合は、Claude CodeでHelmチャートを作成する手順で扱っているテンプレート変数の設計が参考になります。
使う関数はKubernetesにインストールしてから参照します。fn-patch-and-transform.yamlは次の内容です。
apiVersion: pkg.crossplane.io/v1
kind: Function
metadata:
name: crossplane-contrib-function-patch-and-transform
spec:
package: xpkg.crossplane.io/crossplane-contrib/function-patch-and-transform:v0.8.2kubectl apply -f fn-patch-and-transform.yaml
kubectl get function crossplane-contrib-function-patch-and-transformINSTALLEDとHEALTHYが両方Trueになっていることを確認してから次に進みます。
ステップ3: CompositionをXRDに紐づける
CompositionはXRDが定義したXRの型に対してだけ有効です。この対応はspec.compositeTypeRefが決めます。CrossplaneはcompositeTypeRefが一致するCompositionの中から、XRに使うものを選びます。
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: app-yaml
spec:
compositeTypeRef:
apiVersion: example.crossplane.io/v1
kind: App
mode: Pipeline
pipeline:
- step: create-deployment-and-service
functionRef:
name: crossplane-contrib-function-patch-and-transform
input:
apiVersion: pt.fn.crossplane.io/v1beta1
kind: Resources
resources:
- name: deployment
base:
apiVersion: apps/v1
kind: Deployment
spec:
replicas: 2
template:
spec:
containers:
- name: app
ports:
- containerPort: 80
patches:
- type: FromCompositeFieldPath
fromFieldPath: metadata.name
toFieldPath: metadata.labels[example.crossplane.io/app]
- type: FromCompositeFieldPath
fromFieldPath: metadata.name
toFieldPath: spec.selector.matchLabels[example.crossplane.io/app]
- type: FromCompositeFieldPath
fromFieldPath: metadata.name
toFieldPath: spec.template.metadata.labels[example.crossplane.io/app]
- type: FromCompositeFieldPath
fromFieldPath: spec.image
toFieldPath: spec.template.spec.containers[0].image
- type: ToCompositeFieldPath
fromFieldPath: status.availableReplicas
toFieldPath: status.replicas
readinessChecks:
- type: MatchCondition
matchCondition:
type: Available
status: "True"
- name: service
base:
apiVersion: v1
kind: Service
spec:
ports:
- protocol: TCP
port: 8080
targetPort: 80
patches:
- type: FromCompositeFieldPath
fromFieldPath: metadata.name
toFieldPath: metadata.labels[example.crossplane.io/app]
- type: FromCompositeFieldPath
fromFieldPath: metadata.name
toFieldPath: spec.selector[example.crossplane.io/app]
- type: ToCompositeFieldPath
fromFieldPath: spec.clusterIP
toFieldPath: status.address
readinessChecks:
- type: NonEmpty
fieldPath: spec.clusterIPdeploymentとserviceの2つをresourcesに並べ、それぞれのpatchesでXRのmetadata.nameをラベルとセレクタへ、spec.imageをコンテナイメージへ反映させています。deployment側はspec.selector.matchLabelsとspec.template.metadata.labelsの両方にラベルを通さないと、KubernetesがPodをDeploymentの管理下として認識しません。mode: PipelineはCompositionの実行方式です。pipelineには1つ以上の関数をステップとして並べられ、後段の関数は前段の出力を書き換えられます。
Crossplaneが最終的に使うのは、パイプラインの最後の関数が返した結果です。
XRDからの雛形づくりには、betaのcrossplane composition generateもあります。function-auto-readyを実行する1ステップだけのCompositionが生成されるので、そこへ関数の入力を書き足していきます。
同じ種類のXRに対して複数のCompositionを作ることもできます。用途ごとにapp-yamlとapp-pythonのような別名のCompositionを用意しておき、XR個別に選ぶか既定値を決めておく運用です。個々のXRではspec.crossplane.compositionRef.nameで名前指定、またはspec.crossplane.compositionSelector.matchLabelsでラベル指定して選べます。XR側で何も指定しなかった場合の既定は、XRD側のspec.defaultCompositionRefで設定します。全XRに特定のCompositionを使わせたいときは、XRDのenforcedCompositionRef.nameで固定できます。
Compositionを編集すると、そのたびに新しいCompositionリビジョンが作られます。XRは既定(compositionUpdatePolicy: Automatic)で最新のリビジョンへ自動的に切り替わり、XR側をManualにすると切り替わりません。XRD側で既定を変えるならdefaultCompositionUpdatePolicyです。Claude Codeに何度もCompositionを書き換えさせる運用では、この自動追従で本番のXRにも変更が届く点に注意します。IaCツール自体の選定で迷う場合は、Terraform/Pulumi/CloudFormationのMCP比較がKubernetesネイティブなCrossplaneとの対比材料になります。
crossplane composition renderでクラスタなしに検証する
CompositionはCrossplane CLIのcrossplane composition renderでローカルにプレビューできます。クラスタへの接続は不要で、Docker EngineでFunctionを実行して結果を標準出力に返します。Crossplane CLI自体は次のコマンドでインストールできます。
curl -sfL "https://cli.crossplane.io/install.sh" | shスクリプトはカレントディレクトリにcrossplaneバイナリを置き、最後にsudo mv crossplane /usr/local/binを案内します。バージョンはcrossplane versionで見られます。クラスタに接続していない環境ではClient Version: v2.5.0が出たあと、kubeconfigが無いというエラーで止まります。--versionというフラグはなく、crossplane --versionを実行してもバージョンは出ず、使い方(Usage)が表示されます。
renderには3つのファイルを渡します。ステップ3のCompositionはcomposition.yamlとして保存しておきます。Functionはステップ2で作ったfn-patch-and-transform.yamlをそのまま使い、加えてXR本体をxr.yamlとして用意します。
apiVersion: example.crossplane.io/v1
kind: App
metadata:
namespace: default
name: my-app
spec:
image: nginxcrossplane composition render xr.yaml composition.yaml fn-patch-and-transform.yaml出力はCompositionが作成する各リソースのYAMLです。XR本体の出し方は資料で違います。ドキュメントの出力例ではXR全体が先頭に並びます。一方、v2.5.0のcrossplane composition render --helpは、既定ではXRのstatusとmetadata.nameだけを出すと説明しています。入力XRのspecとmetadataの複製も含めるには、--include-full-xr(-x)を付けます。
renderの主なオプション
--helpに載っているオプションのうち、Compositionの検証で出番が多いものは次の4つです。
renderのオプション(v2.5.0)
-o 観測済みリソース
--observed-resourcesでYAMLファイルまたはディレクトリを渡すと、クラスタで観測されたリソースとして関数に見せられます。既存XRの更新を再現するときに使います。-r 関数の診断
--include-function-resultsで、関数が返した情報・警告をkind: Resultのリソースとして出力に含めます。--crossplane-version
renderに使うCrossplaneのバージョンを指定します。既定は最新の安定版で、ヘルプの例は
--crossplane-version=v2.3.0です。-e 追加リソース
--required-resourcesで、Compositionの外にあるクラスタ上のオブジェクトを模擬します。function-extra-resourcesなど、それを要求する関数と組み合わせます。
観測済みリソースのファイルは、Compositionのresourcesで付けた名前をcrossplane.io/composition-resource-name注釈に書いて渡します。ヘルプの例の注釈値はresource-bです。ステップ3のDeploymentなら、注釈の値はdeploymentです。
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
annotations:
crossplane.io/composition-resource-name: deployment
status:
availableReplicas: 2crossplane composition render xr.yaml composition.yaml fn-patch-and-transform.yaml \
-x -r -o observed.yaml実行にはDockerデーモンが必要です。ヘルプには、Dockerを使わない道として2つの設定が書かれています。関数側は、Functionにrender.crossplane.io/runtime: "Development"注釈を付ける方法です。この注釈があると、--insecure付きでlocalhost:9443に起動した関数へ接続します。Crossplane本体は--crossplane-binaryでローカルのバイナリを指定します。
Claude Codeに回させる検証サイクル
- 1
Compositionを編集させる
composition.yamlだけを直させ、この時点ではkubectlを実行させません。 - 2
renderして差分を報告させる
次のように依頼すると、出力を読ませたうえでパッチの結果を確認できます。
「compositionを編集したら
crossplane composition render xr.yaml composition.yaml fn-patch-and-transform.yaml -xを実行して、Deployment側のimageとラベルが意図通りパッチされているか差分を報告して」 - 3
承認してからクラスタへ適用する
結果に問題がなければ、ステップ4の
kubectl applyだけを人が確認して実行します。
renderはクラスタに接続せずに動きます。そこで.claude/settings.jsonのpermissions.allowにBash(crossplane composition render *)を追加しておくと、確認のたびに許可を求められずに済みます。実際にクラスタへ反映するkubectl applyは許可リストに入れず、都度確認する運用のままにします。使うFunctionのパッケージ名とバージョンはCLAUDE.mdに書いておくと、セッションをまたいでもClaude Codeが生成するfunctionRefがぶれません。
ステップ4: XRを作成してクラスタで確認する
renderでパッチの結果を確認したら、renderで使ったxr.yamlをそのままクラスタへ適用してXRを作成します。
kubectl apply -f xr.yaml
kubectl get -f xr.yaml出力のSYNCED列とREADY列が両方Trueになれば、AppはComposition経由でDeploymentとServiceを作り終えています。COMPOSITION列には実際に使われたComposition名が表示されるので、同じXRに複数のCompositionを用意している場合はここで見分けます。DeploymentとServiceの実体は次のコマンドで直接確認できます。
kubectl get deploy,service -l example.crossplane.io/app=my-appAppのspec.imageを書き換えると、Crossplaneは紐づくDeploymentのimageも追従させます。
よくあるつまずき
- パッチが意図せず上書きされる: 複数の関数を並べると、先に書いたパッチが後段の関数でエラーを出さずに書き換わることがあります。
crossplane composition renderの出力で、最終的な値を確かめます。 - provider未インストールの種類のリソースを作ろうとする: Crossplaneのサービスアカウントは、providerがインストールした種類とXRDが定義した種類のリソースに加えて、Deploymentのように自身の動作に必要な一部のコアKubernetesリソースにも既定でアクセスできます。本記事のDeployment・Serviceはこの既定権限の範囲内なので、追加のRBACは不要です。それ以外の種類(未インストールのproviderが管理するリソース等)を作る場合は、
rbac.crossplane.io/aggregate-to-crossplane: "true"のラベルを付けたClusterRoleを別途作成し、CrossplaneのClusterRoleに集約させます。 - XRを削除したら子リソースごと消える: Appを削除すると、Compositionが作ったDeploymentとServiceも一緒に削除されます。検証中に何度もXRを作り直す運用では、削除のタイミングに注意します。
まとめ
Crossplaneのcompositionは、APIのスキーマ(XRD)と生成ロジック(Composition)を分けて設計する仕組みです。Claude Codeには、差分を追いやすいYAMLのパッチから書かせるのが始めやすい進め方です。編集のたびにcrossplane composition renderをローカルで実行させれば、クラスタに触れる前にパッチの結果を確認できます。Kubernetesリソースを直接YAMLで書く基本操作は、Claude CodeでKubernetesマニフェストを書く手順で扱っています。
参照した一次ソース
この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。