Crossplane คืออะไร
Crossplane เป็น open source Kubernetes add-on ที่เปลี่ยน Kubernetes cluster ให้เป็น universal control plane สำหรับจัดการ cloud infrastructure ทุกชนิด ใช้ Kubernetes API และ custom resources ในการสร้างและจัดการ cloud resources เช่น databases, storage buckets, VPCs, Kubernetes clusters บน AWS, GCP, Azure และ providers อื่นๆ
หลักการสำคัญของ Crossplane ได้แก่ Infrastructure as Data ประกาศ infrastructure เป็น Kubernetes YAML manifests, Compositions สร้าง abstractions ที่รวม resources หลายตัวเข้าด้วยกัน, Self-Healing Kubernetes reconciliation loop ดูแลให้ infrastructure ตรงกับ desired state, GitOps Ready ใช้กับ ArgoCD หรือ Flux ได้ทันที และ Multi-Cloud จัดการ resources จากหลาย cloud providers ด้วย API เดียว
Crossplane เหมาะสำหรับ platform teams ที่ต้องการสร้าง Internal Developer Platform (IDP) ให้ developers สร้าง infrastructure ได้เองผ่าน self-service API โดยไม่ต้องเรียนรู้ cloud-specific tools
ติดตั้ง Crossplane บน Kubernetes
ขั้นตอนติดตั้ง Crossplane
# === ติดตั้ง Crossplane ===
# 1. Prerequisites
# ===================================
# Kubernetes cluster (1.24+)
# kubectl configured
# Helm 3.x installed
kubectl version --client
helm version
# 2. Install Crossplane with 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-composition-revisions"}' \
--wait
# Verify
kubectl get pods -n crossplane-system
# crossplane-xxx 1/1 Running
# crossplane-rbac-manager-xxx 1/1 Running
# 3. Install Crossplane CLI
# ===================================
curl -sL "https://raw.githubusercontent.com/crossplane/crossplane/master/install.sh" | sh
sudo mv crossplane /usr/local/bin/
crossplane --version
# 4. Install AWS Provider
# ===================================
cat <<'EOF' | kubectl apply -f -
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws
spec:
package: xpkg.upbound.io/upbound/provider-aws-s3:v1.1.0
EOF
# Wait for provider to be healthy
kubectl get providers
kubectl wait provider provider-aws --for=condition=Healthy --timeout=300s
# 5. Configure AWS Credentials
# ===================================
# Create credentials secret
cat > aws-credentials.txt << 'CRED'
[default]
aws_access_key_id = YOUR_ACCESS_KEY
aws_secret_access_key = YOUR_SECRET_KEY
CRED
kubectl create secret generic aws-secret \
-n crossplane-system \
--from-file=creds=./aws-credentials.txt
# Create 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-secret
key: creds
EOF
# 6. Verify Setup
# ===================================
kubectl get providers
kubectl get providerconfigs
kubectl api-resources | grep aws
echo "Crossplane installed and configured"
Compositions และ Composite Resources
สร้าง Compositions สำหรับ infrastructure abstractions
# === Crossplane Compositions ===
# 1. CompositeResourceDefinition (XRD)
# กำหนด API สำหรับ developers
cat <<'EOF' | kubectl apply -f -
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:
engine:
type: string
enum: ["postgres", "mysql"]
default: "postgres"
size:
type: string
enum: ["small", "medium", "large"]
default: "small"
region:
type: string
default: "ap-southeast-1"
storageGB:
type: integer
default: 20
required:
- engine
- size
EOF
# 2. Composition
# กำหนดว่า XDatabase สร้าง resources อะไรบ้าง
cat <<'EOF' | kubectl apply -f -
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: database-aws
labels:
provider: aws
spec:
compositeTypeRef:
apiVersion: platform.example.com/v1alpha1
kind: XDatabase
resources:
- name: rds-instance
base:
apiVersion: rds.aws.upbound.io/v1beta1
kind: Instance
spec:
forProvider:
engine: postgres
engineVersion: "15"
instanceClass: db.t3.micro
allocatedStorage: 20
publiclyAccessible: false
skipFinalSnapshot: true
masterUsername: admin
masterPasswordSecretRef:
namespace: crossplane-system
name: db-password
key: password
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.engine
toFieldPath: spec.forProvider.engine
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.region
toFieldPath: spec.forProvider.region
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.storageGB
toFieldPath: spec.forProvider.allocatedStorage
- 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
- name: security-group
base:
apiVersion: ec2.aws.upbound.io/v1beta1
kind: SecurityGroup
spec:
forProvider:
description: "Database security group"
ingress:
- fromPort: 5432
toPort: 5432
protocol: tcp
cidrBlocks:
- "10.0.0.0/8"
patches:
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.region
toFieldPath: spec.forProvider.region
EOF
# 3. Claim (Developer API)
# Developer สร้าง database ด้วย simple YAML
cat <<'EOF' | kubectl apply -f -
apiVersion: platform.example.com/v1alpha1
kind: Database
metadata:
name: my-app-db
namespace: default
spec:
parameters:
engine: postgres
size: small
region: ap-southeast-1
storageGB: 50
EOF
# 4. Check Status
kubectl get databases
kubectl get xdatabases
kubectl get managed
สร้าง Cloud Infrastructure ด้วย Crossplane
ตัวอย่างการสร้าง infrastructure จริง
#!/usr/bin/env python3
# crossplane_manager.py — Crossplane Infrastructure Manager
import json
import logging
import subprocess
from typing import Dict, List, Optional
from dataclasses import dataclass
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("crossplane")
class CrossplaneManager:
def __init__(self):
self.resources = []
def apply_manifest(self, manifest: Dict):
"""Apply a Kubernetes manifest"""
manifest_json = json.dumps(manifest)
# result = subprocess.run(
# ["kubectl", "apply", "-f", "-"],
# input=manifest_json, capture_output=True, text=True
# )
self.resources.append(manifest)
kind = manifest.get("kind", "Unknown")
name = manifest.get("metadata", {}).get("name", "unnamed")
logger.info(f"Applied: {kind}/{name}")
return {"status": "applied", "kind": kind, "name": name}
def create_database_claim(self, name, namespace="default",
engine="postgres", size="small",
region="ap-southeast-1", storage_gb=20):
claim = {
"apiVersion": "platform.example.com/v1alpha1",
"kind": "Database",
"metadata": {"name": name, "namespace": namespace},
"spec": {
"parameters": {
"engine": engine,
"size": size,
"region": region,
"storageGB": storage_gb,
}
}
}
return self.apply_manifest(claim)
def create_bucket_claim(self, name, namespace="default",
region="ap-southeast-1", versioning=True):
claim = {
"apiVersion": "platform.example.com/v1alpha1",
"kind": "Bucket",
"metadata": {"name": name, "namespace": namespace},
"spec": {
"parameters": {
"region": region,
"versioning": versioning,
}
}
}
return self.apply_manifest(claim)
def create_app_infrastructure(self, app_name, environment="staging"):
"""Create complete infrastructure for an application"""
results = []
# Database
db_size = "small" if environment == "staging" else "medium"
results.append(self.create_database_claim(
f"{app_name}-db-{environment}",
engine="postgres", size=db_size, storage_gb=50
))
# Cache (Redis)
results.append(self.apply_manifest({
"apiVersion": "platform.example.com/v1alpha1",
"kind": "Cache",
"metadata": {"name": f"{app_name}-cache-{environment}"},
"spec": {
"parameters": {
"engine": "redis",
"size": "small" if environment == "staging" else "medium",
}
}
}))
# Storage Bucket
results.append(self.create_bucket_claim(
f"{app_name}-assets-{environment}",
versioning=(environment == "production")
))
return {
"app": app_name,
"environment": environment,
"resources_created": len(results),
"details": results,
}
def get_resource_status(self):
# result = subprocess.run(
# ["kubectl", "get", "managed", "-o", "json"],
# capture_output=True, text=True
# )
return {
"total_resources": len(self.resources),
"resources": [
{
"kind": r["kind"],
"name": r["metadata"]["name"],
"status": "Ready",
}
for r in self.resources
]
}
mgr = CrossplaneManager()
result = mgr.create_app_infrastructure("my-app", "production")
print(json.dumps(result, indent=2))
print(json.dumps(mgr.get_resource_status(), indent=2))
Interview Questions และคำตอบ
คำถามสัมภาษณ์เกี่ยวกับ Crossplane
# === Crossplane Interview Questions ===
# Q1: Crossplane ต่างจาก Terraform อย่างไร?
# ===================================
# Crossplane:
# - Kubernetes-native (uses CRDs and controllers)
# - Continuous reconciliation (self-healing)
# - Uses kubectl / Kubernetes API
# - Compositions = reusable abstractions
# - Built-in RBAC via Kubernetes
# - GitOps-ready (ArgoCD/Flux)
# - Real-time drift detection and correction
#
# Terraform:
# - Standalone tool with HCL language
# - Plan/Apply workflow (not continuous)
# - Uses terraform CLI
# - Modules = reusable components
# - Separate state management
# - Requires wrapper for GitOps
# - Drift detection only on terraform plan
# Q2: Composition คืออะไรและทำไมต้องใช้?
# ===================================
# Composition คือ template ที่กำหนดว่าเมื่อ user สร้าง
# Composite Resource (XR) จะต้องสร้าง managed resources อะไรบ้าง
#
# ใช้เพราะ:
# 1. Abstraction: ซ่อน complexity จาก developers
# 2. Standardization: enforce standards (security, naming, tags)
# 3. Self-service: developers สร้าง infra เองได้
# 4. Multi-cloud: เปลี่ยน provider โดยไม่ต้องเปลี่ยน Claim
# Q3: XRD, Composition, XR, Claim ต่างกันอย่างไร?
# ===================================
# XRD (CompositeResourceDefinition):
# - กำหนด API schema (เหมือน CRD)
# - กำหนดว่า user ส่ง parameters อะไรได้บ้าง
#
# Composition:
# - กำหนดว่า XR สร้าง resources อะไร
# - มี patches สำหรับ map parameters ไป resources
# - สามารถมีหลาย Compositions ต่อ 1 XRD (multi-cloud)
#
# XR (Composite Resource):
# - Instance ของ XRD ที่สร้างจริง
# - Cluster-scoped
# - Owner ของ managed resources
#
# Claim:
# - Namespace-scoped wrapper ของ XR
# - สำหรับ developers (ไม่ต้องเห็น cluster-level details)
# Q4: Crossplane reconciliation loop ทำงานอย่างไร?
# ===================================
# 1. User creates Claim/XR
# 2. Composition controller creates managed resources
# 3. Provider controller calls cloud API to create resources
# 4. Controller continuously checks actual state vs desired state
# 5. If drift detected, controller corrects it automatically
# 6. Status propagated back to XR and Claim
#
# Interval: default 1 minute (configurable)
# This is why Crossplane provides "self-healing" infrastructure
# Q5: วิธี handle secrets ใน Crossplane?
# ===================================
# 1. ConnectionDetails: Crossplane propagates secrets from
# managed resources to Kubernetes secrets automatically
# 2. External Secrets Operator: integrate with Vault, AWS SM
# 3. ProviderConfig credentials: stored as K8s secrets
# 4. IRSA/Workload Identity: cloud-native auth (no static keys)
# Q6: Crossplane กับ ArgoCD ใช้ร่วมกันอย่างไร?
# ===================================
# ArgoCD manages Crossplane manifests in Git:
# - XRDs and Compositions in platform-team repo
# - Claims in application-team repos
# - ArgoCD syncs Claims to cluster
# - Crossplane creates cloud resources
# - GitOps workflow for infrastructure changes
echo "Interview preparation complete"
Best Practices และ Production Tips
แนวปฏิบัติสำหรับ production
# === Crossplane Production Best Practices ===
# 1. Composition Design Patterns
# ===================================
# a) Keep Compositions simple (< 10 resources)
# b) Use sensible defaults in XRD schema
# c) Version your XRDs (v1alpha1 -> v1beta1 -> v1)
# d) Use labels and annotations for tracking
# e) Test Compositions in staging before production
# 2. Security Best Practices
# ===================================
# a) Use IRSA/Workload Identity instead of static credentials
# b) Least privilege for provider service accounts
# c) Namespace-scoped Claims (not cluster-scoped XRs) for developers
# d) Use Kubernetes RBAC to control who can create Claims
# e) Encrypt sensitive ConnectionDetails
# Example RBAC for developers
cat <<'EOF'
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: database-consumer
rules:
- apiGroups: ["platform.example.com"]
resources: ["databases"]
verbs: ["get", "list", "create", "update", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: dev-team-databases
subjects:
- kind: Group
name: dev-team
roleRef:
kind: ClusterRole
name: database-consumer
apiGroup: rbac.authorization.k8s.io
EOF
# 3. Monitoring and Alerting
# ===================================
# Prometheus metrics:
# crossplane_managed_resource_exists{kind="Instance"}
# crossplane_managed_resource_ready{kind="Instance"}
# crossplane_composite_resource_ready{kind="XDatabase"}
#
# Alert rules:
# - Resource not ready for > 10 minutes
# - Provider unhealthy
# - Composition error rate > 0
# 4. Disaster Recovery
# ===================================
# a) Backup Crossplane CRDs and custom resources
# b) Store Compositions and XRDs in Git (GitOps)
# c) Claims stored in application repos
# d) Cloud resources exist independently of Crossplane
# e) deletionPolicy: Orphan prevents resource deletion
# 5. Performance Tuning
# ===================================
# a) Increase provider replicas for many resources
# b) Set appropriate pollInterval (default 1m)
# c) Use providerConfigRef to distribute load
# d) Monitor controller memory usage
# Tune provider resources
cat <<'EOF'
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws
spec:
package: xpkg.upbound.io/upbound/provider-aws-s3:v1.1.0
controllerConfigRef:
name: aws-config
---
apiVersion: pkg.crossplane.io/v1alpha1
kind: ControllerConfig
metadata:
name: aws-config
spec:
resources:
limits:
memory: 512Mi
cpu: 500m
requests:
memory: 256Mi
cpu: 100m
args:
- --poll=30s
- --max-reconcile-rate=10
EOF
echo "Best practices documented"
FAQ คำถามที่พบบ่อย
Q: Crossplane เหมาะกับองค์กรแบบไหน?
A: เหมาะกับองค์กรที่ใช้ Kubernetes เป็นหลักอยู่แล้ว, ต้องการสร้าง Internal Developer Platform (IDP) ให้ developers self-service infrastructure, ใช้ multi-cloud หรือ hybrid cloud, ต้องการ GitOps workflow สำหรับ infrastructure และ ต้องการ continuous reconciliation (self-healing) ไม่เหมาะกับองค์กรที่ไม่ใช้ Kubernetes หรือ team เล็กที่ Terraform เพียงพอ
Q: Crossplane กับ Pulumi ต่างกันอย่างไร?
A: Crossplane เป็น Kubernetes-native ใช้ YAML declarative approach ทำงานเป็น controller ใน cluster มี continuous reconciliation เหมาะสำหรับ platform teams ที่สร้าง abstractions Pulumi ใช้ general-purpose programming languages (Python, Go, TypeScript) มี flexibility สูงกว่า ไม่ต้องใช้ Kubernetes เหมาะสำหรับ teams ที่ต้องการ programmatic control ใช้ Crossplane ถ้า Kubernetes-centric ใช้ Pulumi ถ้าต้องการ code-first approach
Q: Composition patches ทำงานอย่างไร?
A: Patches ใช้ map ค่าจาก Composite Resource (XR) ไปยัง managed resources มีหลายประเภท FromCompositeFieldPath copy ค่าจาก XR ไป resource, ToCompositeFieldPath copy ค่าจาก resource กลับไป XR, CombineFromComposite รวมหลายค่าเข้าด้วยกัน (เช่น naming), transforms แปลงค่า (map, math, string) เช่น map size small/medium/large ไปเป็น instance class patches ทำให้ Compositions flexible และ reusable
Q: จะ migrate จาก Terraform ไป Crossplane อย่างไร?
A: ทำ gradual migration ไม่ต้องเปลี่ยนทั้งหมดในครั้งเดียว เริ่มจาก import existing resources ด้วย crossplane managed resource annotations, สร้าง Compositions สำหรับ new resources, ใช้ Terraform สำหรับ existing resources และ Crossplane สำหรับ new ones, ค่อยๆ migrate resources เมื่อ team พร้อม ใช้ Upbound marketplace สำหรับ pre-built providers และ configurations เพื่อเร่ง migration
