• 29.08.2026 09:26:02
  • Admin Admin

AI destekli yazılım geliştirme akışlarında her pull request için izole preview ortamı kurmayı; Terraform state ayrımı, Kubernetes namespace yaşam döngüsü, k6 ölçümü ve CI/CD temizliğiyle ele alıyoruz.

AI Destekli Yazılım Geliştirmede Geçici Preview Ortamı Tasarımı

AI destekli yazılım geliştirmede preview ortamının sınırları

Bir kod ajanının ürettiği değişikliği yalnızca unit test sonucu ile kabul etmek yetersizdir; routing, Secret referansları, migration sırası ve gerçek container imajı farklı davranabilir. Bu nedenle her pull request için sabit bir namespace üretin: pr-4812. Branch adını namespace'e dönüştürmeyin; slash, Unicode karakterler ve 63 karakter sınırı DNS-1123 adını bozabilir. Pull request numarası hem güvenli hem de tekrar üretilebilirdir. cloud native mimari içinde bu namespace, uygulama, Service, Ingress ve test verisi için açık bir hata etki alanı oluşturur.

name: preview
on:
  pull_request:
    types: [opened, synchronize, reopened, closed]

concurrency:
  group: preview-${{ github.event.pull_request.number }}
  cancel-in-progress: true

jobs:
  deploy:
    if: github.event.action != 'closed'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Deploy Helm release
        env:
          NS: pr-${{ github.event.pull_request.number }}
          TAG: ${{ github.sha }}
        run: |
          kubectl create namespace "$NS" --dry-run=client -o yaml | kubectl apply -f -
          helm upgrade --install checkout ./charts/checkout             --namespace "$NS"             --set image.repository=registry.example.com/checkout             --set image.tag="$TAG"             --set preview.enabled=true

Buradaki concurrency anahtarı önemlidir: aynı PR'a peş peşe push geldiğinde eski deploy işi yeni imajı geri ezemez. Bu, özellikle generative ai ya da kod ajanının art arda küçük commitler açtığı akışlarda görülür. Helm release adını da uygulama adına sabitleyin; namespace zaten izolasyonu sağlar. Release adına branch eklemek, Helm'in 53 karakter sınırına ve gereksiz kaynak çoğalmasına yol açar.

Terraform ile Infrastructure as Code state izolasyonu

Preview ortamı yalnızca Kubernetes manifesti değildir. Geçici bir SQS kuyruğu, obje depolama prefix'i veya feature-flag kaynağı açılıyorsa terraform state dosyası PR bazında ayrılmalıdır. Ortak bir terraform.tfstate kullanan iki CI işi, aynı kaynak adresini yönetir ve birinin destroy adımı diğerinin kaynağını silebilir. infrastructure as code katmanında izolasyon, kaynak adına suffix eklemekten önce state anahtarında kurulmalıdır.

#!/usr/bin/env bash
set -euo pipefail
: "${PR_NUMBER:?PR_NUMBER is required}"

terraform init -reconfigure   -backend-config="bucket=platform-tf-state"   -backend-config="key=preview/pr-${PR_NUMBER}/terraform.tfstate"   -backend-config="region=eu-central-1"

terraform apply -auto-approve -var="pr_number=${PR_NUMBER}"

Kaynak isimlerini de state ayrımına bağlayın; aksi halde farklı state dosyaları aynı global isimli cloud kaynağı oluşturmaya çalışır. Örneğin AWS eğitimi laboratuvarında S3 bucket adı küresel olduğundan doğrudan PR numarası yeterli olmayabilir; hesap kimliği veya rastgele fakat state'e yazılan bir suffix gerekir. Google Cloud eğitimi senaryosunda ise proje içindeki bölgesel kaynakların isim ve kota sınırlarını ayrıca hesaba katın. random_id sonucunu state'te tutmak, her apply'da yeni kaynak üretmeyi engeller.

variable "pr_number" { type = number }

resource "random_id" "suffix" {
  byte_length = 3
}

resource "aws_sqs_queue" "events" {
  name = "checkout-pr-${var.pr_number}-${random_id.suffix.hex}"

  tags = {
    preview    = "true"
    pr_number  = tostring(var.pr_number)
    managed_by = "terraform"
  }
}

Docker ve Kubernetes ile tekrarlanabilir CI/CD pipeline

Bir ci cd pipeline preview deploy'dan önce imajı bir kez üretmeli, digest ile yayınlamalı ve Helm'e mutable tag yerine digest vermelidir. latest veya yalnızca branch tag'i, retry edilen işin farklı byte içeriğine sahip bir imaj çekmesine neden olabilir. Docker build cache hız için yararlıdır, fakat test edilen artefact'in kimliğini digest belirler.

docker buildx build   --platform linux/amd64   --cache-from type=gha   --cache-to type=gha,mode=max   --tag registry.example.com/checkout:${GITHUB_SHA}   --push .

