ai

Crossplane Composition Developer Experience DX

Crossplane Composition Developer Experience DX

Crossplane Composition Developer Experience DX คืออะไร

Crossplane Composition Developer Experience DX

Crossplane เป็น open source Kubernetes add-on ที่ช่วยจัดการ cloud infrastructure ผ่าน Kubernetes API ด้วย Compositions developers สร้าง self-service platform สำหรับ provision resources ข้าม cloud providers Developer Experience (DX) คือการออกแบบ platform ให้ developers ใช้งานง่าย ลด cognitive load และเพิ่ม productivity การรวมสองแนวคิดนี้ช่วยสร้าง Internal Developer Platform (IDP) ที่ abstract ความซับซ้อนของ infrastructure ให้ developers focus ที่ application code โดยขอ resources ผ่าน simple YAML claims

Crossplane Composition Basics

# composition_basics.py — Crossplane Composition fundamentals

import json



class CompositionBasics:

    CONCEPTS = {

        "composite_resource_def": {

            "name": "CompositeResourceDefinition (XRD)",

            "description": "กำหนด schema ของ custom resource ที่ developers จะใช้",

            "analogy": "เหมือน class definition — กำหนดว่า resource มี fields อะไรบ้าง",

        },

        "composition": {

            "name": "Composition",

            "description": "กำหนดว่า XRD จะสร้าง cloud resources อะไรบ้าง (implementation)",

            "analogy": "เหมือน class implementation — map fields ไปเป็น actual resources",

        },

        "claim": {

            "name": "Claim (XRC)",

            "description": "สิ่งที่ developers ใช้ขอ resources — simple YAML",

            "analogy": "เหมือน new ClassName() — สร้าง instance จาก definition",

        },

        "provider": {

            "name": "Provider",

            "description": "Plugin สำหรับ cloud provider (AWS, GCP, Azure)",

            "examples": "provider-aws, provider-gcp, provider-azure, provider-helm",

        },

    }



    XRD_EXAMPLE = """

# xrd-database.yaml — CompositeResourceDefinition

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:

                size:

                  type: string

                  enum: [small, medium, large]

                  description: "Database size"

                engine:

                  type: string

                  enum: [postgres, mysql]

                  default: postgres

              required: [size]

"""



    CLAIM_EXAMPLE = """

# claim-database.yaml — What developers write (simple!)

apiVersion: platform.example.com/v1alpha1

kind: Database

metadata:

  name: my-app-db

  namespace: team-alpha

spec:

  size: medium

  engine: postgres

"""



    def show_concepts(self):

        print("=== Crossplane Concepts ===\n")

        for key, concept in self.CONCEPTS.items():

            print(f"[{concept['name']}]")

            print(f"  {concept['description']}")

            print()



    def show_xrd(self):

        print("=== XRD Example ===")

        print(self.XRD_EXAMPLE[:500])



    def show_claim(self):

        print(f"\n=== Developer Claim (Simple!) ===")

        print(self.CLAIM_EXAMPLE)



basics = CompositionBasics()

basics.show_concepts()

basics.show_claim()

Developer Experience Design

# dx_design.py — Developer Experience design principles

import json



