İçeriğe geç

(B) DevOps

CDK8s ile Kubernetes Manifestolarını Kodla Tanımlama

YAML, Kubernetes ekosisteminin ortak dili olmuş durumda ama manifestolar çoğaldıkça kopyala yapıştır bakıma dönüşüyor. CDK8s tam bu noktaya dokunuyor:…

10 dk okuma

YAML, Kubernetes ekosisteminin ortak dili olmuş durumda ama manifestolar çoğaldıkça kopyala yapıştır bakıma dönüşüyor. CDK8s tam bu noktaya dokunuyor: manifestoları TypeScript, Python, Java ya da Go ile yazıyorsunuz, araç sizin yerinize YAML üretiyor. AWS tarafından geliştirilen, Apache 2.0 lisanslı açık kaynak bir proje ve CDK ailesinin (aws-cdk, cdktf ile kardeş) Kubernetes tarafını oluşturuyor. Amaç YAML düşmanlığı değil; şablon mantığı, döngüler, fonksiyonlar ve tip denetimiyle tekrar eden manifestoları programlanabilir kılmak.

Üç kavram: App, Chart ve ApiObject

Pratikte CDK8s'in en güçlü yanı, ortak yapıları bir kez tanımlayıp tüm mikroservislerde yeniden kullanabilmeniz. Örneğin tüm servislerinizde geçerli olan resource limitleri, securityContext ayarları, label standartları ve probe tanımlarını tek bir base class içinde topluyorsunuz. Yeni bir servis eklemek, bu sınıftan türetmek ve sadece farklılaşan parametreleri geçmek kadar basit hale geliyor. YAML'da aynı standardı korumak için ya kopyala-yapıştır yaparsınız ya da Helm chart karmaşasına girersiniz; CDK8s'te ise derleyici ve tip sistemi sizi hatalı kullanımda derleme aşamasında uyarıyor.

CDK8s dünyasında her şey bir App içinde yaşar. App, sentez işlemi için kök nesnedir. Her Chart, App altında tanımlanır ve sentez sonunda kendi YAML dosyasına karşılık gelir; dist dizini altında her chart için ayrı bir k8s.yaml dosyası oluşur. ApiObject ise en düşük seviyeli yapı taşıdır; apiVersion, kind, metadata ve spec alanlarını doğrudan siz verirsiniz. Kubernetes tarafında ne varsa ApiObject ile tanımlanabilir, çünkü bu sınıf herhangi bir API nesnesinin birebir karşılığıdır.

import { App, Chart, ApiObject } from "cdk8s";
import { Construct } from "constructs";

export class MerhabaChart extends Chart {
  constructor(scope: Construct, id: string) {
    super(scope, id);
    new ApiObject(this, "ayarlar", {
      apiVersion: "v1",
      kind: "ConfigMap",
      data: {
        karsilama: "merhaba dunya"
      }
    });
  }
}

const app = new App();
new MerhabaChart(app, "merhaba");
app.synth();

Roller net: App sentezi yönetir, Chart çıktı dosyasının sınırını çizer, ApiObject içerik taşır. Bu üçlünün üzerine diğer her şey kurulur.

L1 dünyası cdk8s import ile üretiliyor

Synth çıktısı saf Kubernetes YAML'ı olduğu için mevcut GitOps akışınıza doğrudan oturuyor. ArgoCD ya da Flux gibi araçlar üretilen manifestoları her zamanki gibi izlemeye devam ediyor; CDK8s sadece üretim katmanında duruyor, runtime'a hiçbir şey enjekte etmiyor. Bu da vendor lock-in riskini ciddi ölçüde azaltıyor: yarın CDK8s'ten vazgeçseniz bile elinizde son üretilmiş YAML'lar kalıyor ve cluster hiçbir şey hissetmiyor. Kustomize veya Helm ile karşılaştırıldığında en belirgin fark, şablonlama yerine gerçek bir programlama dilinin tüm araçlarını - test framework'leri, linter'lar, IDE tamamlama - kullanabiliyor olmanız.