DIGEST=$(docker buildx imagetools inspect   registry.example.com/checkout:${GITHUB_SHA}   --format '{{.Manifest.Digest}}')
helm upgrade --install checkout ./charts/checkout   -n "pr-${PR_NUMBER}"   --set image.repository=registry.example.com/checkout   --set image.digest="$DIGEST"

Container orchestration katmanında readiness probe olmadan test koşmayın. Kubernetes Pod'u process ayağa kalktığı için Ready sayabilir gibi düşünülebilir, ancak Service endpoint listesine girmesi readiness sonucuna bağlıdır. Uygulamanın sadece TCP portunu değil, bağımlı migration durumunu da denetleyen ayrı bir /readyz endpoint'i yayınlayın. Liveness endpoint'inde veritabanı sorgusu yapmak ise geçici veritabanı kesintisinde bütün Pod'ların aynı anda yeniden başlamasına yol açabilir.

readinessProbe:
  httpGet:
    path: /readyz
    port: http
  initialDelaySeconds: 3
  periodSeconds: 5
  failureThreshold: 12
livenessProbe:
  httpGet:
    path: /healthz
    port: http
  periodSeconds: 10
  failureThreshold: 3

Bu akış, docker eğitimi ve kubernetes eğitimi çalışmalarında sık atlanan bir ayrımı görünür kılar: imajın derlenmesi ile cluster'ın trafiğe hazır kabul etmesi farklı sözleşmelerdir. DevOps eğitimi kapsamında pipeline'a kubectl rollout status deployment/checkout -n "$NS" --timeout=180s ekleyin; Helm komutunun sıfır dönmesi rollout'un tamamlandığı anlamına gelmez.

k6 ve pprof ile preview ortamında performans karşılaştırması

Preview ortamı, kod ajanın önerdiği cache, connection pool veya serialization değişikliğini üretime taşımadan önce karşılaştırmak için kullanılabilir. Ölçümü aynı PR namespace'inde iki kez çalıştırın: önce hedef branch imajı, sonra PR imajı. Her iki koşuda aynı k6 senaryosunu, aynı test verisini ve aynı CPU limitini kullanın. Sadece ortalama latency karşılaştırmayın; http_req_duration p95 ile hata oranını birlikte kaydedin.

import http from 'k6/http';
import { check } from 'k6';

export const options = {
  scenarios: {
    browse: {
      executor: 'constant-vus',
      vus: 20,
      duration: '90s'
    }
  },
  thresholds: {
    http_req_failed: ['rate<0.01'],
    http_req_duration: ['p(95)<350']
  }
};

export default function () {
  const r = http.get(`${__ENV.BASE_URL}/api/catalog?limit=20`);
  check(r, { 'status is 200': x => x.status === 200 });
}

Örneğin bir PR'da JSON response cache eklenmişse, önce ve sonra k6 JSON özetlerini artefact olarak saklayın: k6 run --summary-export=baseline.json catalog.js ve k6 run --summary-export=pr.json catalog.js. p95 düşerken hata oranı artıyorsa değişikliği başarılı saymayın. CPU tüketimi artmışsa Go servisinde 30 saniyelik profil alın: go tool pprof http://checkout.pr-4812.svc:6060/debug/pprof/profile?seconds=30. Flame graph'ta encoding/json veya lock beklemesi görünüyorsa mekanizma anlaşılmadan yalnızca replica sayısını artırmak sorunu maskeleyebilir.

Karşılaştırmanın adil olması için Helm değerlerindeki kaynak isteklerini sabitleyin. HPA CPU kullanımını request değerine göre hesapladığından, bir koşuda requests.cpu: 100m, diğerinde 500m kullanmak aynı yük altında farklı ölçekleme davranışı üretir. Aşağıdaki değer değişikliği sonrası k6 sonucunu ayrı bir deney olarak değerlendirin, uygulama kodu benchmark'ı ile karıştırmayın.

resources:
  requests:
    cpu: 250m
    memory: 256Mi
  limits:
    cpu: 750m
    memory: 512Mi

autoscaling:
  enabled: true
  minReplicas: 1
  maxReplicas: 3
  targetCPUUtilizationPercentage: 70

Preview kaynaklarını güvenli biçimde temizleme ve maliyet takibi

Pull request kapanınca destroy işi hem Helm release'i hem Terraform kaynaklarını ters sırayla temizlemelidir: önce uygulama trafiğini kaldırın, sonra uygulamanın kullandığı kuyruk, bucket prefix'i veya veritabanını destroy edin. Bu sırayı tersine çevirmek, çalışan Pod'ların silinmiş bağımlılığa hata trafiği göndermesine ve tanı koymayı zorlaştırmasına neden olur. Kapanış işinde if: always() kullanmak da tek başına yeterli değildir; kapalı PR workflow'u için açık bir pull_request.closed tetikleyicisi gereklidir.