class DXDesign:

    PRINCIPLES = {

        "simplicity": {

            "name": "Simplicity (ง่าย)",

            "description": "Developer ไม่ต้องรู้ implementation details — แค่ระบุ size, engine, region",

            "bad": "Developer ต้องเขียน 200 lines YAML สำหรับ RDS + VPC + Security Group",

            "good": "Developer เขียน 10 lines YAML claim → platform สร้างทุกอย่างให้",

        },

        "guardrails": {

            "name": "Guardrails (ราวกั้น)",

            "description": "จำกัด options ที่ developers เลือกได้ ป้องกันความผิดพลาด",

            "bad": "Developer เลือก instance type อะไรก็ได้ → เลือก x2idn.24xlarge ($10/hr)",

            "good": "enum: [small, medium, large] → platform map ไปเป็น instance type ที่เหมาะสม",

        },

        "self_service": {

            "name": "Self-Service (บริการตัวเอง)",

            "description": "Developer ขอ resources ได้เองทันที ไม่ต้องเปิด ticket รอ ops",

            "bad": "เปิด JIRA ticket → รอ ops 2-3 วัน → ได้ database",

            "good": "kubectl apply -f claim.yaml → ได้ database ใน 5-10 นาที",

        },

        "defaults": {

            "name": "Sensible Defaults (ค่า default ดี)",

            "description": "ทุก field มี default ที่เหมาะสม — developer ระบุแค่สิ่งที่จำเป็น",

            "bad": "ต้องระบุ 30+ fields ทุกตัว",

            "good": "ระบุแค่ name + size → อย่างอื่น platform จัดการให้",

        },

        "discoverability": {

            "name": "Discoverability (ค้นหาง่าย)",

            "description": "Developer รู้ว่ามี resources อะไรใช้ได้ และใช้อย่างไร",

            "tools": "kubectl explain, API docs, Backstage catalog, CLI tools",

        },

    }



    def show_principles(self):

        print("=== DX Design Principles ===\n")

        for key, p in self.PRINCIPLES.items():

            print(f"[{p['name']}]")

            print(f"  {p['description']}")

            if 'good' in p:

                print(f"  Good: {p['good']}")

            print()



    def dx_comparison(self):

        print("=== Before vs After Crossplane ===")

        print(f"\n  Before (Manual):")

        print(f"    1. Developer เปิด JIRA ticket")

        print(f"    2. Ops review + approve (1-2 days)")

        print(f"    3. Ops สร้าง resources manually/Terraform (1 day)")

        print(f"    4. Ops ส่ง credentials กลับ (1 day)")

        print(f"    Total: 2-5 days")

        print(f"\n  After (Crossplane Self-Service):")

        print(f"    1. Developer: kubectl apply -f claim.yaml")

        print(f"    2. Crossplane provisions all resources")

        print(f"    3. Credentials auto-injected as Secret")

        print(f"    Total: 5-15 minutes")



dx = DXDesign()

dx.show_principles()

dx.dx_comparison()

Composition Implementation

Crossplane Composition Developer Experience DX
# composition_impl.py — Composition implementation

import json



class CompositionImpl:

    COMPOSITION = """

# composition-database.yaml — Full Composition

apiVersion: apiextensions.crossplane.io/v1

kind: Composition

metadata:

  name: database-aws

  labels:

    provider: aws

spec:

  compositeTypeRef:

    apiVersion: platform.example.com/v1alpha1

    kind: XDatabase

  

  resources:

    # 1. RDS Instance

    - name: rds

      base:

        apiVersion: rds.aws.upbound.io/v1beta1

        kind: Instance

        spec:

          forProvider:

            engine: postgres

            engineVersion: "15"

            allocatedStorage: 20

            instanceClass: db.t3.medium

            publiclyAccessible: false

            skipFinalSnapshot: true

      patches:

        # Map 'size' to instance class

        - type: FromCompositeFieldPath

          fromFieldPath: spec.size

          toFieldPath: spec.forProvider.instanceClass

          transforms:

            - type: map

              map:

                small: db.t3.micro

                medium: db.t3.medium

                large: db.r6g.large

        # Map engine

        - type: FromCompositeFieldPath

          fromFieldPath: spec.engine

          toFieldPath: spec.forProvider.engine

    

    # 2. Security Group

    - name: sg

      base:

        apiVersion: ec2.aws.upbound.io/v1beta1

        kind: SecurityGroup

        spec:

          forProvider:

            description: "Database security group"

    

    # 3. Connection Secret

    - name: connection-secret

      connectionDetails:

        - name: host

          fromFieldPath: status.atProvider.endpoint

        - name: port

          value: "5432"

        - name: username

          fromFieldPath: spec.forProvider.username

"""



    SIZE_MAPPING = {

        "small": {"instance": "db.t3.micro", "storage": "20GB", "cost": "~$15/month"},

        "medium": {"instance": "db.t3.medium", "storage": "50GB", "cost": "~$50/month"},

        "large": {"instance": "db.r6g.large", "storage": "100GB", "cost": "~$150/month"},

    }



    def show_composition(self):

        print("=== Composition YAML ===")

        print(self.COMPOSITION[:600])



    def show_mapping(self):

        print(f"\n=== Size Mapping ===")

        for size, details in self.SIZE_MAPPING.items():

            print(f"  [{size}] → {details['instance']} | {details['storage']} | {details['cost']}")



impl = CompositionImpl()

impl.show_composition()

