Altyapıyı elle kurmanın sınırına bir kez çarptıysan ne demek istediğimi bilirsin: üç sunucuyu tek tek hazırlarsın, dördüncüsünde bir firewall kuralını atlarsın ve iki hafta sonra kimse o ortamın neden farklı davrandığını açıklayamaz. Herkes er ya da geç aynı yere gelir — altyapıyı kod olarak tanımlamaya. Bu kararı verdikten sonra karşına çıkan ilk çatal yol da genellikle Pulumi ve Terraform karşılaştırması olur. İkisi de aynı problemi çözer: kaynakları bildirimsel olarak tarif edersin, araç mevcut durumla arzu edilen durumu karşılaştırır ve aradaki farkı uygular.
Bu rehberde iki aracı pazarlama sayfalarındaki özellik listesiyle değil, günlük kullanımda gerçekten fark yaratan noktalarla karşılaştıracağım: yapılandırmayı hangi dille yazdığın, state dosyasının nerede ve nasıl saklandığı, sırların (secret) ne kadar güvenli tutulduğu, provider ekosisteminin genişliği, lisans değişikliğinin ne anlama geldiği ve ekibinin profiline göre hangisinin daha az sürtünme yarattığı. Sonunda da ikisini de yanlış kullandığında başına gelen klasik tuzakları anlatacağım — çünkü asıl acı orada.
Temel Yaklaşım Farkı: Özel Dil mi, Bildiğin Dil mi#
Terraform, HCL (HashiCorp Configuration Language) adında amaca özel bir yapılandırma dili kullanır. HCL programlama dili değildir; blok tabanlı, bildirimsel bir tarif dilidir. Bunun getirisi büyüktür: dosyaya baktığında ne olacağını okumak kolaydır, herkes aynı biçimde yazar ve "akıllı" kod yazma isteği doğal olarak sınırlanır. Bedeli ise for_each, count, dynamic blokları ve try()/can() gibi fonksiyonlarla yaptığın her karmaşık işin, gerçek bir dilde üç satır olacak şeyi on beş satıra çıkarmasıdır.
# Terraform: üç web sunucusu ve ortak güvenlik grubu
variable "sunucu_sayisi" {
type = number
default = 3
}
resource "example_server" "web" {
count = var.sunucu_sayisi
name = "web-${count.index + 1}"
image = "ubuntu-24-04"
region = "tr-ist"
}
output "ip_listesi" {
value = example_server.web[*].ipv4_address
}
Pulumi ise tam tersini yapar: altyapıyı TypeScript, Python, Go, C# veya Java gibi genel amaçlı bir dille yazarsın. Döngü for döngüsüdür, koşul iftir, tekrar eden yapıyı bir fonksiyona ya da sınıfa alırsın, birim testi yazabilirsin ve IDE'n otomatik tamamlama yapar. Aynı örnek Pulumi'de şöyle görünür:
# Pulumi (Python): aynı üç sunucu, dilin kendi döngüsüyle
import pulumi
import pulumi_example as example
sunucu_sayisi = 3
sunucular = []
for i in range(sunucu_sayisi):
sunucular.append(example.Server(
f"web-{i + 1}",
image="ubuntu-24-04",
region="tr-ist",
))
pulumi.export("ip_listesi", [s.ipv4_address for s in sunucular])
Bu fark, aracı seçerken göz ardı edilemeyecek kadar belirleyicidir. Yazılım geliştiricilerden oluşan bir ekipte Pulumi'nin öğrenme eğrisi neredeyse sıfırdır. Sistem yöneticilerinden oluşan bir ekipte ise HCL'in sınırlılığı bir kısıt değil, bir korkuluk olarak işe yarar: kimse altyapı deposunun içine bir mini uygulama gömemez.
State Yönetimi: İşin En Kritik Yarısı#
Her iki araç da uyguladığı her kaynağı bir state dosyasında tutar. State, "ben şu kaynağı şu kimlikle oluşturdum" defteridir; bu defter olmadan araç neyi güncelleyeceğini, neyi sileceğini bilemez. Terraform'da varsayılan olarak terraform.tfstate dosyası yerel diske yazılır ve bu, tek kişilik denemeler dışında hemen değiştirilmesi gereken bir varsayılandır. Ekip çalışmasında state uzak bir backend'e (S3 uyumlu depolama, HTTP backend, HCP Terraform gibi) alınır ve kilitleme (locking) devreye sokulur.
# Terraform: S3 uyumlu uzak backend + kilitleme
terraform {
backend "s3" {
bucket = "firmaniz-tfstate"
key = "uretim/altyapi.tfstate"
region = "eu-central-1"
# Aynı anda iki apply çalışmasını engelleyen kilit tablosu
dynamodb_table = "terraform-locks"
encrypt = true
}
}
Pulumi'de varsayılan backend, ücretsiz katmanı olan Pulumi Cloud servisidir; ama tamamen kendine ait bir yere de kayabilirsin. pulumi login --local yerel dosya sistemini, pulumi login s3://kova-adi ise nesne depolamayı backend yapar. Pulumi'nin burada kayda değer bir üstünlüğü var: sırlar varsayılan olarak state içinde şifreli tutulur. Terraform'da ise bir veritabanı parolasını sensitive = true işaretlesen bile state dosyasında düz metin durur — bu yüzden Terraform state dosyası tam yetkili bir sır kasası gibi korunmalıdır.
# Pulumi: state'i kendi nesne depolamana al ve şifreleme anahtarını sen belirle
pulumi login s3://firmaniz-pulumi-state
export PULUMI_CONFIG_PASSPHRASE='uzun-ve-rastgele-bir-parola'
# Sırrı şifreli olarak yapılandırmaya yaz
pulumi config set --secret db_parolasi 'S3cr3t-Deg3r'
# Ne değişecek, önce göster
pulumi preview
| Konu | Terraform | Pulumi |
|---|---|---|
| Yapılandırma dili | HCL (amaca özel) | TypeScript, Python, Go, C#, Java, YAML |
| Varsayılan state konumu | Yerel terraform.tfstate | Pulumi Cloud (yerel/S3'e alınabilir) |
| State içinde sır | Düz metin | Varsayılan olarak şifreli |
| Değişiklik önizleme | terraform plan | pulumi preview |
| Yeniden kullanım birimi | Module | ComponentResource / sınıf |
| Test edilebilirlik | Sınırlı (terratest gibi dış araçlar) | Dilin kendi birim test altyapısı |
| Mevcut kaynağı içeri alma | terraform import | pulumi import (kod da üretir) |
Provider Ekosistemi ve Olgunluk#
Terraform'un en güçlü tarafı ekosistemidir. Yıllardır fiilen standart olduğu için, aklına gelen hemen her bulut sağlayıcısının, DNS servisinin, izleme aracının ve hatta bazı SaaS ürünlerinin resmi ya da topluluk tarafından bakılan bir provider'ı vardır. Bir sorunla karşılaştığında, o sorunu senden önce yaşamış birinin yazdığı bir issue ya da blog yazısını bulma ihtimalin çok yüksektir. Bu, canlı ortamda gece yarısı bir hata ayıklarken düşündüğünden daha değerlidir.
Pulumi bu boşluğu akıllıca kapatmıştır: Terraform provider'larını köprüleyerek (bridge) kendi paketlerini üretir. Yani pratikte Terraform'un provider genişliğinin büyük bölümüne Pulumi'den de erişirsin, sadece paket adları ve tip isimleri dilin konvansiyonuna uyarlanmıştır. Buna karşılık köprülenmiş bir provider'da yeni çıkan bir özelliğin Pulumi tarafına düşmesi bazen birkaç sürüm gecikebilir. Elinde niş bir sağlayıcı varsa, karar vermeden önce o sağlayıcının Pulumi paketinin ne kadar güncel olduğunu kontrol et.
Mevcut bir Terraform kod tabanın varsa geçiş de mümkündür; Pulumi HCL dosyalarını hedef dile çeviren bir dönüştürücü sunar:
# Var olan Terraform modülünü Pulumi projesine çevir
pulumi convert --from terraform --language typescript --out ./pulumi-altyapi
# Zaten var olan bir kaynağı state'e ve koda al
pulumi import example:index/server:Server web-1 srv-12345
Dönüştürücünün çıktısını asla göz kapalı uygulamama alma; okunabilir ama her zaman idiomatik olmayan bir kod üretir. Onu bir başlangıç taslağı say, elden geçir, sonra preview çıktısının sıfır değişiklik gösterdiğini doğrula. Konteyner tabanlı bir yığını kodla yönetiyorsan, aynı disiplini uygulama katmanında da sürdürmek istersin; Docker Compose kullanımı yazısı servis tanımlarını sürüm kontrolünde tutmanın karşılığını iyi anlatır.
Lisans, OpenTofu ve Kurumsal Risk#
2023'te HashiCorp, Terraform'un lisansını açık kaynak MPL 2.0'dan BUSL 1.1'e taşıdı. Sıradan bir kullanıcı için pratikte bir şey değişmedi: kendi altyapını yönetmek hâlâ serbest. Değişen şey, Terraform'u temel alan rakip bir ticari ürün sunmanın kısıtlanmasıydı. Buna tepki olarak topluluk, son MPL sürümünden çatallayarak Linux Foundation çatısı altında OpenTofu projesini kurdu. OpenTofu'nun komut satırı aracı tofu adını taşır ve HCL uyumluluğunu korur; çoğu projede terraform komutunu tofu ile değiştirmek yeterli olur.
Bu tabloyu bilmek karar verirken önemlidir çünkü artık tek bir "Terraform" yok; HashiCorp'un ürünü ve topluluk çatalı var. Kurumsal bir satın alma sürecinden geçiyorsan hukuk ekibinin BUSL maddelerini okuması gerekebilir. Pulumi tarafında motor Apache 2.0 lisanslıdır; ücretli olan kısım, ekip özellikleri sunan barındırılan servistir ve state'i kendi deponda tutarak o servisi hiç kullanmadan da çalışabilirsin.
| Kriter | Terraform (BUSL) | OpenTofu | Pulumi |
|---|---|---|---|
| Lisans | BUSL 1.1 | MPL 2.0 | Apache 2.0 (motor) |
| Yönetim | HashiCorp | Linux Foundation | Pulumi Corp. + topluluk |
| Ücretli katman | HCP Terraform | Yok | Pulumi Cloud (ekip özellikleri) |
| Kendi state'ini barındırma | Evet | Evet | Evet |
Hangi Durumda Hangisini Seçmelisin#
Onlarca projede ikisini de kullandıktan sonra vardığım pratik ayrım şu: aracın dili, ekibinin dilini takip etmeli. Altyapıyı yazacak insanlar günlerini Python ya da TypeScript içinde geçiriyorsa Pulumi seni hızlandırır; aynı insanlar bash, ansible ve YAML dünyasından geliyorsa HCL'in öngörülebilirliği daha az sürtünme yaratır.
| Senaryo | Daha uygun seçim | Neden |
|---|---|---|
| Karma ekip, altyapıyı SRE yazıyor | Terraform / OpenTofu | Tek biçimli, okuması kolay, iş ilanı havuzu geniş |
| Altyapıyı uygulama geliştiricileri yazıyor | Pulumi | Aynı dil, aynı test araçları, aynı paket yöneticisi |
| Çok sayıda benzer ortamın programatik üretimi | Pulumi | Gerçek döngü/soyutlama, Automation API |
| Hazır modül ekosisteminden azami fayda | Terraform / OpenTofu | Registry olgunluğu ve topluluk hacmi |
| Sırların state'te şifreli durması şart | Pulumi | Varsayılan şifreleme |
| Lisans belirsizliğinden tamamen kaçınmak | OpenTofu | MPL 2.0, vakıf yönetimi |
Şunu da net söyleyeyim: yanlış seçim yapıp yapmadığın, altı ay sonra kod tabanına bakıldığında anlaşılır. İkisi de doğru kullanıldığında işini görür; ikisi de state'i özensiz yönetildiğinde aynı biçimde canını yakar.
Sık Yapılan Hatalar ve Tuzaklar#
En sık gördüğüm hata, state dosyasını sürüm kontrolüne koymaktır. terraform.tfstate içinde kaynak kimlikleri, IP adresleri ve çoğu zaman düz metin sırlar bulunur; deponun okuma yetkisi olan herkes bunları görür. .gitignore dosyana *.tfstate, *.tfstate.backup ve .terraform/ girdilerini ilk günden ekle, state'i uzak backend'e al. Bu konunun ne kadar kolay felakete dönüştüğünü görmek istersen .git klasörü ve .env dosyası ifşası yazısındaki senaryolar iyi bir uyarıdır.
İkinci klasik hata, kilitleme olmadan ekipçe apply çalıştırmaktır. İki kişi aynı anda uygularsa state bozulur ve düzeltmesi elle state rm / import gerektiren, saatler süren bir işe dönüşür. Uzak backend seçerken kilit desteği olduğundan emin ol.
Üçüncüsü, provider ve modül sürümlerini sabitlememektir. Sürüm aralığını açık bıraktığında, bugün çalışan plan yarın bambaşka bir çıktı üretir ve suçu kendi değişikliğinde ararsın:
terraform {
required_version = "~> 1.9"
required_providers {
example = {
source = "example/example"
version = "~> 2.4" # 2.5 gelirse otomatik atlamasın
}
}
}
Dördüncüsü, tek dev state. Ağ, veritabanı, Kubernetes ve DNS'i tek bir state'e koyarsan her küçük değişiklik için tüm altyapıyı planlamak zorunda kalırsın; plan süresi dakikalara çıkar ve bir hata tüm ortamı riske atar. Sorumluluk sınırlarına göre böl: ağ ayrı, veri katmanı ayrı, uygulama ayrı.
Beşincisi, konsoldan elle müdahale. Panelden hızlıca bir kural eklersin, kod bunu bilmez ve bir sonraki apply sessizce geri alır. terraform plan -refresh-only veya pulumi refresh ile kaymayı (drift) düzenli olarak kontrol et, tespit edilen farkı ya koda taşı ya da geri al.
Sıkça Sorulan Sorular#
Pulumi ücretsiz mi#
Pulumi'nin komut satırı aracı ve motoru açık kaynaktır ve ücretsizdir; altyapını istediğin ölçekte yönetebilirsin. Ücretli olan kısım, state'i barındıran ve ekip yönetimi, denetim kaydı, erişim kontrolü gibi özellikler sunan Pulumi Cloud servisidir. State'i kendi nesne depolamanda ya da yerel diskte tutarak bu servisi hiç kullanmadan da çalışabilirsin; bireysel kullanım için ücretsiz bir katman da mevcuttur.
Terraform'dan Pulumi'ye geçiş ne kadar sürer#
Küçük ve modüler bir kod tabanında birkaç gün, büyük ve iç içe geçmiş bir altyapıda haftalar sürebilir. pulumi convert --from terraform komutu HCL'i hedef dile çevirerek işin mekanik kısmını halleder, ama çıktının elden geçirilmesi gerekir. Kritik adım, dönüşümden sonra pulumi preview çıktısının hiçbir değişiklik göstermemesidir; bu, mevcut kaynakların yeniden oluşturulmayacağını kanıtlar.
OpenTofu ile Terraform kodum çalışır mı#
Çoğu durumda evet. OpenTofu, Terraform'un son açık kaynak sürümünden çatallandığı için HCL söz dizimini ve provider protokolünü korur; birçok projede terraform komutunu tofu ile değiştirmek yeterli olur. Ancak iki proje zamanla ayrıştığı için, HashiCorp'un son sürümlerine özgü yeni özellikler kullanıyorsan geçişten önce mutlaka bir test ortamında tofu plan çalıştırıp çıktıyı karşılaştır.
Hangisi daha hızlı çalışır#
İkisi arasındaki hız farkı pratikte belirleyici değildir; çünkü sürenin büyük bölümünü aracın kendisi değil, bulut sağlayıcısının API çağrıları harcar. Yüz kaynaklık bir yığında ikisi de benzer sürelerde biter. Asıl hız farkını state'in boyutu ve nerede durduğu yaratır: tek dev state ve yavaş bir backend, hangi aracı kullanırsan kullan planlama süresini dakikalara çıkarır.
State dosyasını kaybedersem ne olur#
Araç, hangi kaynağı yönettiğini unutur; sunucuların çalışmaya devam eder ama bir sonraki uygulamada hepsini yeniden oluşturmaya kalkar. Bu yüzden state uzak, sürümlenen ve yedeklenen bir depoda tutulmalıdır. Yine de kaybedersen tek çıkış yolu her kaynağı tek tek terraform import veya pulumi import ile geri almaktır; bu, büyük bir altyapıda günler alan bir iştir.
IaC aracını izleme sistemiyle birlikte nasıl kurgularım#
En temiz yaklaşım, izleme yığınını da altyapı kodunun bir parçası yapmaktır: Prometheus, Grafana ve exporter'ları elle kurmak yerine aynı depoda tanımlarsın, böylece yeni bir ortam açtığında izleme kendiliğinden gelir. Sunucu tarafında metrik toplamaya nereden başlayacağını Prometheus kurulumu yazısında adım adım bulabilirsin. Kural şudur: izlemesi olmayan bir ortam, kodla kurulmuş olsa bile üretim ortamı sayılmaz.
Kapanış#
Pulumi ve Terraform arasındaki seçim, teknik üstünlük yarışından çok bir uyum meselesidir. Aklında kalması gereken dört pratik alışkanlık şunlar: state'i ilk günden uzak ve kilitlenebilir bir backend'e al, sırları asla state'e düz metin bırakma, provider ve modül sürümlerini sabitle, altyapıyı tek dev state yerine sorumluluk sınırlarına göre böl. Bunları yaptıktan sonra hangi aracı seçtiğin ikinci derece bir ayrıntıya dönüşür.
Kodla tanımladığın altyapının altında sağlam bir makine olması gerekiyorsa, tam root erişimli VDS ve sanal sunucu paketlerimiz üzerinde Terraform veya Pulumi ile kendi ortamını sıfırdan kurabilirsin. Daha esnek ölçeklenen bir zemin istersen bulut sunucu tarafına bakabilir, kurulum ve bakım yükünü tamamen devretmek istersen sunucu yönetimi hizmetimizle bu işi biz üstlenebiliriz.