Her Kubernetes nesnesi için elle sınıf yazmak anlamsız olurdu. cdk8s import komutu, Kubernetes API tanımlarından otomatik kod üretir. Sonuç, Kube önekiyle adlandırılan sınıflardır: KubeDeployment, KubeService, KubeIngress gibi. Bu sınıflar Kubernetes API yüzeyinin birebir yansımasıdır; alan adları, spec yapısı ve tipler API şemasından gelir. Yeni bir Kubernetes sürümüne geçmek istediğinizde import komutunu tekrar çalıştırıp kodu yeniden üretirsiniz.

import { KubeDeployment } from "./imports/k8s";

new KubeDeployment(this, "web", {
  spec: {
    replicas: 3,
    template: {
      spec: {
        containers: [
          { name: "nginx", image: "nginx:1.27" }
        ]
      }
    }
  }
});

Kurulum tarafında CLI aracı global olarak kurulur:

npm install -g cdk8s-cli
cdk8s init app --language typescript
cdk8s synth

init komutu proje iskeletini, synth ise dist dizinine YAML dosyalarını yazar. Proje yapılandırması cdk8s.yaml dosyasında tutulur; dil, sentez komutu ve import kaynakları bu dosyada izlenir.

cdk8s-plus ile daha az seremoni

Test tarafında da ciddi kazanım var. Üretilen manifestoları snapshot testlerle kilitleyebilir, bir refaktörün beklenmedik değişiklik üretip üretmediğini CI'da otomatik yakalayabilirsiniz. Jest ya da pytest ile chart'larınızı birim testine tabi tutmak, YAML diff'lerini gözle kontrol etmekten çok daha güvenilir. Ayrıca cdk8s import komutuyla mevcut CRD'lerinizden tip tanımları üretebildiğiniz için özel operatörlerinizin kaynaklarını da aynı tip güvenliğiyle yönetebiliyorsunuz.

Ham API yansımaları güçlü ama ayrıntılı. cdk8s-plus kütüphanesi, güncel sürümlerde yüksek seviye soyutlar sunar: Deployment, Service, Job gibi nesneler makul varsayılanlarla gelir. Kütüphanenin adlandırması da Kubernetes sürümleriyle hizalıdır; cdk8s-plus-27 paketi Kubernetes 1.27 API yüzeyini hedefler. Bu sayede kullandığınız soyutlamanın hangi küçük sürüme karşılık geldiğini adından okursunuz.

import { Deployment } from "cdk8s-plus-27";

const web = new Deployment(chart, "web", {
  containers: [
    { image: "nginx:1.27", portNumber: 80 }
  ]
});

web.exposeViaService();

Bu örnekte port tanımı, container ve service bağlantısı tek noktadan yönetiliyor. Elle YAML yazarken dört ayrı yerde dokunmanız gereken alanlar, tek bir çağrıya iniyor.

Test ve sentez akışı

Öğrenme eğrisi açısından bakınca, hali hazırda TypeScript veya Python bilen bir ekip için geçiş neredeyse pürüzsüz. Constructs kavramı AWS CDK'dan tanıdık geliyor ve dokümantasyon örnekleri pratik senaryolara odaklı. Küçük bir tavsiye: projeye tek bir chart ile başlayın, mevcut bir deployment'ınızı CDK8s'e taşıyıp üretilen YAML'ı mevcut haliyle diff'leyerek ilerleyin. Bu yaklaşım hem güven veriyor hem de abstraction seviyenizi kademeli artırmanıza izin veriyor.

Sentez işlemi kümeden bağımsızdır; credential gerekmez, tamamen yerel çalışır. Bu, birim test yazmayı da kolaylaştırır. Testing yardımcı sınıfı ile chart oluşturup sentezlenen nesneleri denetleyebilirsiniz:

import { Testing } from "cdk8s";

const app = Testing.app();
const chart = new MerhabaChart(app, "test");
console.log(Testing.synth(chart));

