30 Eylül 2025 Salı

Docker Buildx ile Çok Mimarili İmaj Oluşturma ve Cosign ile İmzalama (Güncel Rehber)

Giriş

Apple Silicon (ARM64) cihazların yaygınlaşması ve edge sunucuların çoğalmasıyla, tek bir mimariye derlenmiş konteyner imajları hızla demode oldu. Üretim ortamında aynı uygulamayı hem linux/amd64 hem de linux/arm64 üzerinde sorunsuz çalıştırmak için Docker Buildx ile çok mimarili (multi-arch) imaj üretmek artık bir zorunluluk. Bu yazıda, Buildx’i etkinleştirme, çok mimarili push, önbellek optimizasyonu ve imaj imzalama (Sigstore Cosign) adımlarını pratik ve güncel bir yaklaşımla anlatıyorum.

Neden Çok Mimarili İmaj?

M1/M2/M3 Mac’lerde lokal geliştirme yapıp, üretimde x86_64 (amd64) sunuculara deploy etmek en yaygın senaryo. Multi-arch sayesinde tek bir etiket ile iki mimariyi de içeren bir manifest yayınlarsınız; docker pull işlemi çalıştığı platforma uygun katmanı otomatik indirir. Böylece ayrı Dockerfile’lar, ayrı registry etiketleri ve karmaşık akışlar ortadan kalkar.

Önkoşullar

- Docker 20.10+ ve BuildKit etkin (varsayılan).
- QEMU emülasyonu için binfmt kurulumu (host’ta veya builder içinde).
- Bir container registry (Docker Hub, GHCR, ECR vb.).
- Opsiyonel: İmaj imzalama için Cosign ve SBOM üretimi.

Buildx’i Etkinleştirme ve Binfmt Kurulumu

Önce Buildx sürümünüzü kontrol edin: docker buildx version. Yeni bir builder oluşturup varsayılan yapın: docker buildx create --name multi --use. Gerekirse platform emülasyonu için docker run --privileged --rm tonistiigi/binfmt --install all komutunu çalıştırın. Bu adım, ARM64 makinede amd64 image derlemek gibi çapraz mimari senaryoları mümkün kılar.

Tek Komutta Çok Mimarili İmaj Üretme

Proje dizininizde basit bir Dockerfile olduğunu varsayalım. Multi-arch build ve push için şu kalıbı kullanabilirsiniz: docker buildx build --platform linux/amd64,linux/arm64 -t kullanici/uygulama:1.0 --push . Bu komut, her iki mimari için ayrı katmanlar üretir ve registry’e tek bir manifest altında yükler. Test etmek için docker buildx imagetools inspect kullanici/uygulama:1.0 çıktısında iki platformu görmelisiniz.

Performans ve Önbellek İpuçları

Yapı sürelerini kısaltmak için BuildKit cache kullanın. Registry tabanlı önbellek için: --cache-to type=registry,ref=kullanici/uygulama:cache,mode=max ve --cache-from type=registry,ref=kullanici/uygulama:cache seçeneklerini ekleyin. Ayrıca, Dockerfile’ı katman dostu yazmak (bağımlılıkları erken kopyalamak, --mount=type=cache kullanımı, çok aşamalı derleme) build sürelerini dramatik şekilde azaltır.

CI/CD’de Otomasyon (GitHub Actions Örneği)

CI’da tipik akış: checkoutdocker/setup-qemu-action ile QEMU → docker/setup-buildx-action ile Buildx → registry’ye login → docker buildx build --platform linux/amd64,linux/arm64 --push. Sürüm etiketlerini v1.2.3, latest ve commit SHA gibi çoklu tag’lerle birlikte yayınlamak, tüketicilerin sağlam bir sürüm stratejisi izlemesine yardımcı olur.

Güvenlik: Cosign ile İmaj İmzalama ve SBOM

Supply chain güvenliği artık lüks değil. Cosign ile imajlarınızı imzalayarak, imajın sizden çıktığını kanıtlayabilirsiniz. Adımlar basit: cosign generate-key-pair ile bir anahtar çifti üretin; cosign sign --key cosign.key kullanici/uygulama:1.0 ile imzalayın; doğrulama için cosign verify --key cosign.pub kullanici/uygulama:1.0 çalıştırın. Build aşamasında SBOM eklemek için Buildx’in --sbom=true ve --provenance=mode=max seçeneklerini kullanabilir, yazılım bileşen envanterini otomatik üretip imajla ilişkilendirebilirsiniz.

Yaygın Hatalar ve Çözüm Yolları

- “no match for platform in manifest”: Multi-arch manifest push edilmemiş olabilir; --push bayrağını ve --platform listesini kontrol edin.
- Temel imaj arm64 yok: Kullandığınız base image’in her iki mimari için resmi desteği olduğundan emin olun. Örneğin alpine, debian ve ubuntu çoğunlukla multi-arch sunar.
- Yavaş build: QEMU emülasyonu doğal olarak yavaştır; mümkünse native runner kullanın (amd64 için amd64 runner). Cache’i registry’ye yazmayı ve tekrar kullanmayı unutmayın.
- İmza doğrulanmıyor: Doğru public key kullandığınızdan ve imzanın ilgili etikete uygulandığından emin olun. CI ortamında key yönetimi için OIDC ile keyless imzalama da değerlendirilmelidir.

En İyi Uygulamalar

- Tag stratejisi: semver (+ latest), commit SHA ve platform bağımsız tek etiket kullanın.
- Reproducible build: Sabit bağımlılık versiyonları ve belirli builder sürümleri seçin.
- Güvenlik: İmza ve SBOM’u pipeline’ın ayrılmaz parçası haline getirin, hatalı doğrulamada deploy’u durdurun.
- Gözlemlenebilirlik: Build süreleri, cache isabet oranı ve başarısızlık nedenlerini CI’da raporlayın.

Sonuç

Docker Buildx, çok mimarili konteyner üretimini günlük pratiğin doğal bir parçası haline getiriyor. Doğru yapılandırmayla tek komutta amd64 ve arm64 için imaj üretip push edebilir, CI/CD’de otomatikleştirip, Cosign ile imzalayarak supply chain güvenliğini güçlendirebilirsiniz. Bu yaklaşım, hem geliştirici deneyimini iyileştirir hem de üretim ortamlarında taşınabilirlik ve güvenilirliği artırır.

29 Eylül 2025 Pazartesi

Ollama ve ChromaDB ile RAG: Kendi Verinizle Yerel Yapay Zekâ Sohbet Botu Nasıl Kurulur?

RAG nedir ve neden önemli?

Retrieval-Augmented Generation (RAG), bir dil modelinin cevap üretmeden önce bir vektör veritabanından ilgili parçaları geri çağırdığı, bu sayede daha doğru ve kaynaklı yanıtlar ürettiği bir yaklaşımdır. Güncel kurumsal ihtiyaçlarda gizlilik, maliyet kontrolü ve özelleştirme kritik hale geldiği için RAG, özellikle şirket içi dokümanlar, bilgi tabanları ve politikalar üzerinde çalışan sohbet botları için en verimli yöntemlerden biri olarak öne çıkıyor.

Bu rehberde, tamamen yerel çalışan bir kurulumla Ollama (yerel LLM çalıştırma), ChromaDB (vektör veritabanı) ve Python kullanarak adım adım bir RAG sistemi kurulumu yapacağız. Amaç, Türkçe metinlerle yüksek doğrulukta, düşük gecikmeli ve veri gizliliği korunan bir sohbet deneyimi sunmak.

Gerekenler ve mimari

