1. Apa itu Crossplane?
Crossplane adalah open-source Kubernetes add-on yang memungkinkan Anda mengelola infrastruktur cloud (database, cluster, storage, networking) menggunakan Kubernetes Custom Resource Definitions (CRDs). Dengan Crossplane, infrastruktur dikelola dengan cara yang sama seperti aplikasi Kubernetes — deklaratif, version-controlled, dan GitOps-friendly.
Composition (API)
(simplified API)
Managed Resources
Actual infrastructure
1.1 Crossplane vs Terraform
| Fitur | Crossplane | Terraform |
|---|---|---|
| State | CRD di Kubernetes (etcd) | State file (.tfstate) |
| Reconciliation | Continuous (watch loop) | Hanya saat apply |
| Abstraction | XRD + Composition | Modules |
| GitOps | Native (ArgoCD) | Butuh wrapper |
| Drift Detection | Otomatis | Terraform plan |
2. Instalasi & Setup
# Install Crossplane menggunakan Helm helm repo add crossplane-stable https://charts.crossplane.io/stable helm repo update # Install Crossplane helm install crossplane crossplane-stable/crossplane \ --namespace crossplane-system \ --create-namespace \ --wait # Verifikasi instalasi kubectl get pods -n crossplane-system # Install Crossplane CLI (kubectl crossplane) curl -sL https://raw.githubusercontent.com/crossplane/crossplane/master/install.sh | sh sudo mv crossplane /usr/local/bin/ # Install provider untuk AWS kubectl crossplane install provider crossplane/provider-aws:v0.44.0 # Install provider untuk AWS (terbaru) kubectl crossplane install provider xpkg.upbound.io/crossplane-contrib/provider-aws:v1.1.0 # Cek status provider kubectl get providers # NAME INSTALLED HEALTHY AGE # crossplane-provider-aws True True 2m
3. Providers
Provider adalah plugin yang memungkinkan Crossplane berkomunikasi dengan cloud provider. Setiap provider mendefinisikan Managed Resources (MR) — representasi CRD dari resource cloud yang sebenarnya.
# Install provider AWS
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws-s3
spec:
package: xpkg.upbound.io/crossplane-contrib/provider-aws-s3:v1.1.0
# Runtime config untuk mengatur resource limits
runtimeConfigRef:
name: provider-aws-runtime
---
apiVersion: pkg.crossplane.io/v1beta1
kind: DeploymentRuntimeConfig
metadata:
name: provider-aws-runtime
spec:
deployment:
spec:
replicas: 1
template:
spec:
containers:
- name: package-runtime
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 100m
memory: 256Mi
# Install provider AWS RDS
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-aws-rds
spec:
package: xpkg.upbound.io/crossplane-contrib/provider-aws-rds:v1.1.0
# Install provider Kubernetes (untuk mengelola K8s resources)
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-kubernetes
spec:
package: xpkg.upbound.io/crossplane-contrib/provider-kubernetes:v0.14.0
# Install provider Helm
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
name: provider-helm
spec:
package: xpkg.upbound.io/crossplane-contrib/provider-helm:v0.18.0
# Cek semua providers
kubectl get providers
4. XRDs (Composite Resource Definitions)
XRD mendefinisikan API baru yang disederhanakan untuk application teams. Platform team membuat XRD yang mengabstraksi kompleksitas cloud resource menjadi API yang lebih sederhana.
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xpostgresqlinstances.database.example.com
spec:
group: database.example.com
names:
kind: XPostgreSQLInstance
plural: xpostgresqlinstances
claimNames:
kind: PostgreSQLInstance
plural: postgresqlinstances
connectionSecretKeys:
- host
- port
- username
- password
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
parameters:
type: object
description: "Parameter yang bisa diatur oleh app team"
properties:
storageGB:
type: integer
description: "Ukuran storage dalam GB"
minimum: 20
maximum: 1000
default: 50
engine:
type: string
enum: ["postgres"]
default: "postgres"
engineVersion:
type: string
enum: ["14", "15", "16"]
default: "16"
multiAZ:
type: boolean
default: false
description: "Enable Multi-AZ untuk high availability"
backupRetentionDays:
type: integer
minimum: 0
maximum: 35
default: 7
required:
- storageGB
required:
- parameters
status:
type: object
properties:
endpoint:
type: string
port:
type: integer
instanceId:
type: string
XRD adalah API internal platform Anda. Application team tidak perlu tahu apakah database menggunakan AWS RDS, Google Cloud SQL, atau self-hosted PostgreSQL. Mereka hanya perlu menspesifikasi storageGB dan engineVersion. Platform team yang memutuskan implementasi di belakangnya.
5. Compositions
Composition mendefinisikan bagaimana XRD di-mapping ke managed resources yang sebenarnya. Ini adalah template yang menggabungkan beberapa cloud resource menjadi satu unit logis.
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: postgresql-aws
labels:
provider: aws
spec:
compositeTypeRef:
apiVersion: database.example.com/v1alpha1
kind: XPostgreSQLInstance
writeConnectionSecretsToNamespace: crossplane-system
patchSets:
- name: common
patches:
- type: FromCompositeFieldPath
fromFieldPath: metadata.labels
toFieldPath: metadata.labels
resources:
# Resource 1: RDS Subnet Group
- name: subnetGroup
base:
apiVersion: rds.aws.crossplane.io/v1alpha1
kind: DBSubnetGroup
spec:
forProvider:
description: "Crossplane managed subnet group"
subnetIds:
- subnet-0123456789abcdef0
- subnet-0123456789abcdef1
providerConfigRef:
name: aws-provider
patches:
- type: FromCompositeFieldPath
fromFieldPath: metadata.uid
toFieldPath: spec.forProvider.tags
transforms:
- type: string
string:
fmt: "crossplane-%s"
policy:
mergeOptions:
appendSlice: true
# Resource 2: RDS Instance
- name: rdsInstance
base:
apiVersion: rds.aws.crossplane.io/v1alpha1
kind: DBInstance
spec:
forProvider:
dbInstanceClass: db.t3.medium
engine: postgres
publiclyAccessible: false
autoMinorVersionUpgrade: true
storageEncrypted: true
multiAZ: false
masterUsername: admin
providerConfigRef:
name: aws-provider
writeConnectionSecretToRef:
namespace: crossplane-system
patches:
- type: CombineFromComposite
combine:
variables:
- fromFieldPath: metadata.uid
strategy: string
string:
fmt: "crossplane-%s"
toFieldPath: metadata.annotations[crossplane.io/external-name]
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.storageGB
toFieldPath: spec.forProvider.allocatedStorage
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.engineVersion
toFieldPath: spec.forProvider.engineVersion
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.multiAZ
toFieldPath: spec.forProvider.multiAZ
- type: FromCompositeFieldPath
fromFieldPath: spec.parameters.backupRetentionDays
toFieldPath: spec.forProvider.backupRetentionPeriod
connectionDetails:
- name: host
fromFieldPath: status.atProvider.endpoint.address
- name: port
fromFieldPath: status.atProvider.endpoint.port
type: FromFieldPath
- name: username
fromConnectionSecretKey: username
- name: password
fromConnectionSecretKey: password
6. Claims
Claims adalah cara application team meminta resource. Claims adalah namespace-scoped, berbeda dengan Composite Resource yang cluster-scoped.
# Application team hanya perlu submit claim ini
apiVersion: database.example.com/v1alpha1
kind: PostgreSQLInstance
metadata:
name: my-app-db
namespace: app-team-a
spec:
parameters:
storageGB: 100
engineVersion: "16"
multiAZ: true
backupRetentionDays: 14
compositionSelector:
matchLabels:
provider: aws # Pilih AWS implementation
writeConnectionSecretToRef:
name: my-app-db-connection
---
# Cek status claim
# kubectl get postgresqlinstances -n app-team-a
# NAME READY CONNECTION-SECRET AGE
# my-app-db True my-app-db-connection 5m
# Connection secret berisi endpoint, port, username, password
# kubectl get secret my-app-db-connection -n app-team-a -o yaml
# Gunakan connection secret di Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: app-team-a
spec:
template:
spec:
containers:
- name: my-app
image: my-app:latest
env:
- name: DB_HOST
valueFrom:
secretKeyRef:
name: my-app-db-connection
key: host
- name: DB_PORT
valueFrom:
secretKeyRef:
name: my-app-db-connection
key: port
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: my-app-db-connection
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: my-app-db-connection
key: password
7. Provider Config & Secrets
# Simpan AWS credentials di Kubernetes Secret
apiVersion: v1
kind: Secret
metadata:
name: aws-credentials
namespace: crossplane-system
type: Opaque
stringData:
credentials: |
[default]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
---
# ProviderConfig mengarahkan provider ke credentials
apiVersion: aws.crossplane.io/v1beta1
kind: ProviderConfig
metadata:
name: aws-provider
spec:
credentials:
source: Secret
secretRef:
name: aws-credentials
namespace: crossplane-system
key: credentials
# Alternatif: IRSA (IAM Roles for Service Accounts) — lebih aman
apiVersion: aws.crossplane.io/v1beta1
kind: ProviderConfig
metadata:
name: aws-provider-irsa
spec:
credentials:
source: InjectedIdentity # Gunakan workload identity
---
# Multi-region: buat ProviderConfig per region
apiVersion: aws.crossplane.io/v1beta1
kind: ProviderConfig
metadata:
name: aws-us-east-1
spec:
credentials:
source: InjectedIdentity
region: us-east-1
apiVersion: aws.crossplane.io/v1beta1
kind: ProviderConfig
metadata:
name: aws-ap-southeast-1
spec:
credentials:
source: InjectedIdentity
region: ap-southeast-1
8. GitOps Integration
Crossplane bekerja sangat baik dengan GitOps karena semua konfigurasi adalah CRD yang bisa di-commit ke Git dan di-manage dengan ArgoCD.
# Repository structure untuk GitOps dengan Crossplane
# gitops-repo/
# ├── providers/
# │ ├── aws-provider.yaml
# │ └── provider-config.yaml
# ├── xrd/
# │ ├── xrd-database.yaml
# │ ├── xrd-bucket.yaml
# │ └── xrd-cluster.yaml
# ├── compositions/
# │ ├── composition-db-aws.yaml
# │ └── composition-bucket-aws.yaml
# ├── claims/
# │ ├── dev/
# │ │ ├── app-database.yaml
# │ │ └── app-bucket.yaml
# │ └── prod/
# │ ├── app-database.yaml
# │ └── app-bucket.yaml
# └── argocd/
# ├── app-of-apps.yaml
# └── applications/
# ├── providers.yaml
# ├── xrd.yaml
# └── claims-dev.yaml
# ArgoCD Application untuk providers
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: crossplane-providers
namespace: argocd
spec:
project: infrastructure
source:
repoURL: https://github.com/my-org/gitops-infra.git
targetRevision: main
path: providers
destination:
server: https://kubernetes.default.svc
namespace: crossplane-system
syncPolicy:
automated:
prune: true
selfHeal: true
# Perubahan infrastruktur = perubahan Git commit
# Developer mengubah storageGB dari 50 ke 100:
# 1. Edit claim-database.yaml di Git (ubah storageGB)
# 2. Commit & push
# 3. ArgoCD detect perubahan & sync ke cluster
# 4. Crossplane detect perubahan pada Claim
# 5. Crossplane reconcile: update RDS instance storage
# 6. Status Claim menjadi "Ready"
Saat menggunakan ArgoCD dengan Crossplane, perhatikan propagationPolicy saat menghapus resource. Jika ArgoCD menghapus Claim, Crossplane akan menghapus managed resources dan juga cloud resource yang sebenarnya. Pastikan Anda memiliki backup atau menggunakan deletionPolicy: Orphan untuk resource production.
9. Quiz: Uji Pemahamanmu!
Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut: