Crossplane Composition

Crossplane Composition Low Code No Code Cloud Infrastructure Self-service XRD Composition Functions Platform API Kubernetes GitOps Enterprise

FeatureCrossplaneTerraformPulumi
ParadigmDeclarative (K8s API)Declarative (HCL)Imperative (Code)
ReconciliationContinuous (Controller)On-demand (apply)On-demand (up)
Self-serviceXRD + Claim (built-in)Module + WrapperComponent + Automation
GitOpsNative (ArgoCD/Flux)Atlantis/TF CloudPulumi Operator
StateKubernetes etcdState file (S3/Cloud)Pulumi Cloud/S3
Learning Curveสูง (K8s + Cloud)กลาง (HCL)กลาง (Programming)

XRD and Composition

# === Crossplane XRD and Composition ===

# CompositeResourceDefinition (XRD)
# apiVersion: apiextensions.crossplane.io/v1
# kind: CompositeResourceDefinition
# metadata:
# name: databases.platform.example.com
# spec:
# group: platform.example.com
# names:
# kind: Database
# plural: databases
# claimNames:
# kind: DatabaseClaim
# plural: databaseclaims
# versions:
# - name: v1alpha1
# served: true
# referenceable: true
# schema:
# openAPIV3Schema:
# type: object
# properties:
# spec:
# type: object
# properties:
# engine:
# type: string
# enum: [postgres, mysql]
# size:
# type: string
# enum: [small, medium, large]
# region:
# type: string
# default: ap-southeast-1
# required: [engine, size]

# Composition
# apiVersion: apiextensions.crossplane.io/v1
# kind: Composition
# metadata:
# name: database-aws
# spec:
# compositeTypeRef:
# apiVersion: platform.example.com/v1alpha1
# kind: Database
# resources:
# - name: rds-instance
# base:
# apiVersion: rds.aws.upbound.io/v1beta1
# kind: Instance
# spec:
# forProvider:
# instanceClass: db.t3.micro
# allocatedStorage: 20
# engine: postgres
# patches:
# - fromFieldPath: spec.engine
# toFieldPath: spec.forProvider.engine
# - fromFieldPath: spec.size
# toFieldPath: spec.forProvider.instanceClass
# transforms:
# - type: map
# map:
# small: db.t3.micro
# medium: db.t3.medium
# large: db.r5.large

from dataclasses import dataclass

@dataclass
class PlatformAPI:
 resource: str
 inputs: str
 creates: str
 claim_lines: int
 cloud_resources: int

apis = [
 PlatformAPI("Database", "engine, size, region",
 "RDS + Security Group + Subnet Group + Secret",
 8, 4),
 PlatformAPI("Cache", "engine, size, replicas",
 "ElastiCache + Security Group + Parameter Group",
 7, 3),
 PlatformAPI("Bucket", "name, versioning, encryption",
 "S3 Bucket + Policy + Lifecycle Rule",
 6, 3),
 PlatformAPI("Network", "cidr, azs, nat_gateway",
 "VPC + Subnets + IGW + NAT + Route Tables",
 8, 8),
 PlatformAPI("Cluster", "version, node_size, node_count",
 "EKS + Node Group + IAM Roles + Add-ons",
 9, 6),
]

print("=== Platform APIs ===")
for a in apis:
 print(f" [{a.resource}] Inputs: {a.inputs}")
 print(f" Creates: {a.creates}")
 print(f" Claim: {a.claim_lines} lines YAML | Cloud: {a.cloud_resources} resources")

Self-service Portal

# === Developer Self-service ===

# Developer Claim (what devs write — just 8 lines!)
# apiVersion: platform.example.com/v1alpha1
# kind: DatabaseClaim
# metadata:
# name: my-app-db
# namespace: team-alpha
# spec:
# engine: postgres
# size: medium
# region: ap-southeast-1

# Backstage Integration
# - Backstage Software Template creates Claim YAML
# - Developer fills form in UI (no YAML needed)
# - Template commits to Git repository
# - ArgoCD detects change, applies to cluster
# - Crossplane creates all cloud resources
# - Connection details stored in Kubernetes Secret