Bileşenler: Ollama (Llama 3 veya benzeri açık kaynak model), ChromaDB (kalıcı vektör deposu), bir gömme (embedding) modeli (örn. intfloat/multilingual-e5-base), Python 3.10+, LangChain veya minimal kendi kodunuz. İsteğe bağlı olarak PDF/Word dosyaları için pypdf veya docx desteği ekleyebilirsiniz.

Akış: Dokümanları parçalara ayır → Embedding ile vektörleştir → ChromaDB’de indeksle → Soru geldiğinde benzer parçaları getir → Model için talimat şablonuna (prompt) enjekte et → Yanıtı oluştur ve kaynakları göster.

Kurulum adımları

1) Ollama’yı kurun. Resmi site üzerinden işletim sisteminize uygun paketi indirin. Model indirmek için komut satırında şu adımı uygulayın:
ollama pull llama3
Ardından test amaçlı kısa bir deneme yapabilirsiniz:
ollama run llama3

2) Python ortamını hazırlayın. Ayrı bir sanal ortam tercih edin:
python -m venv .venv && source .venv/bin/activate (Windows için .venv\Scripts\activate)
pip install chromadb sentence-transformers langchain langchain-community pypdf

Veri hazırlığı: parçalama ve temizleme

İyi bir RAG’in temeli, doğru parça boyutları ve temiz veridir. Türkçe belgelerde 300–500 token’lık parçalar pratikte iyi sonuç verir. Parçaları ayırırken başlık bilgilerini ve içerik konusunu korumaya çalışın. Örneğin bir politika belgesinde bölüm başlığını her parçaya meta veri olarak ekleyin. Bu, hem geri çağırmayı hem de kaynakları kullanıcıya göstermeyi kolaylaştırır.

Temizlik aşamasında gereksiz boşlukları, tekrar eden sayfa altbilgilerini ve tablo görsellerinden gelen çöp metinleri temizleyin. PDF okuyucu olarak pypdf kullanabilir, Markdown veya HTML dokümanlarını doğrudan metne dönüştürebilirsiniz.

ChromaDB ile vektör indeksleme

Embedding için çok dilli ve Türkçe performansı yüksek bir model seçin. “intfloat/multilingual-e5-base”, hız/doğruluk dengesiyle güvenilir bir tercih. Basit bir akış şöyle olabilir: Belgeleri oku → Böl → Her parça için embedding hesapla → ChromaDB’ye “persist_directory” ile kalıcı olarak yaz. Bu sayede uygulama yeniden başladığında indeksi tekrar oluşturmadan kullanabilirsiniz.

Koleksiyonlarınızı konuya göre ayırın (örn. “insan_kaynaklari”, “urun_dokumantasyonu”). Meta veriye kaynak adı, sayfa numarası, bölüm ve tarih gibi alanlar eklemek, yanıtların izlenebilirliğini artırır.

Sorgulama: RAG adım adım

Kullanıcıdan gelen soruyu önce bir sorgu embedding’ine dönüştürün, ardından ChromaDB’den en ilgili 3–5 parçayı çekin. Bu parçaları modelinize şu yapıda verin: kısa bir talimat + kullanıcı sorusu + “bağlam” bölümü (geri çağrılan parçalar). Örnek şablon yaklaşımı: “Aşağıdaki bağlamdan faydalanarak soruya kısa ve kaynaklı bir yanıt ver. Bağlamda yoksa tahmin yürütme.”

Ollama tarafında llama3 modelini çağırırken sıcaklık (temperature) düşük (0.1–0.3) tutulduğunda halüsinasyon azalır. Yanıtın sonuna “Kaynaklar” başlığı ile geri çağrılan parçaların referanslarını eklemek, güven inşa eder ve SEO açısından “uzman” hissiyatı yaratır.

İyileştirme: yeniden sıralama ve çoklu sorgu

Bazı senaryolarda temel benzerlik araması yeterli olmaz. Açık kaynak yeniden sıralayıcılar (örn. bge-reranker-large) ile ilk 20 sonucu alıp en iyi 5’ini rerank ederek doğruluğu yükseltebilirsiniz. Ayrıca multi-query tekniği ile kullanıcı sorusunu farklı biçimlerde genişletip (eş anlamlılar, farklı bağlamlar) birleştirilmiş sonuçlar elde etmek de hatırlamayı artırır.

Soru ön-işleme katmanında yazım hatalarını düzeltmek, alan terimlerini sözlükten normalleştirmek ve tarih-sayı gibi varlıkları standart forma getirmek, özellikle kurumsal dokümanlarda fark yaratır. Halüsinasyonları azaltmak için “sadece bağlamdan yanıt ver, bağlam yoksa ‘yok’ de” gibi net kurallar koyun.

Performans, güvenlik ve üretime alma

CPU ile başlayıp gerekirse GPU’ya geçin. Düşük bellekli sistemlerde quantized (örneğin Q4_0) model varyantları iyi sonuç verir. ChromaDB tarafında kalıcı dizin SSD üzerinde olmalı ve düzenli olarak koleksiyon boyutu ile gecikmeyi izleyin. Top_k değerini 3–8 arasında test ederek doğruluk/performans dengesini bulun.

Üretim ortamında bir FastAPI uç noktası ile sorgulama zincirinizi sunabilirsiniz. Yanıtları ve kullanılan kaynakları log’layarak kalite ölçümü yapın. Kişisel veriler içeren dokümanlarda yerel çalışmanın avantajı büyüktür; ağ dışına veri çıkarmadan kurumsal uyumluluk hedeflerine yaklaşabilirsiniz.

Sonuç

Ollama + ChromaDB ile kurulan yerel RAG yığını, maliyeti düşük, gizliliği yüksek ve yönetilebilir bir yapay zekâ çözümü sunar. Doğru parça boyutu, iyi bir embedding modeli ve dikkatli şablonlama ile Türkçe içerikte dahi oldukça isabetli yanıtlar elde edebilirsiniz. Bu rehberi temel alarak önce küçük bir pilot oluşturun, ardından veri kapsamını ve değerlendirme metriklerini (doğruluk, geri çağırma, MRR) aşamalı olarak genişletin. Böylece güncel ve ileri seviye bir deneyimi, tamamen kendi verinizle kontrol ederek hayata geçirebilirsiniz.

28 Eylül 2025 Pazar

HTTP/3 ve QUIC Etkinleştirme Rehberi: Nginx ve Cloudflare ile Daha Hızlı Web

Giriş

Web sitenizi hızlandırmanın en etkili yollarından biri, HTTP/3 ve QUIC protokolünü devreye almak. 2024 ve sonrasında modern tarayıcıların büyük bölümü HTTP/3’ü yerleşik destekliyor ve başta mobil kullanıcılar olmak üzere gecikmeye duyarlı senaryolarda ciddi kazanımlar sağlıyor. Bu rehberde, HTTP/3 (QUIC) nedir, neden önemlidir ve Cloudflare ile Nginx üzerinde nasıl etkinleştirilir adım adım anlatıyorum. Ayrıca doğru test ve ölçüm yöntemleriyle kurulumun gerçekten işe yarayıp yaramadığını nasıl doğrulayabileceğinizi paylaşıyorum.

HTTP/3 ve QUIC Nedir, Neden Önemli?

HTTP/3, Google’ın QUIC protokolü üzerine inşa edilen ve TCP yerine UDP kullanan modern bir HTTP sürümüdür. Paket kaybı durumunda daha hızlı toparlanma, bağlantı göçü (Wi‑Fi’dan hücresel ağa geçerken bağlantının kopmaması), başlık sıkıştırması (QPACK) ve 0‑RTT gibi özelliklerle özellikle mobil ve yüksek gecikme senaryolarında daha düşük TTFB ve daha tutarlı yükleme süreleri sağlar.

HTTP/3 devreye alındığında siteniz HTTP/2 ve HTTP/1.1’e geriye dönük uyumluluğu korur. Yani destekleyen tarayıcılar otomatik olarak h3 kullanırken, diğerleri mevcut protokollere düşer. Bu da canlıya geçişte riskleri minimize eder.

Önkoşullar ve Uyum

- Sunucu veya CDN tarafında TLS 1.3 etkin olmalı. HTTP/3, TLS 1.3 gerektirir.

- Güvenlik duvarınızda UDP 443 açık olmalı. QUIC, TCP yerine UDP üzerinde çalışır.

- Tarayıcılarınız güncel olmalı. Chrome, Edge, Safari ve Firefox’un güncel sürümleri HTTP/3’ü destekler.

Cloudflare Üzerinden HTTP/3’i Açma

1) Cloudflare Paneline girin ve ilgili alan adını seçin. SSL/TLS bölümünde modunuzu “Full (strict)” olacak şekilde ayarlayın. Bu, güvenli uçtan uca bağlantıyı sağlar.

2) “Network” sekmesine gidin ve “HTTP/3 (with QUIC)” seçeneğini aktif edin. Cloudflare kenarlarında Alt-Svc başlığı otomatik olarak eklenecek, tarayıcılar h3’e geçecektir.

3) Güvenlik duvarı kurallarınızın UDP 443 trafiğini engellemediğini doğrulayın. Bazı kurum ağlarında UDP kısıtlı olabilir; gerçek kullanıcıların deneyimi bu durumdan etkilenebilir.

4) Test: Chrome DevTools’u açın (F12), Network sekmesinde “Protocol” sütununu görünür yapın. Sayfanızı yenileyin; isteklerin “h3” olarak geldiğini görmelisiniz. Alternatif olarak curl ile “curl -I --http3 https://alanadiniz.com” komutunu deneyebilirsiniz.

Nginx ile (Origin) HTTP/3 Yayını

Cloudflare kullanmıyorsanız veya origin’den doğrudan HTTP/3 sunmak istiyorsanız Nginx’in HTTP/3 desteğini etkinleştirmeniz gerekir. Nginx 1.25+ ile QUIC/HTTP/3 desteği mevcuttur ancak uygun şekilde derlenmiş paket (BoringSSL/QuicTLS ile) kullanmanız veya dağıtımınızın hazır paketlerini tercih etmeniz gerekir. Alternatif olarak Caddy gibi H3’ü daha kolay etkinleştiren sunucular da tercih edilebilir.

Nginx tarafında örnek bir yaklaşım: 443’te UDP ve TCP dinleyin, TLS 1.3’ü zorunlu kılın ve tarayıcıları HTTP/3’e yönlendirmek için Alt-Svc başlığı ekleyin. Yapılandırma mantığı şu şekildedir: 1) “listen 443 quic reuseport;” satırıyla QUIC’i açın. 2) “listen 443 ssl http2;” satırıyla H2 geri dönüşünü sağlayın. 3) “ssl_protocols TLSv1.3;” ile TLS 1.3’ü zorunlu tutun. 4) “add_header Alt-Svc 'h3=":443"; ma=86400';” başlığıyla tarayıcıya H3 desteğini duyurun. 5) Geçerli bir “ssl_certificate” ve “ssl_certificate_key” tanımlayın.

Değişikliklerden sonra Nginx’i yeniden yükleyin ve curl ile “--http3” bayrağını kullanarak test edin. Ayrıca tarayıcı geliştirici araçlarında protokol sütununu kontrol ederek canlı doğrulama yapabilirsiniz.

Performans Ölçümü ve Doğrulama

- Laboratuvar testleri: WebPageTest üzerinde “Advanced Settings” kısmından “HTTP/3 allowed” seçeneği ile koşun, TTFB ve “First Byte Out” metriklerini karşılaştırın. Lighthouse ve Chrome User Timing ile de sayfa içi işaretleri gözlemleyin.

- Gerçek kullanıcı verisi (RUM): Eğer mümkünse tarayıcı API’lerinden (PerformanceNavigationTiming) TTFB ve “connection type” bilgilerini toplayın. Mobil ağlarda H3 farkı daha belirgin çıkar.

- Doğrulama araçları: https://http3check.net ve https://quic.rocks gibi siteler hızlı doğrulama sunar. Cloudflare kullanıyorsanız Analytics > Performance bölümünde HTTP/3 istek yüzdesini görebilirsiniz.

Yaygın Sorunlar ve Çözümler

- UDP 443 kapalı: Birçok kurum veya ISS, UDP’yi kısıtlayabilir. Sunucu ve ağ sınırlarınızda bu portun açık olduğundan emin olun.

- Eski TLS yapılandırması: HTTP/3 sadece TLS 1.3 ile çalışır. Orijin veya CDN tarafında TLS 1.2’ye zorlayan kurallar mevcutsa kaldırın.

- Alt-Svc gecikmesi: Tarayıcılar Alt-Svc keşfini önbelleğe alır. İlk ziyarette HTTP/2, sonraki ziyaretlerde HTTP/3 görebilirsiniz. Testleri birden çok yenilemeyle yapın.

- Orijin ve CDN çakışması: Hem CDN hem orijin H3 sunuyorsa, tünelleme ve başlıklar beklenmedik etkileşime girebilir. Genellikle CDN üzerinden H3 sunmak en basit ve tutarlı yaklaşımdır.

Sonuç

HTTP/3 ve QUIC, özellikle mobil ve yüksek gecikmeli ortamlarda sitenizin algılanan hızını artırır, paket kaybından daha az etkilenir ve bağlantı değişimlerinde kullanıcı deneyimini korur. Cloudflare gibi bir CDN ile etkinleştirmek yalnızca birkaç tıklama sürer; orijin üzerinde Nginx ile kurulum ise biraz daha teknik olsa da kalıcı bir kazanım sağlar. Kurulumu tamamladıktan sonra doğru ölçümlerle etkiyi doğrulayın; TTFB, ilk boyama ve etkileşime geçiş metriklerinde genellikle kayda değer iyileşmeler göreceksiniz.

27 Eylül 2025 Cumartesi

WebGPU ile Tarayıcıda Makine Öğrenmesi: ONNX Runtime Web ile GPU Hızlandırmalı Görüntü Sınıflandırma

Giriş

WebGPU, tarayıcıda modern grafik ve hesaplama iş yüklerini donanıma yakın performansla çalıştırmaya imkan tanıyor. Bu makalede, ONNX Runtime Web kullanarak WebGPU üzerinde GPU hızlandırmalı bir görüntü sınıflandırma örneğini adım adım kuracağız. Amaç, ek bir sunucuya gerek kalmadan, tamamen istemci tarafında çalışan ve gerçek zamanlıya yakın tepki veren bir makine öğrenmesi deneyimi elde etmek.

Neden WebGPU ve ONNX Runtime Web?

WebGL veya WASM ile kıyaslandığında WebGPU, paralel iş yüklerini daha verimli planlayarak tensör işlemlerini hızlandırır. ONNX Runtime Web ise aynı model dosyasını hem WebGPU hem WASM üzerinde çalıştırabilen esnek bir yürütme altyapısı sunar. Bu sayede destekli cihazlarda GPU, diğerlerinde otomatik olarak CPU kullanılabilir; uygulama tek kod tabanıyla geniş bir cihaz yelpazesini kapsar.

Ön Koşullar ve Ortam

- Chrome 121+ veya Edge 121+ gibi WebGPU destekli bir tarayıcı kullanın. Firefox’ta Nightly sürümünde dom.webgpu.enabled bayrağıyla çalışır. Safari’de ise güncel sürümler kısmi destek verir. Uygulamayı güvenli kökenden (https veya localhost) barındırın.

