- Published on
CrossplaneでKubernetes-Native IaCを実現する:Terraformを代替するクラウドコントロールプレーン
- Authors
- Name
- はじめに
- Crossplane vs Terraform
- Crossplaneのインストール
- AWS Providerの設定
- Managed Resources — クラウドリソースの直接管理
- Composition — 抽象化の核心
- Functions — 高度なCompositionロジック
- ArgoCD連携GitOps
- Usages — リソース依存関係の保護
- トラブルシューティング
- まとめ
はじめに
TerraformはIaCのデファクトスタンダードでしたが、Kubernetes中心の環境では限界があります。ステートファイルの管理、Plan/Applyの手動実行、ドリフト検出の困難さなどが代表的です。Crossplaneはこの問題を、Kubernetesの宣言的モデルとコントローラーパターンで解決します。
2025年10月にCNCF Graduatedプロジェクトに昇格したCrossplaneは、今やプロダクション環境で十分に検証されています。
Crossplane vs Terraform
| 項目 | Terraform | Crossplane |
|---|---|---|
| 実行モデル | CLI(Plan/Apply) | Kubernetesコントローラー(継続的調整) |
| 状態管理 | tfstateファイル(外部バックエンド必要) | etcd(Kubernetesネイティブ) |
| ドリフト検出 | 手動planが必要 | 自動(reconciliation loop) |
| 抽象化 | Module | Composition |
| 権限管理 | 別途IAM設定 | RBAC統合 |
| GitOps | 別途パイプラインが必要 | ArgoCD/Fluxネイティブ連携 |
Crossplaneのインストール
# Helmでインストール
helm repo add crossplane-stable https://charts.crossplane.io/stable
helm repo update
helm install crossplane crossplane-stable/crossplane \
--namespace crossplane-system \
--create-namespace \
--set args='{"--enable-usages"}'
# インストール確認
kubectl get pods -n crossplane-system
kubectl api-resources | grep crossplane
AWS Providerの設定
# AWS Providerのインストール
cat <<EOF | kubectl apply -f -
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws-s3
spec:
package: xpkg.upbound.io/upbound/provider-aws-s3:v1.18.0
EOF
# Providerのインストール確認
kubectl get providers
認証設定
# AWS認証情報Secretの作成
kubectl create secret generic aws-creds \
-n crossplane-system \
--from-file=credentials=$HOME/.aws/credentials
# ProviderConfigの作成
cat <<EOF | kubectl apply -f -
apiVersion: aws.upbound.io/v1beta1
kind: ProviderConfig
metadata:
name: default
spec:
credentials:
source: Secret
secretRef:
namespace: crossplane-system
name: aws-creds
key: credentials
EOF
Managed Resources — クラウドリソースの直接管理
# s3-bucket.yaml
apiVersion: s3.aws.upbound.io/v1beta2
kind: Bucket
metadata:
name: my-crossplane-bucket
spec:
forProvider:
region: ap-northeast-2
tags:
Environment: production
ManagedBy: crossplane
providerConfigRef:
name: default
kubectl apply -f s3-bucket.yaml
# 状態確認
kubectl get bucket my-crossplane-bucket
# NAME READY SYNCED EXTERNAL-NAME AGE
# my-crossplane-bucket True True my-crossplane-bucket 2m
# 詳細状態
kubectl describe bucket my-crossplane-bucket
RDSインスタンスの作成
# rds-instance.yaml
apiVersion: rds.aws.upbound.io/v1beta2
kind: Instance
metadata:
name: my-postgres
spec:
forProvider:
region: ap-northeast-2
allocatedStorage: 20
engine: postgres
engineVersion: '16.4'
instanceClass: db.t3.micro
dbName: myapp
masterUsername: admin
masterPasswordSecretRef:
name: rds-password
namespace: default
key: password
skipFinalSnapshot: true
publiclyAccessible: false
vpcSecurityGroupIdSelector:
matchLabels:
app: my-rds
providerConfigRef:
name: default
writeConnectionSecretToRef:
name: rds-connection
namespace: default
kubectl apply -f rds-instance.yaml
# 接続情報が自動的にSecretに保存される
kubectl get secret rds-connection -o yaml
Composition — 抽象化の核心
Compositionは複数のManaged Resourceを1つの高レベルAPIにまとめます。TerraformのModuleに似ていますが、Kubernetesネイティブです。
CompositeResourceDefinition(XRD)
# xrd-database.yaml
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xdatabases.platform.example.com
spec:
group: platform.example.com
names:
kind: XDatabase
plural: xdatabases
claimNames:
kind: Database
plural: databases
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
parameters:
type: object
properties:
size:
type: string
enum: ['small', 'medium', 'large']
default: 'small'
engine:
type: string
enum: ['postgres', 'mysql']
default: 'postgres'
region:
type: string
default: 'ap-northeast-2'
required:
- size
Composition
# composition-database.yaml
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: aws-database
labels:
provider: aws
spec:
compositeTypeRef:
apiVersion: platform.example.com/v1alpha1
kind: XDatabase
resources:
- name: rds-instance
base:
apiVersion: rds.aws.upbound.io/v1beta2
kind: Instance
spec:
forProvider:
region: ap-northeast-2
engine: postgres
engineVersion: '16.4'
skipFinalSnapshot: true
publiclyAccessible: false
providerConfigRef:
name: default
patches:
# size → instanceClassのマッピング
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.size
toFieldPath: spec.forProvider.instanceClass
transforms:
- type: map
map:
small: db.t3.micro
medium: db.t3.medium
large: db.r6g.large
# size → allocatedStorageのマッピング
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.size
toFieldPath: spec.forProvider.allocatedStorage
transforms:
- type: map
map:
small: '20'
medium: '100'
large: '500'
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.engine
toFieldPath: spec.forProvider.engine
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.region
toFieldPath: spec.forProvider.region
- name: security-group
base:
apiVersion: ec2.aws.upbound.io/v1beta1
kind: SecurityGroup
spec:
forProvider:
region: ap-northeast-2
description: 'Managed by Crossplane'
ingress:
- fromPort: 5432
toPort: 5432
protocol: tcp
cidrBlocks:
- '10.0.0.0/8'
Claim — 開発者が使用するインターフェース
# claim-database.yaml
apiVersion: platform.example.com/v1alpha1
kind: Database
metadata:
name: my-app-db
namespace: team-alpha
spec:
parameters:
size: medium
engine: postgres
region: ap-northeast-2
writeConnectionSecretToRef:
name: db-credentials
kubectl apply -f claim-database.yaml
# 開発者はこれだけ知っていればよい
kubectl get database -n team-alpha
# NAME READY CONNECTION-SECRET AGE
# my-app-db True db-credentials 5m
# プラットフォームエンジニアが確認
kubectl get composite
kubectl get managed
Functions — 高度なCompositionロジック
Crossplane Functionsを使用すると、Go/Pythonなどで複雑なパッチロジックを実装できます。
# function-go-templatingの使用例
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: dynamic-database
spec:
compositeTypeRef:
apiVersion: platform.example.com/v1alpha1
kind: XDatabase
mode: Pipeline
pipeline:
- step: render-resources
functionRef:
name: function-go-templating
input:
apiVersion: gotemplating.fn.crossplane.io/v1beta1
kind: GoTemplate
source: Inline
inline:
template: |
apiVersion: rds.aws.upbound.io/v1beta2
kind: Instance
metadata:
annotations:
gotemplating.fn.crossplane.io/composition-resource-name: rds
spec:
forProvider:
region: {{ .observed.composite.resource.spec.parameters.region }}
engine: {{ .observed.composite.resource.spec.parameters.engine }}
instanceClass: {{ if eq .observed.composite.resource.spec.parameters.size "small" }}db.t3.micro{{ else if eq .observed.composite.resource.spec.parameters.size "medium" }}db.t3.medium{{ else }}db.r6g.large{{ end }}
- step: auto-ready
functionRef:
name: function-auto-detect-ready
ArgoCD連携GitOps
CrossplaneリソースはKubernetesの通常のマニフェストなので、ArgoCDと自然に統合できます。
# argocd-application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: infrastructure
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/myorg/infra-repo.git
targetRevision: main
path: crossplane/claims
destination:
server: https://kubernetes.default.svc
namespace: default
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
# GitにClaimをpushすると自動的にインフラがプロビジョニングされる
git add claim-database.yaml
git commit -m "feat: provision medium postgres for team-alpha"
git push origin main
# ArgoCDが自動的にsync
argocd app get infrastructure
Usages — リソース依存関係の保護
削除順序を保護するUsageリソースです。
apiVersion: apiextensions.crossplane.io/v1alpha1
kind: Usage
metadata:
name: db-used-by-app
spec:
of:
apiVersion: platform.example.com/v1alpha1
kind: Database
resourceRef:
name: my-app-db
by:
apiVersion: apps/v1
kind: Deployment
resourceRef:
name: my-app
namespace: team-alpha
reason: 'Database is used by the application'
トラブルシューティング
# Providerの状態確認
kubectl get providers
kubectl describe provider provider-aws-s3
# Managed Resourceのイベント確認
kubectl describe bucket my-crossplane-bucket
# Compositionのデバッグ
kubectl get composite -o wide
kubectl describe xdatabase my-app-db-xxxxx
# Crossplaneのログ
kubectl logs -n crossplane-system deploy/crossplane -f
# 特定Providerのログ
kubectl logs -n crossplane-system \
$(kubectl get pods -n crossplane-system -l pkg.crossplane.io/revision -o name | head -1) -f
まとめ
CrossplaneはTerraformと競合するのではなく、Kubernetesネイティブ環境でIaCを一段階進化させます:
- 継続的調整:Plan/Applyなしで宣言するだけでコントローラーが自動管理
- セルフサービスプラットフォーム:Compositionで複雑なインフラを抽象化して開発者に提供
- GitOpsネイティブ:ArgoCD/Fluxとの自然な統合
- RBAC統合:Kubernetesの既存権限体系をそのまま活用
- ドリフト自動復旧:誰かがコンソールで手動変更しても自動的に復元
クイズ:Crossplane理解度チェック(7問)
Q1. CrossplaneがTerformと比較してドリフト検出に強い理由は?
Kubernetesコントローラーのreconciliation loopが継続的に実際の状態と宣言された状態を比較し、自動的に復旧します。
Q2. Managed ResourceとComposite Resourceの違いは?
Managed Resourceは実際のクラウドリソース(S3、RDSなど)を1:1でマッピングし、Composite Resourceは複数のManaged Resourceを1つの高レベルAPIにまとめたものです。
Q3. Claimの役割は何ですか?
Claimはネームスペースレベルで開発者がインフラを要求するインターフェースです。Composite Resourceを直接扱わず、抽象化されたAPIを使用します。
Q4. Crossplaneの状態(state)はどこに保存されますか?
Kubernetesのetcdに保存されます。Terraformのように別途の状態ファイル管理が不要です。
Q5. Compositionのmode: Pipelineにはどのようなメリットがありますか?
Go Templating、Pythonなど様々なFunctionをチェーンで連結して、複雑なリソース作成ロジックを実装できます。
Q6. Usageリソースの役割は?
リソース間の依存関係を宣言し、使用中のリソースが誤って削除されることを防止します。
Q7. CrossplaneをArgoCDと連携する際に特別な設定は必要ですか?
いいえ。Crossplaneリソースは通常のKubernetesマニフェストなので、ArgoCDがそのままsyncできます。