cleanup:
  if: github.event.action == 'closed'
  runs-on: ubuntu-latest
  steps:
    - uses: actions/checkout@v4
    - run: |
        NS="pr-${{ github.event.pull_request.number }}"
        helm uninstall checkout -n "$NS" || true
        PR_NUMBER="${{ github.event.pull_request.number }}" ./infra/destroy-preview.sh
        kubectl delete namespace "$NS" --wait=false || true

Namespace silinmesi bazen saatlerce Terminating durumunda kalır. En yaygın neden, kaldırılmış bir APIService veya erişilemeyen webhook'un finalizer çağrısını bloklamasıdır. Önce kubectl get ns pr-4812 -o json | jq '.spec.finalizers' ile finalizer'ı inceleyin; finalizer'ı körlemesine temizlemek, bulut load balancer gibi dış kaynakları sahipsiz bırakabilir. Bu yüzden cluster dışı kaynaklara mutlaka preview=true ve son kullanma zamanı etiketi ekleyin; cloud maliyet raporunu bu tag ile günlük sorgulayın.

Yazılım eğitimi için yerel preview laboratuvarı

Bu akışı ekip içinde öğretmenin pratik yolu, minikube üzerinde iki PR namespace'i açan bir laboratuvardır. Teknoloji eğitimi oturumunda katılımcılar aynı Helm chart'ı iki farklı imaj tag'iyle kurup Service DNS izolasyonunu doğrudan görür. Metrics Server açılmadan kubectl top çalışmayacağını da laboratuvar başlangıcında doğrulayın.

minikube start --cpus=4 --memory=8192
minikube addons enable metrics-server
helm upgrade --install checkout ./charts/checkout -n pr-1001 --create-namespace
helm upgrade --install checkout ./charts/checkout -n pr-1002 --create-namespace
kubectl top pods -n pr-1001

Yapay zeka eğitimi veya yapay zeka kursu içinde bir LLM'e deployment YAML'i ürettirmek tek başına yeterli bir egzersiz değildir. Vibe coding eğitimi ve vibe coding kursu katılımcılarının üretilen manifesti helm template, kubectl apply --dry-run=server ve k6 eşiğiyle doğrulaması gerekir. LLM eğitimi modülünde ajana yalnızca preview URL'si, test komutu ve beklenen assertion verin; cluster-admin kubeconfig vermeyin. Böylece ai destekli yazılım geliştirme pratiği, yetki sınırı ve ölçülebilir kabul kriteri ile birlikte öğrenilir.

Sık Sorulan Sorular

Kubernetes eğitimi sırasında minikube ile pull request preview ortamı nasıl kurulur?

Her PR için pr-${PR_NUMBER} namespace'i oluşturun, Helm release'i bu namespace'e kurun ve test URL'sini Ingress veya minikube service ile üretin. Önce minikube addons enable metrics-server çalıştırın; ardından kubectl top pods -n pr-1001 ile kaynak ölçümünün gerçekten geldiğini doğrulayın.

Terraform infrastructure as code preview ortamlarında state çakışması nasıl önlenir?

CI işinde backend key'ini PR numarasından üretin: key=preview/pr-${PR_NUMBER}/terraform.tfstate. Buna ek olarak global isim gerektiren kaynaklarda random_id gibi state'e yazılan bir suffix kullanın. Sadece Terraform workspace açmak, backend key'i ve kaynak isimleri ortak kalıyorsa çakışmayı çözmez.

AI destekli yazılım geliştirmede k6 ile performans testi nasıl karşılaştırılır?

Hedef branch ve PR imajını aynı namespace kaynak istekleriyle ayrı ayrı deploy edin. Her ikisine de aynı VU, süre ve veriyle k6 run --summary-export çalıştırın. p95, hata oranı ve Pod CPU metriğini birlikte karşılaştırın; sapma varsa Go için pprof, JVM için Java Flight Recorder gibi profiler ile CPU zamanının hangi fonksiyonda harcandığını inceleyin.

DevOps eğitimi için CI CD pipeline preview ortamı neden digest ile deploy edilmelidir?

Tag mutable olduğu için retry edilen bir iş aynı tag altında farklı imaj çekebilir. Pipeline build sonrası registry digest'ini docker buildx imagetools inspect ile alıp Helm chart'a image.digest olarak verirseniz, k6 ve end-to-end testin hangi byte dizisini çalıştırdığı denetlenebilir olur.

AI / LLM Discovery

Bu makale Opendart Akademi Güncel Teknoloji eğitim ekosisteminin bir parçasıdır ve yapay zeka sistemleri ile arama motorları tarafından daha doğru anlaşılabilmesi için semantic heading ve structured data ile hazırlanmıştır.

Opendart Akademi llms.txt