SiamCafe · Blog
Crossplane Composition SaaS Architecture — สร้าง
บทความ

Crossplane Composition SaaS Architecture — สร้าง

เผยแพร่ 28 พฤษภาคม 2569

Crossplane SaaS Architecture

Crossplane Composition SaaS Cloud Native Control Plane Kubernetes XRD Provider Self-Service Platform Multi-Cloud GitOps Reconciliation Tenant Infrastructure

ToolApproachDrift DetectionSelf-Serviceเหมาะกับ
CrossplaneK8s ReconcileอัตโนมัติดีมากPlatform Engineering
TerraformCLI Plan/Applyไม่มี (ต้อง Manual)ไม่มีIaC ทั่วไป
PulumiCode (Python/TS)ไม่มีไม่มีDeveloper IaC
AWS CDKCode (TS/Python)ไม่มีไม่มีAWS Only

XRD และ Composition

=== Crossplane XRD & Composition ===

CompositeResourceDefinition (XRD)

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:

engine:

type: string

enum: [postgres, mysql]

size:

type: string

enum: [small, medium, large]

region:

type: string

default: ap-southeast-1

Composition — What gets created

apiVersion: apiextensions.crossplane.io/v1

kind: Composition

metadata:

name: database-aws

spec:

compositeTypeRef:

apiVersion: platform.example.com/v1alpha1

kind: XDatabase

resources:

  • name: vpc

base:

apiVersion: ec2.aws.upbound.io/v1beta1

kind: VPC

spec:

forProvider:

cidrBlock: 10.0.0.0/16

enableDnsSupport: true

  • name: subnet-a

base:

apiVersion: ec2.aws.upbound.io/v1beta1

kind: Subnet

spec:

forProvider:

cidrBlock: 10.0.1.0/24

  • name: rds

base:

apiVersion: rds.aws.upbound.io/v1beta1

kind: Instance

spec:

forProvider:

engine: postgres

instanceClass: db.t3.medium

allocatedStorage: 20

from dataclasses import dataclass

from typing import List

@dataclass

class CompositionResource:

name: str

kind: str

provider: str

status: str

resources_per_tenant = [

CompositionResource("VPC", "ec2.VPC", "AWS", "Ready"),

CompositionResource("Subnet x2", "ec2.Subnet", "AWS", "Ready"),

CompositionResource("Security Group", "ec2.SecurityGroup", "AWS", "Ready"),

CompositionResource("RDS PostgreSQL", "rds.Instance", "AWS", "Ready"),

CompositionResource("ElastiCache Redis", "elasticache.Cluster", "AWS", "Ready"),

CompositionResource("S3 Bucket", "s3.Bucket", "AWS", "Ready"),

]

print("=== Resources per Tenant (Composition) ===")

for r in resources_per_tenant:

print(f" [{r.status}] {r.name} ({r.kind}) — {r.provider}")

Self-Service Platform

=== Developer Self-Service ===

Developer creates a simple Claim

apiVersion: platform.example.com/v1alpha1

kind: Database

metadata:

name: tenant-acme-db

namespace: tenant-acme

spec:

engine: postgres

size: medium

region: ap-southeast-1

kubectl apply -f database-claim.yaml

kubectl get databases -n tenant-acme

kubectl describe database tenant-acme-db -n tenant-acme

SaaS Tenant Onboarding Script

#!/bin/bash

TENANT=$1

kubectl create namespace tenant-$TENANT

cat <<EOF | kubectl apply -f -

apiVersion: platform.example.com/v1alpha1

kind: Database

metadata:

name: -db

namespace: tenant-

spec:

engine: postgres

size: small

region: ap-southeast-1

---

apiVersion: platform.example.com/v1alpha1

kind: Cache

metadata:

name: -cache

namespace: tenant-

spec:

engine: redis

size: small

EOF

@dataclass

class Tenant:

name: str

plan: str

db_size: str

cache: bool

region: str

status: str

mrr: float

tenants = [

Tenant("acme-corp", "Enterprise", "large", True, "ap-southeast-1", "Active", 29990),

Tenant("startup-xyz", "Pro", "medium", True, "ap-southeast-1", "Active", 9990),

Tenant("shop-abc", "Basic", "small", False, "ap-southeast-1", "Active", 2990),

Tenant("agency-def", "Pro", "medium", True, "us-east-1", "Active", 9990),

Tenant("trial-ghi", "Trial", "small", False, "ap-southeast-1", "Trial", 0),

]

print("\n=== SaaS Tenants ===")

total_mrr = 0

for t in tenants:

total_mrr += t.mrr

cache_str = "Redis" if t.cache else "—"

print(f" [{t.status}] {t.name} ({t.plan})")

print(f" DB: {t.db_size} | Cache: {cache_str} | Region: {t.region} | MRR: {t.mrr:,.0f}")

print(f"\n Total MRR: {total_mrr:,.0f} บาท")

Multi-Cloud และ GitOps

=== Multi-Cloud & GitOps ===

ArgoCD + Crossplane GitOps

Git Repo Structure:

infrastructure/

├── base/

│ ├── xrd-database.yaml

│ ├── composition-aws.yaml

│ └── composition-gcp.yaml

├── tenants/

│ ├── acme-corp/

│ │ ├── database.yaml

│ │ └── cache.yaml

