Blog
Mert Özen'in yazılım geliştirme, backend, frontend ve DevOps üzerine blog yazıları.
Infrastructure as Code Nedir? Terraform, OpenTofu, Bicep, Pulumi ve Ne Zaman Hangisi
Infrastructure as Code, altyapıyı kodla tarif edip bir aracın onu istenen duruma getirmesidir; aynı kodu ikinci kez çalıştırmak hiçbir şeyi değiştirmez, elle yapılan değişiklik de bir sonraki plan'da drift olarak görünür. Bir bash script'iyle Terraform'u aynı işte karşılaştırıyor, kod-plan-apply-state döngüsünü görüyor, Terraform, OpenTofu, Bicep, Pulumi ve Ansible'ı konumlandırıyor ve BSL, OpenTofu ve CDKTF'nin emekliliğinden sonra ekip için seçim kriterlerini çıkarıyoruz.
Terraform Kurulumu ve İlk Resource: Provider, init, plan, apply ve destroy ile Azure'da Bookstore Resource Group'u
Terraform kurulumu tek bir binary'yi PATH'e koymaktır; asıl iş required_version, provider sürüm kısıtları ve commit'lenen .terraform.lock.hcl ile herkesin aynı sürümü kullanmasını sağlamaktır. AzureRM 5.x ile Bookstore'un resource group ve storage account'unu yazıyor, 5.0'daki resource provider registration değişikliğini görüyor, plan çıktısındaki +, ~, -/+ ve - işaretlerini gerçek çıktılarla okuyor ve saved plan, stale plan, destroy, .gitignore ve fmt'yi deniyoruz.
HCL'i Tanımak: Variable, Output, Local, Expression'lar, count, for_each ve Dynamic Block
HCL'de variable dışarıdan gelen değer, local kod içinde hesaplanan ara değer, output da dışarıya verilen sonuçtur; count kaynakları sıra numarasıyla, for_each key'iyle tanıdığı için listenin ortasından eleman silmek count'ta komşu kaynakları yeniden yaratır. Tipli ve validation'lı variable'lar, tfvars ve TF_VAR_, merge/lookup/try/convert, for expression'ları ve dynamic block'larla Bookstore'un App Service, Azure SQL ve Storage kodunu yazıyoruz.
Terraform State: Ne İşe Yarar, Azure Storage'da Remote Backend, Locking ve State Komutları
State, koddaki her kaynağı gerçek dünyadaki nesnesiyle eşleyen ve içinde secret'ları düz metin tutan dosyadır; bu yüzden laptop'ta ya da Git'te değil, erişimi kısıtlı ve locking yapan bir remote backend'de durur. Backend'i bootstrap stack'iyle kuruyor, state'i -migrate-state ile taşıyor, gerçek bir lock hatasını okuyor, Azure Storage backend'ini Entra ID ile yazıyor ve state mv, rm, import ile -refresh-only'yi deniyoruz.
Dependency Graph, Data Source ve Lifecycle: depends_on, create_before_destroy, prevent_destroy ve ignore_changes
Terraform kaynakları referanslardan kurduğu bir dependency graph'a göre ve mümkün olduğunca paralel oluşturur; depends_on yalnız kodun göremediği bağımlılıklar, lifecycle ise replace ve silme davranışını değiştirmek içindir. Graph'ı Mermaid ile çiziyor, data source'larla ortak kaynakları okuyor, create_before_destroy'un sabit adda nasıl takıldığını, prevent_destroy, ignore_changes, replace_triggered_by, precondition, 1.16'daki destroy = false ve check block'larını gerçek çıktılarla görüyoruz.
Module Yazmak ve Kullanmak: Input/Output Sözleşmesi, Registry Module'leri, Versiyonlama ve Dynamic Source
Module, variable'ları ve output'larıyla bir sözleşme sunan, tekrar eden bir kaynak grubudur; kaynakları module'e taşımak moved block'ları olmadan silip yeniden oluşturmak demektir. API'yi bookstore-service, Web App'i bookstore-webapp module'üne taşıyor, prevent_destroy'un neden korumadığını görüyor, Azure Verified Modules'tan birini indirip inceliyor, sürüm sabitlemeyi ve Terraform 1.15'teki const variable'lı module source ile deprecated input/output'ları deniyoruz.
Environment'ları Ayırmak: Workspace mi, Dizin mi, tfvars mı? Blast Radius ve Klasör Düzeni
Her environment'ın kendi state'i olmalı; uzun ömürlü dev, staging ve prod için en güvenli yol, ortak kodu bir module'e koyup her ortamı kendi backend'i ve değerleriyle ayrı bir klasörden çağırmak. Aynı state'e staging değerleri vermenin dev'i nasıl replace ettiğini, CLI workspace'lerini, tfvars ve backend config yolunu ve dizin düzenini gerçek çıktılarla deniyor, state'i katmanlara bölmeyi, terraform_remote_state'in risklerini ve const variable ile module sürümü terfisini görüyoruz.
Var Olan Altyapıyı Terraform'a Almak: import Block, terraform query ve list, moved ve removed Block'ları
Elle kurulmuş bir kaynağı Terraform'a almanın yolu üzerine apply etmek değil, import block'uyla hangi kaynağın hangi adrese ait olduğunu söylemek ve ilk plan'daki her replace satırını tek tek karara bağlamaktır. Elle kurulmuş bir staging'i for_each'li import block'larıyla alıyor, -generate-config-out ve terraform query'nin ne verdiğini görüyor, moved block'larının ne zaman silineceğini, count'tan for_each'e geçişi ve removed ile kaynağı silmeden başka bir state'e devretmeyi deniyoruz.
Terraform'da Secret'lar: sensitive, Ephemeral Value'lar, Write-only Argument'lar ve Key Vault
sensitive yalnız ekrandaki çıktıyı gizler; değer state'te, kaydedilmiş plan'da ve output -json'da düz metin kalır, state dışında tutmanın yolu ephemeral value'ları write-only argument'lara vermektir. Secret'ların sızdığı yerleri gerçek çıktılarla buluyor, ephemeral değerlerin nerede kullanılabildiğini görüyor, write-only şifreyi ve sürümle rotation'ı gerçek bir veritabanında deniyor ve Azure SQL yönetici şifresini state'e hiç yazmadan SQL Server'a ve Key Vault'a veriyoruz.
Terraform Kodunu Doğrulamak ve Test Etmek: fmt, validate, tflint, terraform test, mock_provider ve Policy
validate yalnız kodun çalışabilir olduğunu söyler; kurallarını korumak için tflint, güvenlik taraması ve mock_provider'lı terraform test katmanlarına ihtiyacın var ve hiçbiri cloud hesabı istemez. TLS 1.1'e çekilen bir Web App'i validate'in geçirip testin durdurduğunu görüyor, tflint ve Trivy bulgularını ayıklıyor, bütün Azure ortamını mock'larla apply ediyor, Docker ile gerçek provider testi yazıyor ve hepsini tek bir script'te topluyoruz.
GitHub Actions ile Terraform: OIDC ile Plan/Apply, PR'a Plan Özeti, Onaylı Apply ve Drift Kontrolü
Güvenli bir Terraform pipeline'ında PR'daki plan review içindir; main'de plan yeniden alınıp kaydedilir ve onaydan sonra tam olarak o dosya uygulanır, plan ve apply da OIDC ile ayrı identity'lerle çalışır. Kontrol, plan özeti yorumu, environment onaylı apply ve concurrency içeren workflow'ları yazıyor, fork PR'larını credential'dan ayırıyor ve check block'ları ile provider gürültüsüne takılmayan bir drift script'ini gerçek denemelerle kuruyoruz.
Terraform 1.5'ten 1.17'ye ve AzureRM 3'ten 5'e: Ne Değişti, Eski Kodu Nasıl Okursun
Eski bir Terraform kodunu bugünkü sürüme taşımak, söz dizimi düzeltmelerini, adres taşımalarını ve provider'dan kaldırılmış tiplerin göçünü ayrı adımlarda, her adımda boş bir plan görerek yapmaktır. 0.11 dönemi kodu 1.17 ile çalıştırıyor, null_resource'u terraform_data'ya taşıyor, 1.5'ten 1.17'ye sürüm haritasını ve -minimal-refresh'in drift'i nasıl gizlediğini görüyor, AzureRM 3'ten 5'e yükseltme sırasını ve OpenTofu ile gerçek uyum farklarını deniyoruz.