- Node.js 18+ ve npm gereklidir. Örnek, vanilla JS ve Vite ile hazırlanacaktır.

Proje Kurulumu

1) Yeni bir proje oluşturun: npm create vite@latest webgpu-ml -- --template vanilla

2) Klasöre girin ve bağımlılıkları ekleyin: cd webgpu-ml && npm i onnxruntime-web

3) Basit bir dizin yapısı oluşturun: /public/model/mobilenetv3.onnx ve etiketler için /public/model/labels.json. ONNX modelini ONNX Model Zoo’dan veya dönüştürdüğünüz bir MobileNetV3 modelinden alabilirsiniz.

Temel Kod: Oturum, Ön İşleme, Çıkarım

Aşağıdaki kod, WebGPU destekli bir tarayıcıda modeli başlatır, bir görüntüyü 224x224’e ölçekler, normalleştirir, tensöre çevirir ve çıkarım yapar. Destek yoksa WASM’e otomatik düşer.

import * as ort from 'onnxruntime-web';
// 1) Oturum oluşturma (GPU + CPU yedekli)
const session = await ort.InferenceSession.create('/model/mobilenetv3.onnx', {
  executionProviders: ['webgpu', 'wasm'],
  graphOptimizationLevel: 'all'
});

async function loadImageToTensor(imgEl) {
  const size = 224;
  const canvas = document.createElement('canvas');
  canvas.width = size; canvas.height = size;
  const ctx = canvas.getContext('2d');
  ctx.drawImage(imgEl, 0, 0, size, size);
  const { data } = ctx.getImageData(0, 0, size, size);
  const mean = [0.485, 0.456, 0.406];
  const std = [0.229, 0.224, 0.225];
  const chw = new Float32Array(1 * 3 * size * size);
  for (let i = 0; i < size * size; i++) {
    const r = data[i * 4] / 255, g = data[i * 4 + 1] / 255, b = data[i * 4 + 2] / 255;
    chw[i] = (r - mean[0]) / std[0];
    chw[i + size * size] = (g - mean[1]) / std[1];
    chw[i + 2 * size * size] = (b - mean[2]) / std[2];
  }
  return new ort.Tensor('float32', chw, [1, 3, size, size]);
}

async function classify(imgEl) {
  const input = await loadImageToTensor(imgEl);
  const feeds = { [session.inputNames[0]]: input };
  const outputMap = await session.run(feeds);
  const logits = outputMap[session.outputNames[0]].data;
  // Softmax ve top-k
  const exps = logits.map(x => Math.exp(x - Math.max(...logits)));
  const sum = exps.reduce((a, b) => a + b, 0);
  const probs = exps.map(e => e / sum);
  const topK = [...probs].map((p, i) => ({ i, p })).sort((a, b) => b.p - a.p).slice(0, 5);
  const labels = await fetch('/model/labels.json').then(r => r.json());
  return topK.map(({ i, p }) => ({ label: labels[i], prob: p }));
}

Performans İpuçları

- FP16 kullanımı: Bazı modelleri yarım hassasiyetle (Float16) çalıştırmak bellek ve bant genişliği kullanımını düşürerek hız kazandırır. Modeliniz FP16’ya dönüştürülmüşse WebGPU’da belirgin fark görebilirsiniz.

- Girdi boyutu: 224x224 yerine 192x192 gibi daha küçük boyutlar deneyerek gecikmeyi azaltın. Bu değişim doğruluk kaybı ile hız kazanımı arasında bir denge gerektirir.

- Ortak önbellek: Modeli uygulama yaşam döngüsü boyunca bir kez yükleyip aynı oturumu tekrar kullanın. Tekrarlı session.create maliyetlidir.

- Grafik optimizasyon seviyesi: graphOptimizationLevel: 'all' çoğu senaryoda iyi sonuç verir. Bazı modellerde extended veya basic de test edilmeli.

- Çalışma zamanında veri kopyalarını azaltın: Canvas’tan aldığınız ImageData yerine WebCodecs API ile VideoFrame kullanmak (destekliyse) dönüşümleri hızlandırabilir.

Uyumluluk ve Geriye Dönük Çalışma

WebGPU her cihazda aynı düzeyde mevcut olmayabilir. executionProviders: ['webgpu', 'wasm'] sıralaması sayesinde GPU destekli tarayıcılarda hızlanır, diğerlerinde WASM’e düşer. Bu yaklaşım üretim ortamında kesintisiz deneyim sağlar. Ayrıca HTTPS ve güvenli bağlam zorunluluğuna dikkat edin; yerel geliştirmede localhost istisnadır.

Hata Ayıklama

- Model giriş/çıkış adları: session.inputNames ve session.outputNames ile doğrulayın; ONNX ihracında katman adları değişmiş olabilir.

- Bellek taşmaları: Büyük modeller mobil cihazlarda bellek sınırlarına takılabilir. Modeli quantize ederek (INT8/UINT8) veya daha hafif mimarilere geçerek çözebilirsiniz.

- WebGPU hataları: Tarayıcı konsolunda validation error mesajlarını kontrol edin. Sürücü veya adaptör sınırlamaları için navigator.gpu.requestAdapter() ile dönen limitleri inceleyin.

Gerçek Hayat Senaryoları

- Ürün arama: Kullanıcı yüklediği fotoğrafla eşleşen kategoriye gerçek zamanlı yönlendirme.

- İçerik güvenliği: Tarayıcıda ön filtreleme yaparak sunucu maliyetini ve gecikmeyi azaltma.

- Eğitim: Etkileşimli ML demoları ve ders materyalleri, laboratuvar kurulumları olmadan, yalnızca bir URL ile erişilebilir.

Sonuç

WebGPU ve ONNX Runtime Web birlikteliği, tarayıcıda makine öğrenmesi için yeni bir performans eşiği oluşturuyor. Doğru model seçimi, hafif ön/son işleme ve dikkatli optimizasyonlarla, mobil dahi pek çok cihazda tatmin edici hızlara ulaşmak mümkün. Bu temel iskeleti kullanarak; nesne tespiti, metinden görüntü üretimi veya konuşma tanıma gibi daha karmaşık senaryolara ilerleyebilirsiniz. Üstelik tümü, kullanıcı verisini cihazdan çıkarmadan, gizlilik dostu bir şekilde.

26 Eylül 2025 Cuma

GitHub Actions ile Docker Buildx Kullanarak Çok Mimarili İmaj (amd64 + arm64) Yayınlama Rehberi

Kapsayıcı tabanlı dağıtımların hızla arttığı günümüzde, tek bir mimariye bağlı kalmak ciddi bir kısıt olabilir. Özellikle bulut sağlayıcılar ve edge cihazları (Raspberry Pi gibi ARM tabanlı sistemler) söz konusu olduğunda, amd64 ve arm64 için tek bir sürüm hattından imaj üretebilmek büyük avantaj sağlar. Bu yazıda, GitHub Actions ve Docker Buildx kullanarak çok mimarili (multi-arch) imajı nasıl inşa edip hem Docker Hub hem de GHCR’ye nasıl yayınlayacağınızı adım adım anlatıyorum.

Neden Buildx? Buildx, BuildKit’i temel alır ve çoklu platform inşa, gelişmiş önbellekleme, yerleşik SBOM/provenance gibi özellikleri etkinleştirir. Bunun anlamı: Tek bir pipeline ile linux/amd64 ve linux/arm64 hedeflerini derleyebilir, tek bir manifest altında birleştirip push edebilirsiniz.

Önkoşullar ve depo ayarları