impl.show_mapping()

Platform Engineering Tools

# platform_tools.py — Platform engineering tooling

import json

import random



class PlatformTools:

    TOOLS = {

        "backstage": {

            "name": "Backstage (Spotify)",

            "description": "Developer portal — catalog, templates, docs, plugins",

            "integration": "Backstage templates สร้าง Crossplane claims อัตโนมัติ",

        },

        "port": {

            "name": "Port (getport.io)",

            "description": "Internal developer portal — self-service UI",

            "integration": "Port actions trigger Crossplane claim creation",

        },

        "argocd": {

            "name": "Argo CD",

            "description": "GitOps deployment — sync claims จาก Git repo",

            "integration": "Developer push claim YAML → Argo CD apply → Crossplane provisions",

        },

        "crossplane_cli": {

            "name": "Crossplane CLI (crank)",

            "description": "CLI สำหรับ build, push, install Crossplane packages",

            "integration": "crank build, crank push สำหรับ composition packages",

        },

    }



    AUTOMATION = """

# platform_automation.py — Platform automation script

import subprocess

import yaml

import json



class PlatformAutomation:

    def __init__(self):

        self.namespace = "platform-system"

    

    def create_claim(self, name, kind, spec):

        claim = {

            "apiVersion": "platform.example.com/v1alpha1",

            "kind": kind,

            "metadata": {"name": name, "namespace": "default"},

            "spec": spec,

        }

        yaml_str = yaml.dump(claim)

        result = subprocess.run(

            ["kubectl", "apply", "-f", "-"],

            input=yaml_str, capture_output=True, text=True,

        )

        return result.returncode == 0

    

    def get_status(self, name, kind):

        result = subprocess.run(

            ["kubectl", "get", kind.lower(), name, "-o", "json"],

            capture_output=True, text=True,

        )

        if result.returncode == 0:

            data = json.loads(result.stdout)

            conditions = data.get("status", {}).get("conditions", [])

            ready = any(c["type"] == "Ready" and c["status"] == "True" for c in conditions)

            return {"name": name, "ready": ready, "conditions": conditions}

        return None

    

    def list_claims(self):

        result = subprocess.run(

            ["kubectl", "get", "databases, caches, buckets", "-A", "-o", "json"],

            capture_output=True, text=True,

        )

        return json.loads(result.stdout) if result.returncode == 0 else None



# Usage

platform = PlatformAutomation()

platform.create_claim("my-db", "Database", {"size": "medium", "engine": "postgres"})

"""



    def show_tools(self):

        print("=== Platform Engineering Tools ===\n")

        for key, tool in self.TOOLS.items():

            print(f"[{tool['name']}]")

            print(f"  {tool['description']}")

            print(f"  Integration: {tool['integration']}")

            print()



    def show_automation(self):

        print("=== Automation Script ===")

        print(self.AUTOMATION[:500])



    def platform_dashboard(self):

        print(f"\n=== Platform Dashboard ===")

        resources = [

            {"name": "app-db", "kind": "Database", "team": "alpha", "status": "Ready", "age": f"{random.randint(1, 30)}d"},

            {"name": "cache-1", "kind": "Cache", "team": "beta", "status": "Ready", "age": f"{random.randint(1, 20)}d"},

            {"name": "logs-bucket", "kind": "Bucket", "team": "platform", "status": "Ready", "age": f"{random.randint(5, 60)}d"},

            {"name": "new-db", "kind": "Database", "team": "gamma", "status": "Provisioning", "age": "2m"},

        ]

        for r in resources:

            icon = "OK" if r["status"] == "Ready" else "..."

            print(f"  [{icon:>3}] {r['name']:<15} {r['kind']:<10} Team: {r['team']:<10} Age: {r['age']}")



tools = PlatformTools()

tools.show_tools()

tools.platform_dashboard()

Testing & Validation

# testing.py — Testing Crossplane compositions

import json