# GitOps Workflow
# 1. Developer opens PR with Claim YAML
# 2. CI validates schema, cost estimation
# 3. Reviewer approves PR
# 4. Merge triggers ArgoCD sync
# 5. Crossplane creates resources (~2-10 minutes)
# 6. Secret with connection details created
# 7. App reads Secret, connects to database

@dataclass
class SelfServiceFlow:
 step: int
 actor: str
 action: str
 tool: str
 duration: str

flow = [
 SelfServiceFlow(1, "Developer", "Select resource type and size in portal",
 "Backstage / Port UI", "30 seconds"),
 SelfServiceFlow(2, "CI/CD", "Validate schema, estimate cost, lint",
 "GitHub Actions + OPA", "1 minute"),
 SelfServiceFlow(3, "Reviewer", "Approve PR (optional for non-prod)",
 "GitHub PR Review", "0-30 minutes"),
 SelfServiceFlow(4, "ArgoCD", "Sync Claim to Kubernetes cluster",
 "ArgoCD", "30 seconds"),
 SelfServiceFlow(5, "Crossplane", "Create cloud resources",
 "Crossplane Controller", "2-10 minutes"),
 SelfServiceFlow(6, "Crossplane", "Store connection in Secret",
 "Crossplane Connection Secret", "Automatic"),
 SelfServiceFlow(7, "Developer", "Use resource via Secret reference",
 "Kubernetes Secret Mount / Env", "Immediate"),
]

print("Self-service Flow:")
for s in flow:
 print(f" Step {s.step}: [{s.actor}] {s.action}")
 print(f" Tool: {s.tool} | Duration: {s.duration}")

Production Setup

# === Production Crossplane ===

# Install Crossplane
# helm repo add crossplane-stable https://charts.crossplane.io/stable
# helm install crossplane crossplane-stable/crossplane \
# --namespace crossplane-system --create-namespace

# Install AWS Provider
# apiVersion: pkg.crossplane.io/v1
# kind: Provider
# metadata:
# name: provider-aws
# spec:
# package: xpkg.upbound.io/upbound/provider-family-aws:v1.0.0

# ProviderConfig with IRSA (EKS)
# apiVersion: aws.upbound.io/v1beta1
# kind: ProviderConfig
# metadata:
# name: default
# spec:
# credentials:
# source: IRSA

@dataclass
class ProductionCheck:
 category: str
 item: str
 config: str
 importance: str

checks = [
 ProductionCheck("Security", "IRSA for AWS credentials",
 "No static keys, use IAM Roles for Service Accounts",
 "Critical"),
 ProductionCheck("Security", "RBAC for Claims",
 "Namespace-scoped Claims, restrict who can create what",
 "Critical"),
 ProductionCheck("Reliability", "HA Crossplane deployment",
 "replicas: 2, PDB, resource limits",
 "High"),
 ProductionCheck("Observability", "Crossplane metrics",
 "Prometheus ServiceMonitor for controller metrics",
 "High"),
 ProductionCheck("Cost", "Cost estimation in CI",
 "Infracost or custom OPA policy for cost limits",
 "Medium"),
 ProductionCheck("Governance", "OPA/Kyverno policies",
 "Enforce naming, tagging, size limits",
 "High"),
 ProductionCheck("GitOps", "ArgoCD Application per team",
 "Separate ArgoCD App per namespace/team",
 "High"),
 ProductionCheck("Backup", "XRD and Composition in Git",
 "Version control all platform definitions",
 "Critical"),
]

print("=== Production Checklist ===")
for c in checks:
 print(f" [{c.importance}] {c.category}: {c.item}")
 print(f" Config: {c.config}")

เคล็ดลับ

  • XRD: ออกแบบ XRD Schema ให้เรียบง่าย Developer ไม่ต้องรู้ Cloud Detail
  • Patch: ใช้ Transforms Map แปลงค่าจาก Enum เป็น Cloud-specific Config
  • GitOps: ใช้ ArgoCD Sync Claim จาก Git ไม่ให้ kubectl apply ตรง
  • RBAC: จำกัด Claim ตาม Namespace ให้แต่ละทีมเห็นเฉพาะของตัวเอง
  • Cost: ใส่ Cost Estimation ใน CI ก่อน Merge PR

Crossplane คืออะไร

Open Source Cloud Infrastructure Kubernetes API CRD AWS GCP Azure Platform Team Developer Self-service Terraform GitOps ArgoCD Flux Provider