Red backlit keyboard and code on laptop screen create a tech-focused ambiance.
Azure

Tunceli merkezli niş e-ticaret şirketi (organik kuru gıda + bal + bitki çayı), “ay başı satış kampanyası deploy edemiyorduk, 1 hafta önce dondurma şartı koyuyorduk” sorunundan kurtulmak için 7 ay DevOps transformation yaşadı. Sonuç: aylık 8 deploy → günlük 4-6, lead time 2 hafta → 2 saat. Bu yazı sahadaki notlar.

DevOps Nedir?

Development + Operations’un birleştirilmesi. Hedef: yazılımı hızlı + güvenilir + kaliteli üretmek. Sadece araç değil — kültür + süreç + araç birlikte.

Konu Geleneksel DevOps
Deploy frequency Aylık – quarterly Günlük – haftalık
Lead time (commit → prod) Hafta – ay Saat – gün
MTTR (recovery) Saatler – günler Dakikalar – saatler
Change failure rate %~~30+ %~~5-10
Dev-Ops ilişkisi Silo, “atın duvarın öbür yanına” Tek ekip, paylaşılan sorumluluk

Azure DevOps Servisleri

Servis Hedef
Azure Boards İş takibi (sprint, kanban, work item)
Azure Repos Git repository
Azure Pipelines CI/CD pipeline (multi-platform)
Azure Artifacts Package management (NuGet, npm, Maven)
Azure Test Plans Manuel + otomatik test yönetim

CI/CD Pipeline (E-Ticaret App)