class CompositionTesting:

    STRATEGIES = {

        "unit": {

            "name": "Unit Tests (crossplane-contrib/xrender)",

            "description": "ทดสอบ Composition rendering — input claim → expected resources",

            "tool": "crossplane beta render, kuttl",

        },

        "integration": {

            "name": "Integration Tests",

            "description": "ทดสอบว่า Composition สร้าง actual cloud resources ได้จริง",

            "tool": "Kind cluster + Crossplane + provider",

        },

        "e2e": {

            "name": "E2E Tests",

            "description": "ทดสอบ full flow: claim → resources ready → app connects",

            "tool": "Chainsaw, kuttl, custom scripts",

        },

    }



    RENDER_TEST = """

# test_composition.sh — Test Composition rendering

# Install: crossplane CLI

# crossplane beta render claim.yaml composition.yaml functions.yaml



# Example test with kuttl

# tests/database/00-claim.yaml

apiVersion: platform.example.com/v1alpha1

kind: Database

metadata:

  name: test-db

spec:

  size: small

  engine: postgres



# tests/database/00-assert.yaml

apiVersion: rds.aws.upbound.io/v1beta1

kind: Instance

metadata:

  labels:

    crossplane.io/claim-name: test-db

spec:

  forProvider:

    instanceClass: db.t3.micro

    engine: postgres

"""



    def show_strategies(self):

        print("=== Testing Strategies ===\n")

        for key, strat in self.STRATEGIES.items():

            print(f"[{strat['name']}]")

            print(f"  {strat['description']}")

            print(f"  Tool: {strat['tool']}")

            print()



    def show_render_test(self):

        print("=== Render Test ===")

        print(self.RENDER_TEST[:400])



test = CompositionTesting()

test.show_strategies()

test.show_render_test()

FAQ - คำถามที่พบบ่อย

Q: Crossplane กับ Terraform อันไหนดี?

A: Crossplane: Kubernetes-native, continuous reconciliation, self-service platform, GitOps Terraform: mature, HCL language, state management, broad provider support ใช้ Crossplane: Kubernetes-first org, self-service platform, continuous drift detection ใช้ Terraform: standalone IaC, non-K8s environments, team คุ้นเคย HCL ใช้ทั้งคู่ได้: Terraform สำหรับ bootstrap + Crossplane สำหรับ day-2 operations

เนื้อหาเกี่ยวข้อง — บทความที่เกี่ยวข้อง: private domain คือ — วิธีตั้งค่าและใช้งานจริงพร้อมตัวอย่าง

Q: Developer Experience สำคัญอย่างไร?

แนะนำเพิ่มเติม — หนังสือเทรดที่ SiamCafeBook

A: DX ดี = developer productivity สูง = ship faster = competitive advantage DX แย่ = developer frustration = slow delivery = talent retention issues วัด DX: Time to first resource, number of support tickets, developer satisfaction survey Crossplane ช่วย DX: abstract complexity, self-service, guardrails, sensible defaults

เนื้อหาเกี่ยวข้อง — ทำความเข้าใจ line messaging api คือ

Q: Composition ยากไหม?

A: เขียน Composition: ยากพอสมควร (ต้องรู้ Crossplane + cloud resources) ใช้ Claim: ง่ายมาก (แค่ YAML 10 บรรทัด) Platform team เขียน Composition ครั้งเดียว → developers ใช้ Claim ซ้ำได้ตลอด เริ่มต้น: ใช้ Upbound Marketplace มี ready-made compositions

แนะนำเพิ่มเติม — ติดตาม XM Signal

เนื้อหาเกี่ยวข้อง — ทำความเข้าใจ Healthchecks.io Infrastructure as Code

Q: เริ่มใช้ Crossplane อย่างไร?

A: 1. ติดตั้ง Crossplane บน Kubernetes (helm install) 2. ติดตั้ง Provider (e.g., provider-aws) 3. สร้าง XRD + Composition สำหรับ use case แรก (เช่น Database) 4. ให้ developers ทดลองใช้ Claim 5. เพิ่ม Compositions ตาม feedback Docs: docs.crossplane.io | Upbound: upbound.io

เนื้อหาเกี่ยวข้อง — ทำความเข้าใจ Betteruptime Performance Tuning เพิ่มความเร็ว

XM Legend · เทรดเดอร์ & ผู้สอน Forex 13 ปี

ผู้ก่อตั้ง SiamCafe ตั้งแต่ปี 1997 · เทรดเดอร์สาย Forex มากกว่า 13 ปี ได้รับการยกย่องเป็น XM Legend · แบ่งปันความรู้ Forex, ไอที, AI และการเทรด จากประสบการณ์จริงในตลาดจริง