Üretilen YAML, GitOps araçlarıyla doğal biçimde uyumludur. Depoya gönderilen dist çıktısını Argo CD ya da Flux okuyabilir; isterseniz sentez çıktısını doğrudan kubectl apply ile kümeye verebilirsiniz. CDK8s kümenize hiçbir şey kurmaz, operatör çalıştırmaz. Çıktı düz YAML olduğu için mevcut akışınız bozulmaz.

Sürüm uyumunu ciddiye alın

Sonuç olarak CDK8s, manifest yönetimini şablonlama probleminden yazılım mühendisliği problemine dönüştürüyor. Büyük ve çok ortamlı Kubernetes kurulumlarında bu dönüşümün getirisi net: daha az tekrar, derleme zamanı hata yakalama, gerçek test edilebilirlik ve GitOps ile tam uyum. Tek servisli küçük kurulumlar için hala düz YAML yeterli olabilir, ancak manifesto sayınız arttıkça CDK8s'e geçiş maliyeti hızla kendini amorti ediyor.

cdk8s ve cdk8s-plus hızlı gelişen projeler. Soyutlama API yüzeyi sürümler arasında değişebiliyor, kütüphane major sürümleri geçişlerde kırılmalara yol açabiliyor. Kilitlediğiniz sürümün dokümantasyonunu okuyun; blog yazısında gördüğünüz bir örnek, elinizdeki sürümde farklı parametre adı taşıyor olabilir.

Küçük bir proje için YAML yeterli olabilir. Onlarca deployment, ortam bazlı farklar ve tekrar eden kalıplar devreye girdiğinde ise kod tarafına geçmek geri dönüşü zor olmayan bir rahatlama getiriyor.

Kurulum ve ilk proje

Başlangıç için Node.js tarafında npm install -g cdk8s-cli yeterli. cdk8s init typescript-app komutu size hazır bir iskelet proje çıkarıyor: package.json, tsconfig ve örnek bir main.ts dosyası. Python tercih edenler için cdk8s init python-app aynı yapıyı pipenv/poetry düzeniyle kuruyor. İlk synth denemesi için cdk8s synth komutunu çalıştırdığınızda dist/ klasörü altında hazır YAML dosyanızı buluyorsunuz.

Örnek bir deployment tanımı kabaca şöyle görünüyor: Chart sınıfından türeyen bir sınıf içinde k8s.Deployment nesnesi oluşturuyor, container image, port ve environment değişkenlerini constructor parametresi olarak geçiyorsunuz. IDE'niz her alanın tipini bildiği için yanlış bir alan adı yazdığınızda daha kodu kaydetmeden kırmızı çizgi geliyor. Bu deneyim, YAML içinde string olarak anahtar aramaktan çok farklı.

Çok ortamlı yapılandırma

Gerçek dünyada aynı uygulamanın dev, staging ve prod kopyaları küçük farklarla yaşar. CDK8s'te her ortam için ayrı bir App/Chart instance'ı oluşturup ortama özel değerleri parametre olarak enjekte edebilirsiniz. Environment değişkenlerinden, JSON config dosyalarından ya da merkezi bir config servisinden beslenen tek bir kod tabanı üç ortamın manifestosunu da tutarlı üretir. YAML dünyasında bu iş genelde kustomize overlay katmanlarıyla çözülür; çalışır ama katman arttıkça hangi değerin nereden geldiğini izlemek zorlaşır. Kod tarafında ise sadece fonksiyon parametreleri vardır.

Dikkat edilmesi gerekenler

Her araç gibi CDK8s'in de sınırları var. Ekipte hiç programlama deneyimi olmayan salt operasyon profilleri için başlangıç eşiği YAML'dan yüksek. Ayrıca üretilen YAML'ı elle düzenleyip cluster'a apply etmek anti-pattern: bir sonraki synth'te değişiklikleriniz uçar. Kural basit - değişiklik her zaman kodda yapılır, synth ve apply pipeline işidir. Bir de synth adımını CI'a koymayı unutmayın; aksi halde geliştiricinin yerel makinesi tek doğruluk kaynağı haline gelir ki bu da GitOps felsefesiyle çelişir.