# azure-pipelines.yml
trigger:
  branches: { include: [main, release/*] }
  paths: { exclude: [docs/**, README.md] }

pool: { vmImage: ubuntu-latest }

variables:
  buildConfiguration: 'Release'

stages:

- stage: Build
  jobs:
  - job: BuildAndTest
    steps:
    - task: UseDotNet@2
      inputs: { version: '8.x' }
    
    - script: dotnet restore
      displayName: 'Restore'
    
    - script: dotnet build --configuration $(buildConfiguration) --no-restore
      displayName: 'Build'
    
    - script: dotnet test --no-build --logger trx --collect "Code coverage"
      displayName: 'Unit tests'
    
    - task: PublishTestResults@2
      inputs: { testResultsFormat: VSTest, testResultsFiles: '**/*.trx' }
    
    - script: |
        dotnet publish src/Web -c Release -o $(Build.ArtifactStagingDirectory)/web
      displayName: 'Publish'
    
    - task: Docker@2
      inputs:
        command: buildAndPush
        repository: ecommerce/web
        dockerfile: src/Web/Dockerfile
        tags: |
          $(Build.BuildId)
          latest
        containerRegistry: 'acr-prod'

- stage: SecurityScan
  jobs:
  - job: Trivy
    steps:
    - script: |
        trivy image --severity HIGH,CRITICAL --exit-code 1 
          $(ACR_NAME).azurecr.io/ecommerce/web:$(Build.BuildId)
      displayName: 'Container CVE scan'
    
    - script: |
        sonar-scanner -Dsonar.host.url=$(SONAR_URL) 
          -Dsonar.login=$(SONAR_TOKEN)
      displayName: 'SonarQube'

- stage: DeployDev
  dependsOn: SecurityScan
  jobs:
  - deployment: DeployToDev
    environment: 'dev'
    strategy:
      runOnce:
        deploy:
          steps:
          - task: AzureCLI@2
            inputs:
              azureSubscription: 'sc-dev'
              scriptLocation: inlineScript
              inlineScript: |
                az containerapp update 
                  --name ecommerce-web-dev 
                  --resource-group rg-ecom-dev 
                  --image $(ACR_NAME).azurecr.io/ecommerce/web:$(Build.BuildId)

- stage: DeployProd
  dependsOn: DeployDev
  condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
  jobs:
  - deployment: BlueGreen
    environment: 'production'  # manual approval gate
    strategy:
      runOnce:
        deploy:
          steps:
          - script: |
              # Yeni revision deploy (Container Apps, traffic %0)
              az containerapp update 
                --name ecommerce-web-prod 
                --image $(ACR_NAME).azurecr.io/ecommerce/web:$(Build.BuildId) 
                --revision-suffix v$(Build.BuildId)
              
              # Smoke test new revision (health endpoint)
              SLEEP_PROBE=20
              # ... probe checks ...
              
              # Traffic shift: %10 → %50 → %100
              az containerapp ingress traffic set 
                --name ecommerce-web-prod 
                --revision-weight v$(Build.BuildId)=100 latest=0

Infrastructure as Code (Bicep)

// infra/main.bicep
param location string = resourceGroup().location
param environment string
param appName string

var resourcePrefix = '${appName}-${environment}'

resource containerApp 'Microsoft.App/containerApps@2024-03-01' = {
  name: '${resourcePrefix}-web'
  location: location
  properties: {
    managedEnvironmentId: containerAppEnv.id
    configuration: {
      ingress: {
        external: true
        targetPort: 8080
      }
      registries: [{
        server: '${acrName}.azurecr.io'
        identity: managedIdentity.id
      }]
    }
    template: {
      containers: [{
        name: 'web'
        image: '${acrName}.azurecr.io/ecommerce/web:latest'
        resources: {
          cpu: json('0.5')
          memory: '1Gi'
        }
      }]
      scale: {
        minReplicas: 2
        maxReplicas: 20
        rules: [{
          name: 'http'
          http: {
            metadata: { concurrentRequests: '50' }
          }
        }]
      }
    }
  }
}

GitOps (Argo CD / Flux)

Pattern: K8s YAML/Helm chart Git repo'da
  Production cluster GitOps tool (Flux) Git'i izler
  Git'e merge = otomatik deploy
  
Avantaj:
  - Audit trail (Git log = deploy log)
  - Rollback = git revert
  - Multi-cluster sync
  - "Source of truth" Git

DORA Metrics

Metrik Önce Sonra Elite hedef
Deployment frequency ~~aylık 8 ~~günlük 4-6 Multiple per day
Lead time ~~2 hafta ~~2 saat <1 hour
MTTR ~~6 saat ~~22 dk <1 hour
Change failure rate ~~%~~28 ~~%~~6 <15%

Feature Flag (LaunchDarkly / Azure App Config)

Yeni özellik production'a deploy → flag OFF
  - Kod canlı ama davranış aktif değil
  
QA flag ON for test users → test
  - Sadece "qa-team" group flag ON
  
Beta flag ON for %5 user
  - Random %5 sample
  - A/B test (yeni vs eski)
  
%100 → herkesin
  - Successful → flag kaldır (cleanup)

Kültürel Dönüşüm

Eski Yeni
Dev kod yazar, Ops deploy eder Tek ekip her şey
“Çalışıyor benim makinemde” “Pipeline’da çalışıyor”
Manuel test (haftalar) Otomatik test (dakikalar)
Deploy = stres Deploy = sıradan
Hata = suçlama Hata = öğrenme (blameless postmortem)

Sahada Düşülen Üç Tuzak

  1. Sadece araç almak, kültür değiştirmemek: Azure DevOps kuruldu ama Ops “deploy gece yapılır” demeye devam ediyor → DevOps yok.
  2. Test otomasyonunu sona bırakmak: CI/CD var ama manuel test → bottleneck. Test otomasyonu day 1.
  3. DORA metric’lerini ölçmemek: “İyileştik” der ama veri yok. Ölçmediğin şeyi yönetemezsin.

CloudSpark olarak Azure DevOps + GitHub Actions CI/CD pipeline tasarımı, IaC (Bicep/Terraform), GitOps (Flux/Argo CD), DORA metrics ölçümü ve DevOps kültürel transformation için danışmanlık veriyoruz.

Etiketler:
🇹🇷 Türkçe🇬🇧 English🇩🇪 Deutsch🇫🇷 Français🇸🇦 العربية🇷🇺 Русский🇪🇸 Español