Crossplane ile Kubernetes Uzerinde Altyapi Yonetimi
Bir AWS hesabında RDS instansını biri konsoldan, biri Terraform apply ile değiştirdiyse hangisi kazançlı çıkar? Cevap ne konsol ne Terraform: kazanan, değişikliği sürekli izleyip geri çeviren kontrol düzlemi. Crossplane tam bu cümleyi ürünleştiren proje. Kubernetes cluster içine kuruluyor, dış kaynakları S3 bucket, RDS instansı, DNS kaydı, GitHub reposu ne olursa olsun custom resource olarak modelliyor ve pod gibi sürekli reconcile ediyor. 2025 Ekim ayında CNCF graduated seviyesine ulaştı, yani Kubernetes, Prometheus ve Helm ile aynı olgunluk kademesinde.
Kontrol düzlemi fikri neden farklı
Terraform çalışma modeli plan ve apply üzerine kurulu. Biri komutu çalıştırır, dünya değişir, sonra bir sonraki apply anına kadar kimse gerçeği izlemez. Aradaki süre dakikalar da olabilir aylar da. Bu boşlukta bir SRE break-glass dokunuşuyla, bir başka araç ya da insan cloud tarafında değişiklik yaptıysa buna drift deniyor ve bu drift ancak bir sonraki apply'da, o da şanslıysanız plan çıktısında görünür.
Crossplane'de apply adımı yok. İstenen durum etcd içinde yaşıyor, controller sürekli gerçek duruma doğru çekiyor. RDS instansı cluster dışında biri tarafından silinirse reconcile aralığı içinde fark edilip yeniden oluşturuluyor. Deployment pod'ları nasıl hizalı tutuyorsa Crossplane de altyapıyı aynı düzenle hizalı tutuyor. Bu davranışı bir kez kafanızda oturttuysanız gerisi konfigürasyon.
Terminoloji hızlı tur
Crossplane kurulunca crossplane-system namespace'inde pod'lar ayağa kalkıyor ve çekirdek CRD'ler geliyor: providers.pkg.crossplane.io, locks.pkg.crossplane.io gibi. Çalışma modelinin dört ana parçası var.
Provider, Kubernetes'i dış bir servise bağlayan köprü. provider-aws kurunca RDSInstance, Bucket, VPC gibi yüzlerce yeni CRD ve bunları yöneten controller'lar geliyor. Major bulutlar için resmi provider'lar Terraform provider'larından Upjet ile otomatik üretiliyor, bu yüzden API kapsamı Terraform'la büyük ölçüde eş. provider-kubernetes, provider-helm, provider-terraform gibi özel amaçlı olanları da var.
Managed resource, yani MR, provider'ın tanıdığı ham kaynak. apiVersion: rds.aws.upbound.io/v1beta1, kind: Instance yazıp kubectl apply ile gerçek bir RDS instansı alınır. Bulut konsoluna gitmeye gerek yok.
CompositeResourceDefinition yani XRD, platform ekibinin kendi API şemasını tanımladığı yer. group: database.example.org, kind: PostgreSQLInstance gibi kendi tipinizi tanımlıyorsunuz, altında hangi bulut kaynaklarının saklandığı tüketiciyi ilgilendirmiyor.
Composition, XRD ile tanımlanan soyut tipin hangi MR'ları üreteceğinin şablonu. PostgreSQLInstance isteği geldiğinde RDS instansı, security group, subnet group tek nesne altında paketleniyor. Connection detayları writeConnectionSecretsToNamespace ile belirtilen namespace'e Secret olarak yazılıyor, uygulama pod'u bunu doğrudan mount edebiliyor.
Helm ile kurulum
Resmi kurulum yolu Helm chart. Getting started dokümanındaki adımlar şu şekilde:
kubectl create namespace crossplane-system
helm repo add crossplane-stable https://charts.crossplane.io/stable
helm repo update
helm install crossplane --namespace crossplane-system crossplane-stable/crossplane Kurulumun sağlıklı olduğunu iki komutla doğruluyorsunuz: kubectl get pods -n crossplane-system crossplane pod'unun Running olduğunu, kubectl get crds | grep crossplane.io ile de çekirdek CRD'lerin listelendiğini görmeniz lazım.
CLI tarafında kubectl plugin'i tek satırda iniyor:
curl -sL https://raw.githubusercontent.com/crossplane/crossplane/master/install.sh | sh
sudo mv kubectl-crossplane /usr/local/bin Plugin kurulduktan sonra kubectl crossplane --help ile komut setini görebilirsiniz. AWS blog'undaki kontrol cluster rehberinde de aynı desen var: EKS üzerine Crossplane ve Argo CD kuruluyor, kontrol cluster daha sonra yönettiği workload cluster'ları ve yönetilen servisleri provision ediyor.
Bulut kimlik bilgisini bağlamak
Provider'ın bulut API'sine erişmesi için kimlik bilgisi gerekir ve bu, her zaman Secret üzerinden verilir. AWS tarafında klasik yöntem access key profilini base64 ile paketleyip credentials anahtarıyla bir Secret içine koymak, ardından ProviderConfig nesnesiyle bu Secret'a referans vermek. AWS blog'unda iki ayrı Provider nesnesi kurup aynı Secret'ı kullanıp yalnızca region alanını us-west-2 ve us-east-1 olarak değiştiren bir desen anlatılıyor: tek hesap, iki bölge, tek secret. Bol parametreli production ortamında IRSA yani EKS service account'a bağlı IAM role daha temiz bir yol, External Secrets Operator ile cluster harici bir secret store'dan çekmek de yaygın.
Somut örnek: RDS instansı
RDS instansı MR olarak şöyle görünüyor:
apiVersion: rds.aws.upbound.io/v1beta1
kind: Instance
metadata:
name: orders
spec:
forProvider:
region: us-east-1
engine: postgres
engineVersion: "16"
instanceClass: db.t3.medium
allocatedStorage: 20
dbName: orders
username: app
passwordSecretRef:
namespace: crossplane-system
name: orders-db-password
key: password
skipFinalSnapshot: true
writeConnectionSecretToRef:
namespace: crossplane-system
name: orders-conn
providerConfigRef:
name: aws-provider-config kubectl apply ile gönderiyorsunuz, controller AWS API'sini çağırıyor, instans ayağa kalkıyor, endpoint ve şifre bilgisi orders-conn Secret'ına yazılıyor. Ekranda hiç konsol açmadan db.t3.medium bir PostgreSQL kurulmuş oluyor. vpcSecurityGroupIdRefs ve dbSubnetGroupNameRef alanlarıyla ağ tarafını da aynı manifest içinde bağlarsınız, multiAz: true ve storageEncrypted: true üretim için standart seçenekler.
State dosyası derdi yok
Terraform'ta state yönetimi ayrı bir mühendislik disiplini: S3 backend, DynamoDB lock tablosu, key rotasyonu, state bozulması halinde restore senaryoları. Crossplane'de bu dosya hiç yok. State, cluster'ın etcd'si. Depolama, kilitleme resourceVersion üzerinden, yedekleme cluster yedekleme stratejinizle birlikte çözülüyor.
Bunun bedeli şeffaf: Crossplane kullanmak için bir Kubernetes cluster işletmeniz gerekiyor. İlk bucket'ınızı provision etmeden önce cluster bakımını üstlenmiş oluyorsunuz. Terraform ise tek binary, her işletim sisteminde çalışıyor. Trade-off burada net.
GitOps ile aynı hatta
Tüm altyapı Kubernetes YAML olduğu için Argo CD ve Flux ile doğal bütünleşiyor. AWS blog'undaki rehber tam bu mimariyi kuruyor: infra dizinindeki manifest'ler Argo CD uygulaması olarak cluster'a apply ediliyor, VPC, subnet, EKS cluster ve RDS hepsi Git deposunda versiyonlanıyor. Pull request review'lu, auditable değişiklik akışı elde ediyorsunuz. Crossplane ekibinin kendi karşılaştırma yazısı buna API merkezli bakıyor: Terraform bir kontrol düzlemine komut satırı arayüzü, Crossplane kendisi bir kontrol düzlemi ve REST API'si otomasyonun ortak dili.
v2 ile ne değişti
2025'te çıkan Crossplane v2 çalışma modelini ciddi değiştirdi. Composite ve managed resource'lar artık varsayılan olarak namespaced, v1'deki claim kavramı kaldırıldı. Daha önemlisi composition artık yalnızca Crossplane'in kendi MR'larını değil herhangi bir Kubernetes nesnesini compose edebiliyor: normal bir Deployment'ı bile XR içine koyabilirsiniz. Ayrıca function pipeline'ları Job gibi çalışıp belirli görevleri yapıp sonuç raporlayan Operations kavramı geldi. v1.X rehberlerini okurken bu farklara dikkat edin, claim'li eski örnekler artık geçerli değil.
Pratikte pek çok ekip ikisini birlikte kullanıyor. Terraform VPC, IAM, EKS control plane gibi temel katmanı yönetiyor, Crossplane mikroservislerin ihtiyaç duyduğu RDS, S3, SQS gibi dinamik kaynakları üst katmanda yönetiyor. Cloudkeeper'ın paylaştığı müşteri vakasında aynen bu ayrım uygulanmış: Terraform pisti döşüyor, Crossplane üzerinde uçuyor, GitOps kuleyi kontrol ediyor.
Crossplane bir kere oturunca geri dönüş zor oluyor, iyi tarafı buna ihtiyaç duymuyorsunuz da. Küçük ekip ve statik altyapıysa Terraform sizi yeterince idare eder. Pull request başına kısa ömürlü ortam, self servis veritabanı API'si, sürekli drift düzeltme gibi ihtiyaclar belirginse kontrol düzlemi tartışmasını açmanın tam zamanı.