Helm ve Kustomize ile karşılaştırma

Helm uzun süredir fiili standart ama template yaklaşımı doğası gereği kırılgan: Go template içinde girintileri korumak, koşullu blokların ürettiği YAML'ın her dalda geçerli kalmasını sağlamak ciddi dikkat istiyor. values.yaml üzerinden gelen bir tip hatası ancak render sonrası ortaya çıkıyor. Kustomize daha sade ama overlay mantığında bir değeri override eden üç katman üst üste binince nihai çıktının ne olacağını kafada canlandırmak zorlaşıyor. CDK8s bu iki yaklaşımın dışında duruyor: şablon yok, patch yok; sadece nesneler, koşullar ve döngüler var. Hata varsa synth aşamasında, çoğu zaman daha derleme anında yakalanıyor.

Operasyonel entegrasyon önerileri

Üretim ortamına alırken önerilen akış şu: geliştirici kodu değiştirir, CI synth çalıştırıp üretilen YAML'ı ayrı bir Git reposuna commit eder, ArgoCD o repoyu izleyip cluster'a uygular. Böylece cluster'a giden her değişiklik denetlenebilir bir Git geçmişi taşır ve geri alma işlemi tek bir revert commit'ine indirgenir. Ayrıca synth çıktısını CI'da kubeval ya da kubeconform gibi doğrulayıcılardan geçirmek, API deprecasyonlarını erkenden yakalamanızı sağlar. OPA/Gatekeeper policy'lerinizi de aynı aşamada dry-run ederek güvenlik ihlallerini daha cluster'a ulaşmadan engelleyebilirsiniz.

Secrets yönetiminde de disiplin şart: CDK8s koduna asla düz secret gömmeyin. Sealed Secrets, External Secrets Operator ya da SOPS ile entegre çalışın; kodunuz sadece secret referanslarını üretsin, gerçek değerler şifreli kalsın.

Açık kaynak

GitHub projeleri

Tümünü gör
wireguard-server-panel

WireGuard VPN sunucu paneli - İstemci yönetimi, QR kodları ve trafik istatistikleri için kendi sunucunuzda barındırılan web kullanıcı arayüzü (fork, aktif olarak geliştirilmekte)

Go

Laravel-NDFirewall

Rota Kapsamlı Laravel WAF - RCE, SQLi, XSS ve SSRF algılama özelliklerine sahip hafif bir Web Uygulaması Güvenlik Duvarı

PHP

Trustsslroot

Tek komutla çalışan özel PKI oluşturucu - Kendi kendine imzalanmış kök CA ve sertifikaları anında oluşturun

Go

node_exporter

Hafif sistem metrikleri aktarıcısı - Güvenli erişim kontrolüne sahip, Linux için durum bilgisi barındırmayan tek dosya tabanlı izleme hizmeti

Rust

ipReconary

IP keşif ve alt ağ analiz aracı - Hızlı ağ taraması ve IP istihbarat toplama

Rust

Cloudfiltred

Cloudflare IP beyaz liste güvenlik duvarı - 80/443 numaralı bağlantı noktalarını yalnızca Cloudflare IP'leriyle sınırlayarak kaynak sunucunuzu doğrudan saldırılara karşı koruyun

Rust

LoadAlertTracker

Hafif sistem yükü izleme arka plan programı - Eşik değerleri aşıldığında Telegram, Discord ve Mattermost üzerinden gerçek zamanlı uyarılar

Rust

ctCertWatch

Sertifika Şeffaflığı günlüğü izleyicisi - Kimlik avı alan adlarını, marka taklitçiliğini ve yetkisiz SSL sertifikalarını gerçek zamanlı olarak tespit edin

Rust

DDNS-FW

Dinamik DNS Güvenlik Duvarı - DDNS aracılığıyla değişen IP adreslerini takip edin ve güvenli erişim kontrolü için güvenlik duvarı kurallarını otomatik olarak güncelleyin

Rust