- GitHub repository’nizde Actions etkin olmalı.
- Docker Hub’a push edecekseniz bir erişim token’ı oluşturun ve GitHub’da Settings > Secrets and variables > Actions altında DOCKERHUB_USERNAME ve DOCKERHUB_TOKEN olarak ekleyin.
- GHCR (GitHub Container Registry) kullanacaksanız, secrets.GITHUB_TOKEN çoğu durumda yeterlidir. Özel bir PAT kullanıyorsanız gerekli scope’lar: write:packages ve read:packages.

Workflow mantığı

Pipeline’da sırasıyla QEMU etkinleştirmesi (arm64 emülasyonu için), Buildx builder kurulumu, metadata/etiket üretimi, cache ayarı, çok mimarili build ve push adımları yer alacak. Ek olarak SBOM ve provenance (inşa kanıtı) bilgilerini de ekleyebiliriz.

Örnek workflow (/.github/workflows/release.yml)

name: release-multi-arch
on:
push:
tags:
- 'v*.*.*'
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
id-token: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
platforms: arm64
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: |
ghcr.io/<kullanici>/<imaj-adi>
<kullanici>/<imaj-adi>
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,value=latest
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push multi-arch
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
provenance: true
sbom: true

Önemli noktalar ve iyi uygulamalar

• QEMU: Yerel runner’ınız x86 ise, arm64 imajı için QEMU emülasyonu gerekir. docker/setup-qemu-action bunu sizin yerinize yapar. Performans, yerel ARM runner’a göre daha düşük olabilir; kritik projelerde self-hosted ARM runner düşünebilirsiniz.

• Metadata ve etiketleme: docker/metadata-action; semver uyumlu etiketleri (v1.2.3, 1.2, latest) otomatik üretir. Böylece kullanıcılarınız ister sürüm sabitlemesi, ister “latest” ile hızlı çekim yapabilir.

• Cache: GHA (GitHub Actions) cache’i ile katmanlar arası hız kazanırsınız. Dockerfile’ınızı cache verimini maksimize edecek şekilde düzenleyin: bağımlılık kurulumunu, sık değişen dosyalardan önce konumlandırmayın. Örneğin, package.json kopyası ve “npm ci” adımları, uygulama kodlarından önce gelmeli.

• Güvenlik: provenance: true ve sbom: true ile tedarik zinciri bilgilerini imaja iliştirebilirsiniz. Cosign ile imzalama eklemek isterseniz OIDC tabanlı keyless imzayı tercih edin; sigstore/cosign-installer ve “cosign sign” adımıyla workflow’u genişletebilirsiniz.

• Çok kayıtlı push: Yukarıdaki örnek aynı anda hem GHCR hem Docker Hub’a push eder. Kimlik bilgileri doğru ise manifest listesi, her iki registry’de de aynı etiketlerle yer alır.

Sorun giderme

• “no match for platform in manifest” hatası: Çekmeye çalıştığınız hedef platform için imaj manifest’i yoktur. buildx ile push sonrası, “docker buildx imagetools inspect <image:tag>” çıktısında amd64 ve arm64 görünmelidir.

• QEMU ile yavaş derleme: Bazı bağımlılıklar (ör. kriptografik kütüphaneler) arm64 derlemede ciddi süre alabilir. Mümkünse çok aşamalı (multi-stage) Dockerfile kullanın ve ağır kısımları önbelleğe alın. Alternatif olarak self-hosted arm64 runner veya BuildKit’in uzak builder modlarını düşünebilirsiniz.

• Önbellek isabeti düşükse: “cache-from: type=gha” etkin olmasına rağmen isabet zayıfsa, Dockerfile adımlarının sıralamasını gözden geçirin. “COPY . .” gibi geniş kapsamlı kopyalar, küçük değişikliklerde bile önbelleği bozabilir. Yalnızca gerekli dosyaları kopyalayın.

• Docker Hub hız limitleri: Anonim veya düşük planlı hesaplarda rate limit’e takılabilirsiniz. Login adımı şarttır. Gerekiyorsa workflow’u yeniden deneme stratejisiyle (retry) sarmalayın.

Performans ve maliyet ipuçları