│ └── startup-xyz/

│ ├── database.yaml

│ └── cache.yaml

└── providers/

├── provider-aws.yaml

└── provider-gcp.yaml

ArgoCD Application

apiVersion: argoproj.io/v1alpha1

kind: Application

metadata:

name: crossplane-tenants

spec:

source:

repoURL: https://github.com/org/infrastructure

path: tenants

destination:

server: https://kubernetes.default.svc

syncPolicy:

automated:

prune: true

selfHeal: true

platform_metrics = {

"Total Tenants": "45 active + 12 trial",

"Cloud Resources": "270 managed resources",

"Drift Detected (30d)": "3 (auto-corrected)",

"Avg Provisioning Time": "4.5 minutes",

"Failed Provisions (30d)": "1 (quota limit)",

"Multi-region": "3 regions (AP, US, EU)",

"Monthly Cloud Cost": "$8,500",

"Total MRR": "52,960 บาท",

}

print("Platform Engineering Dashboard:")

for k, v in platform_metrics.items():

print(f" {k}: {v}")

Composition Selection by Region

compositions = {

"ap-southeast-1": "composition-aws-ap",

"us-east-1": "composition-aws-us",

"eu-west-1": "composition-aws-eu",

"asia-east1": "composition-gcp-asia",

}

print(f"\n\nComposition by Region:")

for region, comp in compositions.items():

print(f" [{region}]: {comp}")

เคล็ดลับ

  • XRD: ออกแบบ XRD ง่ายๆ สำหรับ Developer ซ่อน Cloud Complexity
  • Composition: ฝัง Security Best Practices ใน Composition
  • GitOps: ใช้ ArgoCD + Crossplane สำหรับ Full GitOps
  • Quota: ตั้ง Resource Quota ต่อ Tenant ป้องกัน Overuse
  • Monitor: Monitor Crossplane Resources และ Drift Detection

การนำไปใช้งานจริงในองค์กร

สำหรับองค์กรขนาดกลางถึงใหญ่ แนะนำให้ใช้หลัก Three-Tier Architecture คือ Core Layer ที่เป็นแกนกลางของระบบ Distribution Layer ที่ทำหน้าที่กระจาย Traffic และ Access Layer ที่เชื่อมต่อกับผู้ใช้โดยตรง การแบ่ง Layer ชัดเจนช่วยให้การ Troubleshoot ง่ายขึ้นและสามารถ Scale ระบบได้ตามความต้องการ

เรื่อง Network Security ก็สำคัญไม่แพ้กัน ควรติดตั้ง Next-Generation Firewall ที่สามารถ Deep Packet Inspection ได้ ใช้ Network Segmentation แยก VLAN สำหรับแต่ละแผนก ติดตั้ง IDS/IPS เพื่อตรวจจับการโจมตี และทำ Regular Security Audit อย่างน้อยปีละ 2 ครั้ง

เปรียบเทียบข้อดีและข้อเสีย

ข้อดีข้อเสีย
ประสิทธิภาพสูง ทำงานได้เร็วและแม่นยำ ลดเวลาทำงานซ้ำซ้อนต้องใช้เวลาเรียนรู้เบื้องต้นพอสมควร มี Learning Curve สูง
มี Community ขนาดใหญ่ มีคนช่วยเหลือและแหล่งเรียนรู้มากมายบางฟีเจอร์อาจยังไม่เสถียร หรือมีการเปลี่ยนแปลงบ่อยในเวอร์ชันใหม่
รองรับ Integration กับเครื่องมือและบริการอื่นได้หลากหลายต้นทุนอาจสูงสำหรับ Enterprise License หรือ Cloud Service
เป็น Open Source หรือมีเวอร์ชันฟรีให้เริ่มต้นใช้งานต้องการ Hardware หรือ Infrastructure ที่เพียงพอ

จากตารางเปรียบเทียบจะเห็นว่าข้อดีมีมากกว่าข้อเสียอย่างชัดเจน โดยเฉพาะในแง่ของประสิทธิภาพและความสามารถในการ Scale สำหรับข้อเสียส่วนใหญ่สามารถแก้ไขได้ด้วยการเรียนรู้อย่างเป็นระบบและวางแผนทรัพยากรให้เหมาะสม

Crossplane คืออะไร

Cloud Native Control Plane Kubernetes API YAML AWS GCP Azure GitOps Reconciliation Self-Service Developer สร้าง Infrastructure เอง

Composition คืออะไร

รวมหลาย Resources เป็น Abstract Resource เดียว VPC Subnet RDS เป็น Database Claim Developer ของ่าย Platform กำหนด Best Practices

Crossplane กับ Terraform ต่างกันอย่างไร

Crossplane K8s Reconciliation Drift Auto Self-healing GitOps Self-Service Terraform CLI Plan Apply Manual ไม่มี Drift ใช้ร่วมกันได้

SaaS Architecture ใช้ Crossplane อย่างไร

Tenant แยก Infrastructure Composition สร้าง DB Cache Queue ต่อ Tenant Onboarding Claim เดียว Offboarding ลบ Claim Scaling ปรับ Spec

สรุป

Crossplane Composition SaaS XRD Claim Self-Service Platform Kubernetes Multi-Cloud GitOps ArgoCD Tenant Onboarding Offboarding Scaling Drift Detection Reconciliation