• Katman sayısını azaltın, gereksiz paketleri temizleyin (apk/apt ile “--no-cache” ve “rm -rf /var/lib/apt/lists/*”).
• Dil ekosistemlerinde üretim odaklı taban imajları (distroless, alpine, slim) tercih edin.
• Çok aşamalı derlemede builder imajını üretim katmanından ayırın; sadece çalışma zamanı için gereken dosyaları kopyalayın.

Sonuç

GitHub Actions ve Docker Buildx ikilisi, tek bir pipeline üzerinden hem amd64 hem de arm64 imajlarını üreterek modern dağıtım ihtiyaçlarınıza güçlü bir yanıt sunar. Doğru önbellekleme, tutarlı etiketleme ve güvenlik metadatalarıyla (SBOM, provenance) birlikte kullanıldığında, CI/CD hattınız hızlı, izlenebilir ve güvenli çalışır. Bu rehberi temel alarak projenizi kolayca ölçeklendirebilir, bulut ve edge senaryolarında tek bir imaj adını kullanarak tüm platformlara rahatlıkla dağıtım yapabilirsiniz.

25 Eylül 2025 Perşembe

Kubernetes Gateway API ile Ingress’ten Geçiş: Adım Adım Rehber ve En İyi Uygulamalar

Özet: Kubernetes’te trafiği yönetmek için yıllardır varsayılan seçenek olan Ingress, karmaşık senaryolarda yetersiz kalabiliyor. Gateway API, modern trafik yönetimi için daha esnek bir model sunuyor: roller ayrımı, zengin yönlendirme kuralları, taşınabilirlik ve genişletilebilirlik. Bu yazıda, Ingress’ten Gateway API’ye geçişi adım adım anlatıyor, örnek tanımlar ve en iyi uygulamalarla destekliyoruz.

Gateway API Nedir ve Neden Geçmeliyim?

Gateway API, Kubernetes’in ağ katmanında kaynak türlerini genişleterek standartlaştırılmış, sağlayıcıdan bağımsız bir trafik yönetim modeli sunar. Başlıca avantajları:

- Rollerin ayrımı: GatewayClass, Gateway ve HTTPRoute/GRPCRoute/TCPRoute nesneleriyle altyapı ve uygulama ekipleri sorumlulukları net şekilde paylaşır.
- Zengin ifade gücü: Header tabanlı yönlendirme, ağırlıklı trafik bölümü, mTLS, yeniden deneme/politikalar için geniş kapsam.
- Taşınabilirlik ve uyumluluk: Birçok sağlayıcı (NGINX, Kong, Istio, Cilium vb.) aynı API’yi destekler.
- Geleceğe uyum: Topluluk tarafından aktif geliştirilen ve conformance testleriyle doğrulanan bir standart.

Ön Koşullar ve Kurulum

Geçişe başlamadan önce Kubernetes 1.26+ ve seçtiğiniz bir Gateway sağlayıcısı (ör. NGINX, Kong, Istio) kurulu olmalı. CRD’leri etkinleştirmek için aşağıdaki komutu uygulayabilirsiniz (sürüm numarasını güncel olanla değiştirin):

kubectl apply -k "github.com/kubernetes-sigs/gateway-api/config/crd?ref=v1.1.0"

Sağlayıcınıza bağlı olarak bir GatewayClass gelir veya siz tanımlarsınız. Sağlayıcı dökümantasyonunda “GatewayClass name” önemlidir; az sonra Gateway nesnesinde bu ismi kullanacağız.

Ingress’ten Gateway API’ye Geçiş: Adım Adım

1) Mevcut Ingress haritasını çıkarın: Kümelerde hangi alan adları, yollar (path), TLS sertifikaları, backend servisleri ve ağırlıklandırmalar kullanılıyor? Bunları listeleyin. Bu, HTTPRoute’lara dönüşümde yol gösterici olacaktır.

2) GatewayClass ve Gateway tanımlayın: Altyapı ekibi bir GatewayClass sağlar. Ardından trafiğin dinleneceği Gateway nesnesi oluşturulur. Örnek bir Gateway mantığı şöyle olabilir:

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: edge-gw
spec:
  gatewayClassName: nginx
  listeners:
  - name: web
    port: 80
    protocol: HTTP
  - name: web-tls
    port: 443
    protocol: HTTPS
    tls:
      mode: Terminate
      certificateRefs:
      - kind: Secret
        name: site-cert

3) HTTPRoute ile yönlendirme oluşturun: Ingress’teki host ve path kurallarını HTTPRoute’a taşıyın. Örnek bir kurgu:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: shop-route
spec:
  parentRefs:
  - name: edge-gw
  hostnames:
  - shop.ornek.com
  rules:
  - matches:
    - path:
      type: PathPrefix
      value: /api
    backendRefs:
    - name: shop-api
      port: 8080

4) Trafik geçişini risksiz yönetin: Canlı geçişte aynı hostname altında iki servis arasında ağırlıklandırma kullanabilirsiniz. Örnek: eski servis %90, yeni servis %10.

- Ağırlıklandırma: backendRefs altında weight alanını kullanın (ör. weight: 90 ve weight: 10).
- Header tabanlı yönlendirme: Sadece belirli kullanıcı grubuna test için X-Canary: true başlığıyla yeni sürümü gösterin.
- Trafik yansıtma (mirror/tee) özelliği sağlayıcıya göre değişir; destekleniyorsa üretim verisini gölgeleme için kullanın.

5) TLS ve güvenlik: Sertifikaları Secret üzerinden terminate edin. Gateway seviyesinde mTLS veya HTTPRoute bazlı politika tanımlarıyla hassas uç noktaları koruyun. Bazı sağlayıcılar ReferenceGrant ile namespace’ler arası güvenli referanslamayı şart koşar.

6) Gözlemlenebilirlik ve hata ayıklama: Gateway ve Route’ların status alanlarını inceleyin. Olay kayıtları (kubectl describe), metrikler (Prometheus), loglar ve sağlayıcı panellerini birlikte kullanın. Uyuşmayan host veya listener isimleri en sık karşılaşılan kaynaklardır.

Ingress ve Gateway API Arasındaki Farkların Özeti

- Ingress tek bir kaynakla çok şeyi yapmaya çalışır; gelişmiş senaryolarda anotasyon bağımlılığı artar. Gateway API ise modülerdir: Gateway (giriş noktası), Route (uygulama yönlendirmesi) ve Policy (davranış) ayrıdır.
- Birden fazla ekip aynı Gateway’i paylaşabilir; uygulama ekipleri sadece kendi HTTPRoute’larını yönetir.
- Trafik türleri (HTTP, TCP, gRPC) için ayrı Route kaynaklarıyla net ayrımlar sağlanır.

En İyi Uygulamalar

- Adım adım geçiş: Tüm Ingress’leri tek seferde taşımak yerine domain veya mikroservis bazlı fazlara bölün.
- İsimlendirme stratejisi: Gateway, listener ve host adlarını tutarlı belirleyin. Ortak bir etiketleme şeması kullanın (ör. environment, team, cost-center).
- Politikaları merkezileştirin: Zorunlu güvenlik ve hız sınırlama (rate limit) kurallarını gateway seviyesinde; uygulama bazlı esnemeleri route seviyesinde yönetin.
- Conformance kontrolü: Sağlayıcınızın Gateway API uyumluluk seviyesi ve desteklediği ek özellikleri önceden doğrulayın.
- Geri dönüş planı: Canary ve header tabanlı yönlendirmeyle geri alma senaryolarını pratik edin.

Yaygın Hatalar ve Çözümler

- 404/Hostname uyuşmazlığı: HTTPRoute içindeki hostnames listesi, gelen isteğin SNI/Host başlığıyla birebir eşleşmelidir.
- Listener uyuşmazlığı: Route’un parentRefs alanındaki isim, ilgili Gateway listener’ı ile aynı port/protokole uygun olmalı.
- Namespace erişimi: Route’un referans verdiği Service farklı namespace’teyse ReferenceGrant gerektirebilir.
- TLS Secret formatı: tls.crt ve tls.key anahtarları doğru yerleştirilmelidir; yanlış format sertifika yüklenmesini engeller.

Sonuç

Gateway API, Kubernetes’te trafik yönetimini modernleştiriyor. İnce ayarlı yönlendirme, ekipler arası sınırların netleşmesi ve sağlayıcı bağımsızlığı sayesinde büyük ve regüle ortamlarda dahi güvenle ölçeklenebiliyor. Mevcut Ingress’lerinizi envanterleyip küçük adımlarla HTTPRoute’lara taşıyarak, TLS ve politikaları sistematik şekilde uyguladığınızda kesintisiz bir geçiş mümkün. Uzun vadede sade operasyon, daha öngörülebilir davranış ve standart bir ağ katmanı kazanırsınız.

24 Eylül 2025 Çarşamba

Ansible 101 - Uygulamalı Başlangıç Rehberi

    Bir master, üç tane de worker olmak üzere 4 ubuntu'dan oluşan basit bir lab kurdum. Master ubuntu makineme ansible yükledim ve ssh public keyleri worker makinelerime kopyaladım. Böylelikle ansible workerlar ile şifresiz doğrudan iletişim kurabilecek. 


SSH key oluşturduğum komut:
ssh-keygen -t rsa -b 4096

Anahtarı worker'lara kopyaladım:
cat ~/.ssh/id_rsa.pub | ssh [email protected] "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"

Multipass tarafı için aşağıdaki adımları uygulamadım: worker'de aşağıdaki kodlar çalıştırılır ve ubuntu user ile master makinede oluşturulan key içeriği manuel eklenir:

ssh key cat

worker ssh key ekleme


Lab için Ansible dizini oluşturdum:
mkdir -p ~/ansible-lab && cd ~/ansible-lab

İlk denemeler için bir envanter dosyası oluşturdum:
vi hosts

Bu dosyanın içeriğini worker'larıma göre doldurdum:
[web]
192.168.1.110

[db]
192.168.1.111

[prod]
192.168.1.112

[all:vars]
ansible_user=ubuntu
ansible_ssh_private_key_file=~/.ssh/id_rsa

İlk ansible komutumu denedim:
ansible all -i hosts -m ping

Bu komut, hosts envanter dosyasında tanımlı tüm sunuculara SSH ile bağlanır ve Ansible’ın ping modülünü çalıştırarak bağlantıyı test eder. Başarılıysa her sunucudan "pong" cevabı döner.

Ansible Ping


Bu komutu bir .sh dosyasına yazıyorum ve sh dosyasını çalıştırarak daha hızlı bir şekilde yanıt almak istiyorum:
vi pingle.sh

Dosya içeriği:
#!/bin/bash
ansible all -i hosts -m ping

Dosyaya çalıştırma izni: 
chmod +x pingle.sh

Test:
./pingle.sh

Worker'larda sudo yetkisi gerektiren komutları çalıştırmak istediğimde ya şifre sormasını sağlamamız gerekiyor yada şifresiz sudo yetkisini her bir workerda tanımlamak gerekiyor. (test ortamı için çok uygun) Örnek üzerinden bakalım. Tüm worker'larıma htop paketini yüklemek istiyorum, şifre sormasını istiyorsam bu komuttan yararlanabilirim:
ansible all -i hosts -m apt -a "name=htop state=present" --become --ask-become-pass

Ancak şifre sormadan doğrudan komutu koşmak için bir kerelik sudo şifresiz yetkisini workerlara tek tek tanımlamam gerekiyor.
echo "ubuntu ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/ubuntu
sudo chmod 440 /etc/sudoers.d/ubuntu

Böylece şimdi koşacağım komutu şifre yazmadan veya girmeden doğrudan worker'larıma gönderebilirim:
ansible all -i hosts -m apt -a "name=htop state=present" --become

Ve aynı anda tüm makinelerime htop kurulumunu yapabildim:

htop

Bunu paket kurulumu adı altında bir .sh dosyasına da dönüştürebiliriz:


package_install.sh dosyası oluşturdum ve içeriğini bu şekilde doldurdum:
#!/bin/bash

# Kurulacak paketin adı (örnek: htop, curl, nginx, vs)
PAKET_ADI="htop"

# Ansible komutu
ansible all -i hosts -m apt -a "name=$PAKET_ADI state=present" --become

Böylece kurmak istediğim farklı paketler olduğunda içerisine girip paket adını güncellemem yeterli olabilir.

Dosyaya çalıştırma izni vermeyi de unutmuyoruz:
chmod +x paket_kur.sh

Şimdi ise ilk Playbook'umuzu deneyelim, birden fazla paket kurulumunu bir yml dosyası ile host'larımıza gönderelim.


vi package_install.yml dosyasını oluşturdum ve aşağıdaki bilgileri ekledim:

---
- name: Paket kurulumları
  hosts: all
  become: yes

  tasks:
    - name: htop kur
      apt:
        name: htop
        state: present

    - name: curl kur
      apt:
        name: curl
        state: present

    - name: git kur
      apt:
        name: git
        state: present

Ardından playbook dosyamı koşmak için bu komutu kullanıyorum:
ansible-playbook -i hosts package_install.yml

Playbook - Package Installation

    Ve böylece tek bir yml dosyasını çalıştırarak ansible sayesinde tüm hosts makinelerime aynı anda birden fazla uygulama kurulumunu gerçekleştirmiş oldum. Makinelere tek tek bağlanmadım, paketleri tek tek kurmayı denemedim ve zaman kaybı yaşamadım.


Tüm makineleri kapatmak için bir .sh dosyası
#!/bin/bash

# Ansible inventory dosyasını belirt
INVENTORY_FILE="hosts"

# Tüm makineleri anında kapat
ansible all -i "$INVENTORY_FILE" -a "/sbin/shutdown now" --become

chmod +x shutdown-all.sh

Tüm makinelerde bir klasör oluşturmak için: create_folder.sh
#!/bin/bash

# Ansible inventory dosyası
INVENTORY_FILE="hosts"

# Uzak makinelerde klasör oluştur
ansible all -i "$INVENTORY_FILE" -m file -a "path=/tmp/yeni_klasor state=directory mode=0755"
chmod +x create_folder.sh

Bir istisna, tüm hostlara değil, özel bir gruba işlem yapmak için ek bir parametre kullanılır:
ansible-playbook -i hosts package_install.yml --limit web

Command modülü ile uptime bilgisini öğrenme:
ansible all -i hosts -m command -a "uptime"

Copy komutu ile dosyaları hostlara kopyalamak:
ansible all -i hosts -m copy -a "src=dosya.txt dest=/tmp/dosya.txt"

uptime

Şimdi ise bir playbook ile hem paket kurulumu hem de bir dosya oluşturarak içerisine veri yazmayı deneyelim:


Playbook 2

- name: Paket kur ve dosya kopyala
  hosts: all
  become: yes
  tasks:
    - name: htop paketini kur
      apt:
        name: htop
        state: present

    - name: Bilgi dosyasını kopyala
      copy:
        content: "Bu dosya Ansible tarafından oluşturulmuştur\n"
        dest: /tmp/ansible_bilgi.txt
        owner: ubuntu
        group: ubuntu
        mode: '0644'

Sırada bir servis kurmak ve o servisin çalışıp çalışmadığını check etmek var:


apache_setup.yml dosyasını oluşturuyorum ve içeriğini aşağıdaki gibi yapıyorum:

- name: Apache kurulumu ve servisi yönetimi
  hosts: all
  become: yes
  tasks:
    - name: Apache2 paketini kur
      apt:
        name: apache2
        state: present
        update_cache: yes

    - name: Apache servisini başlat
      service:
        name: apache2
        state: started
        enabled: yes

Bu servisi sadece web hostlarıma kurmak istedim, o yüzden bu şekilde bir komut koşuyorum:
ansible-playbook -i hosts apache_setup.yml --limit web

Ve servislerin durumunu check etmek istiyorum:

apache2 ansible service check


When kullanarak bir yml dosyasının içerisine koşul ekleyebiliriz. Ancak bunu zaten --limit komutu ile de yapabilyoruz:


- name: Koşullu görev örneği
  hosts: all
  become: yes
  tasks:
    - name: Sadece worker1'de bu dosyayı oluştur
      copy:
        content: "Bu dosya sadece worker1 içindir\n"
        dest: /tmp/worker1_ozel.txt
      when: inventory_hostname == "worker1"

Gruplamayı yml dosyasının içerisinde de yapabiriz, böylelikle when koşulu veya --limit kullanmadan birden fazla görevi aslında yml dosyasında tek tek host gruplarına atamak mümkün:


Yeni bir yml dosyası oluşturdum: group_specific_tasks.yml 
Bu yml dosyası sadece web ve db makinelerime işlem yapacak ve bu işlem örnekteki gibi bir file oluşturma işlemi olacağı gibi, app kurulumu, güncellemesi vs. gibi herhangi bir işlem olabilir:

- name: Web grubuna özel görev
  hosts: web
  become: yes
  tasks:
    - name: Web makinesine özel bilgi dosyası
      copy:
        content: "Bu worker bir WEB sunucusudur.\n"
        dest: /tmp/web_bilgi.txt

- name: DB grubuna özel görev
  hosts: db
  become: yes
  tasks:
    - name: DB makinesine özel bilgi dosyası
      copy:
        content: "Bu worker bir VERİTABANI sunucusudur.\n"
        dest: /tmp/db_bilgi.txt

Ansible Roles Yapısının Kullanımı

    Ansible'da roles, yapılandırmaları görev, değişken, şablon, handler gibi mantıksal klasörlere ayırır.
Gerçek projelerde playbook'lar roles kullanılarak kurulur.

Örneğin webserver için bir role oluşturmak istiyorum, bu durumda aşağıdaki komutu çalıştırıyorum:
ansible-galaxy init roles/webserver

Ansible bu role için kendi özel yapısını oluşturur:


Ansible Roles

Tasks/main.yml içerisine aşağıdaki konfiği girdim:

- name: Apache kur
  apt:
    name: apache2
    state: present
    update_cache: yes

- name: Apache2 servis başlasın ve aktif kalsın
  service:
    name: apache2
    state: started
    enabled: yes

- name: Özel hoşgeldiniz sayfası
  copy:
    content: "Merhaba Hakan! Apache başarıyla çalışıyor.\n"
    dest: /var/www/html/index.html
    owner: root
    group: root
    mode: '0644'

Projeyi çalıştırabilmek için ana dizinimde (benim için ansible lab çalışmalarını yaptığım ve diğer hosts dosyamın bulunduğu yer) site.yml isimli bir dosya oluşturuyorum ve aşağıdaki gibi konfig giriyorum:

- name: Web makinelerine apache kur, servisi başlat, aktif kalsın ve özel hoşgeldin sayfası oluştur.
  hosts: web
  become: yes
  roles:
    - webserver

 Böylelikle site.yml dosyasını playbook ile koştuğumda webserver rolünde daha önce tanımladığım tüm işlemler gerçekleştiriliyor. Daha işlevsel bir yapıya kavuşmuş oluyorum. Her şey tek bir yml dosyasında olmaktansa görev ve sorumluluklara göre yani rollere göre yml dosyalarını aslında ayırmış oluyorum.

ansible-playbook -i hosts site.yml

sudo systemctl status apache2
sudo systemctl restart apache2
ss -tuln | grep :80
sudo ufw allow 80
sudo ufw allow 443
sudo ufw reload
sudo ufw status

    Ve ardından kendi ana bilgisayarımın tarayıcısını kullanarak http://192.168.1.110:80 bağlantısına gitmeyi çalıştığımda worker1 isimli makinemde çalışan apache2 üzerindeki sayfaya ulaşabildim. Ansible ile gönderilen ve sayfa girişine eklenen yazı da karşıma çıkmış oldu. Böylece çalışmayı başarıyla tamamladım.

Apache2 Main Page

Handlers Kullanımına Örnek

    Bu deneme için init komutunu tekrar koştum ve ikinci bir dizin oluşmasını sağladım, ikinci bir role gibi. ansible-galaxy init roles/webroles2-handlers ve ilgili rolü koşmak için yeni bir yml dosyası oluşturarak ilerledim.

Ansible Handlers


    Handlers, bir görev değişiklik algılandığında tetiklenen özel görevlerdir. Genellikle servisleri yeniden başlatmak, yeniden yüklemek gibi işlemler için kullanılır. Bizde Apache web sayfamızın içeriğinde bir değişiklik algılandığında örnek olması için bir tetikleyici kurgulayacağız ve sistem bu değişikliği algılayarak otomatik olarak apache servisini restart edecek. Bu sadece basit bir örnek, ihtiyaca göre buradaki handlers yeteneklerinden farklı şekillerde yararlanılabilir.


roles/webroles2-handlers/tasks/main.yml içerisine bir ekleme yapıyorum, daha önce eklediğimiz görevlere ek olarak:

---
- name: Apache web sunucusunun kurulu olduğundan emin olun
  ansible.builtin.apt:
    name: apache2
    state: present
    update_cache: yes
  become: yes
  notify: restart_apache_service

- name: Ana sayfa içeriğini değiştirin
  ansible.builtin.copy:
    content: "<html><body><h1>Ansible Handler Pratiği Başarılı!</h1></body></html>"
    dest: /var/www/html/index.html
  become: yes
  notify: restart_apache_service

Şimdi ise Handler dosyasını oluşturarak içerisine tetikleyicimizi ekliyoruz:

vi roles/webroles2-handlers/handlers/main.yml

---
- name: restart_apache_service
  ansible.builtin.service:
    name: apache2
    state: restarted
  become: yes

Şimdi ise Playbook'u oluşturalım: vi 11-handlers-web-webroles.yml

---
- name: Web server rolünü çalıştırma
  hosts: web
  roles:
    - webroles2-handlers

Şimdi ise tetikleyiciyi test edebiliriz:
ansible-playbook -i hosts 11-handlers-web-webroles.yml

Handler Ornek


    Bu çıktı bize şunu söylüyor: Ansible, web sayfasının içeriğinin değiştiğini algıladı. Bu değişiklik nedeniyle, playbook'taki diğer görevler tamamlandıktan sonra, tanımladığınız restart_apache_service handler'ını çalıştırdı. Handler başarılı bir şekilde çalışarak Apache'yi yeniden başlattı ve playbook'unuzu hatasız bir şekilde tamamladı.

Jinja2 Şablon Kullanımına Örnek


Öncelikle yeni bir role oluşturuyorum, bu 12. yml file'ım olmuş olacak.

#ansible-galaxy init info_creator

/roles/info_creator/templates/ dizini altında bilgi.txt.j2 isimli bir dosya oluşturdum ve içeriğini aşağıdaki gibi güncelledim:

Burada toplanan verilere aynı zamanda Ansible Facts ismi verilir.

Bu sunucuya ait bilgiler: Hostname: 
{{ ansible_hostname }} 
IP Adresi: {{ ansible_host }} 
İşletim Sistemi: {{ ansible_distribution }} {{ ansible_distribution_version }} 
Tarih: {{ ansible_date_time.iso8601 }}

/tasks/main.yml içerisine de ilgili ana görevimi ekliyorum:

---
- name: Dinamik bilgi dosyasını oluşturun
  ansible.builtin.template:
    src: bilgi.txt.j2
    dest: /home/ubuntu/bilgi.txt
    owner: ubuntu
    group: ubuntu
    mode: '0644'
  become: yes

ve artık playbook'u oluşturup koşabilirim:

#vi 12-create_info_jinja2_file.yml

ve içerisine:

---
- name: Dinamik bilgi dosyasını oluşturma
  hosts: web
  roles:
    - info_creator

Artık playbook'u koştuktan sonra ilgili makinenin /home/ubuntu/ dizininde yeralan bilgi.txt dosyasını kontrol edebilir ve dinamik bir şekilde bu belgenin güncellendiğini görebilirim:

jinja2


    Jinja2 şablonları, statik dosyaları olduğu gibi kopyalamak yerine, dinamik olarak oluşturmanızı sağlar. Bu şablonlar, her sunucuya özel bilgileri (IP adresi, hostname, port gibi) kullanarak yapılandırma dosyalarını otomatik olarak doldurabilir. Örneğin, bir web sunucusu için Apache sanal host yapılandırma dosyası oluştururken ServerName ve DocumentRoot gibi değerleri sunucunun hostname'ine göre dinamik olarak ayarlayabilirsiniz. Bu sayede, farklı sunucular için ayrı ayrı dosyalar oluşturmak yerine tek bir şablonu kullanabilir ve kod tekrarını önleyebilirsiniz. Aynı zamanda veritabanı yapılandırma dosyalarında bellek ayarları gibi değerleri, sunucunun özelliklerine göre belirlemek için de Jinja2 şablonlarından yararlanabilirsiniz.

    Diyelimki zabbix server'ınız var ve zabbix agentları onlarca makineye kurdunuz ve konfigüre ettiniz. Çeşitli nedenlerle zabbix server IP'ni değişti. Gidip tek tek makinelerinizdeki zabbix conf dosyasını düzenlemenize gerek yok, bunu bir yml file ile ansible kullanarak kolaylıkla halledebilirsiniz.

    Bir başka örnek, makinelerinize cronjob ekleyebilirsiniz. Hatta düzenli cronjoblarınız varsa, envanterinize yeni eklenen bir makine olduğunda crontab'ına ilgili jobların eklenmesini de otomatikleştirebilirsiniz. Cronjob yml dosyanızı bir scriptin içerisine yazarsınız ve ilgili scripti de ansible kurulu makinenizin crontab'ine istediğiniz zaman aralığına göre eklerseniz. Bundan böylelikle sadece envanter dosyanızı yani hosts file'ı güncellemeniz yeterli olacaktır. Crontab otomatik zamanı geldiğinde eklenecek.

    Veya farklı bir örnek, NTP sunucusu kurmak istediniz. Bunu elbette Crony ile yapabilirsiniz. Hem kurulumarı hem de ilgili konfigürasyonu ansible ile koşmanız mümkün. Birkaç dakikada tüm makinelerinizin baktığı NTP sunucusunu güncellenir. Ansible bu ve benzeri birden fazla esneklik ve kolaylık sağlıyor. Zaman zaman bazı örnekler paylaşmaya devam edeceğim, şimdilik bu yazıyı burada sonlandırıyorum.