Classic Release Pipeline'larından YAML'a Geçiş ve 2023–2026'da Azure Pipelines'ta Değişenler
Classic release pipeline'ları YAML'a dışa aktarılamaz; build'ler Export to YAML ile başlar, release'ler stage, check ve template'lerle elle yeniden kurulur. Bookstore'da task group'u step template'ine, eski release'i yeniden deploy etmeyi pipeline resource'lu bir pipeline'a çeviriyor, classic oluşturmayı kapatıyor ve 2023–2026 arasındaki değişiklikleri, roadmap'i ve Azure DevOps'ta kalma kararını tarihleriyle topluyoruz.
Sürüm notu: Bu yazıdaki pipeline ve template dosyaları yq 4.54 ile ayrıştırılarak denetlenmiştir. Classic pipeline'ların, geçiş araçlarının ve 2023–2026 arasındaki değişikliklerin anlatımında Microsoft Learn'deki resmî belgelerden, Azure DevOps sürüm notlarından ve roadmap sayfasından (Kasım 2026 sürümleri) yararlanılmıştır.
Önce Tahmin Et
Hakan'ın ekibi, sitedeki serilerin ortak örnek uygulaması Bookstore'un (bir online kitapçı) eski bir kopyasını yıllardır classic pipeline'larla yayınlıyor: bir classic build, ondan beslenen dört stage'li bir classic release ve hafta içi her gece 02:00'de çalışan zamanlanmış bir build. Plan iki adım: build'i de release'i de YAML (girintiyle yapı kuran veri formatı) dosyasına "Export to YAML" ile aktarmak ve zamanlanmış build'i cron: "0 2 * * 1-5" olarak taşımak. İki adım da düşünüldüğü gibi çalışır mı?
İkisi de çalışmaz. Belgelere göre YAML'a dışa aktarma yalnızca classic build designer'da oluşturulmuş pipeline'larda var; classic release pipeline'larının dışa aktarması yok, task'ları tek tek taşımak gerekiyor. Zamanlama da kayıyor: classic pipeline'lar organization'ın yerel saat dilimini kullanıyor, YAML'daki cron ise UTC (eşgüdümlü evrensel saat). İstanbul saatiyle 02:00'de çalışan build, aynı cron'la taşınırsa 05:00'te çalışmaya başlıyor. Doğru karşılığı Pazar'dan Perşembe'ye UTC 23:00, yani "0 23 * * 0-4". Bu yazıda geçişin bu tür ayrıntılarını, serinin kurduğu yapının üzerinden bir araya getiriyoruz.
Eski Kurulumu Okumak ve Geçiş Haritası
Geçişe bir envanterle başlamak gerekiyor, çünkü classic tarafta bilgi YAML gibi tek dosyada değil, web arayüzünde birçok yere dağılmış durumda. Her classic build ve release için şunlara bakıyoruz: hangi artifact'ları tükettiği, stage'leri ve sırası, her stage'in pre- ve post-deployment koşulları (approval, gate, zamanlama), kullandığı task group'lar ve deployment group'lar, release ve stage değişkenleri ve hangi service connection'lara dokunduğu. Envanter bittiğinde eşleme şöyle:
| Classic | Bookstore'daki YAML karşılığı | Not |
|---|---|---|
| Build definition | azure-pipelines.yml + pipelines/bookstore-ci.yml iskeleti | Export to YAML başlangıç noktası olabilir |
| Release definition ve stage'leri | İskeletteki Deploy_dev, Deploy_staging, Deploy_production | Dışa aktarma yok; elle yazılır |
| Build artifact | release pipeline artifact'ı | Build once, deploy many |
| Task group | Step template (steps/smoke-test.yml) | Task group'lar YAML'da desteklenmiyor |
| Pre-deployment approval ve gate | Environment ve service connection check'leri | Altıncı yazıdaki tablo |
| Release ve stage değişkenleri | Variable group'lar ve Key Vault'a bağlı grup | Secret'lar dosyaya taşınmaz |
| Eski bir release'i bir stage'e yeniden deploy | azure-pipelines.redeploy.yml | Pipeline resource ile |
| Zamanlanmış build/release | schedules cron | UTC; classic'te yerel saat |
| Deployment group | Sanal makine resource'u olan environment | Bookstore App Service kullandığı için gerekmedi |
Export to YAML'ın verdiği dosya bir başlangıç. Belgeler classic editörde tanımlanmış değişkenlerin dosyaya taşınmadığını, YAML'da ya da pipeline ayarlarında yeniden tanımlanması gerektiğini söylüyor. Bizim için asıl iş zaten dışa aktarılan step'leri ortak iskeletin, template'lerin ve check'lerin içine yerleştirmekti; bunu serinin ilk sekiz yazısında yaptık.
Task Group'tan Step Template'e
Task group, classic'te birkaç task'ı tek bir yeniden kullanılabilir task'a çeviriyor; task'lardaki $(MyVariable) biçimindeki değerler task group'un parametreleri oluyor. Belgeler task group'ların YAML'da desteklenmediğini ve yerine template'lerin kullanılması gerektiğini söylüyor. Eski Bookstore'daki "Bookstore - Smoke test" task group'unu bir step template'ine çevirdik:
# Classic "Bookstore - Smoke test" task group'unun yerini alır: aynı step'ler, $(değişkenler) yerine parameter'lar.
parameters:
- name: baseUrl
type: string
- name: attempts
type: number
default: 10
- name: delaySeconds
type: number
default: 15
steps:
- script: bash scripts/smoke-test.sh ${{ parameters.baseUrl }}
displayName: Smoke test
target:
settableVariables: none
env:
SMOKE_ATTEMPTS: ${{ parameters.attempts }}
SMOKE_DELAY_SECONDS: ${{ parameters.delaySeconds }}
Deploy template'i artık script'i doğrudan çağırmıyor, bu template'i kullanıyor:
- template: ../steps/smoke-test.yml
parameters:
baseUrl: $(deployApi.AppServiceApplicationUrl)
İki fark önemli. Task group'ta parametreler metin; template'te number gibi tipleri ve izinli değer listeleri var, yanlış değer dosya işlenirken yakalanıyor. Task group'ta merkezi bir değişiklik onu kullanan bütün tanımlara anında yansıyor; template'te ise değişiklik yeni bir tag'le geliyor ve her pipeline ref'i yükselttiğinde alıyor. Bu ikincisi kısıt gibi görünse de üçüncü yazıda sürüm sabitlemeyi bilerek seçmiştik: bir template değişikliği bütün pipeline'ları aynı anda kıramıyor.
Eski Bir Release'i Yeniden Deploy Etmek
Classic release'in sık kullanılan bir özelliği, geçmişteki bir release'i seçip bir stage'e yeniden deploy etmek. YAML'da bunun karşılığı ayrı bir pipeline: CI pipeline'ını (Azure DevOps'taki adı bookstore-ci) bir pipeline resource'u olarak tanımlıyor ve bir runtime parameter ile ortam seçtiriyor. İkinci yazıda gördüğümüz environment seçimi burada asıl yerini buluyor:
# Daha önceki bir bookstore-ci run'ının release artifact'ını tek bir environment'a yeniden deploy eder.
# Run'ı bu pipeline'ı başlatırken "Resources" altında seç; environment'ın check'leri yine geçerli.
trigger: none
pr: none
parameters:
- name: environment
displayName: Environment
type: string
default: staging
values:
- dev
- staging
- production
resources:
repositories:
- repository: templates
type: git
name: Bookstore/pipeline-templates
ref: refs/tags/v1.6.0
pipelines:
- pipeline: ci
source: bookstore-ci
trigger: none
extends:
template: pipelines/bookstore-redeploy.yml@templates
parameters:
environment: ${{ parameters.environment }}
Belgelere göre run'ı elle başlatırken Resources bölümünden ci resource'u için istediğin run'ı seçebiliyorsun; seçmezsen son başarılı CI run'ı kullanılıyor. Yeni iskelet (pipelines/bookstore-redeploy.yml) tek bir deploy stage'i üretiyor ve deploy template'ine artifact'ın nereden geleceğini söylüyor:
stages:
- template: ../stages/deploy.yml
parameters:
environment: ${{ parameters.environment }}
dependsOn: []
mainOnly: ${{ eq(parameters.environment, 'production') }}
useSlot: ${{ eq(parameters.environment, 'production') }}
artifactPipeline: ${{ parameters.artifactPipeline }}
Deploy template'i artifactPipeline current değilse iki şeyi değiştiriyor: artifact'ı download: ci ile indiriyor ve klasörü $(Pipeline.Workspace)/ci/release olarak kullanıyor (belgelere göre pipeline resource artifact'ları <pipeline-identifier>/<artifact-identifier> altına iniyor). Beklenen commit de $(resources.pipeline.ci.sourceCommit) oluyor. Altıncı yazıdaki commit kontrolünün değeri burada ortaya çıkıyor: seçilen run'ın artifact'ı başka bir commit'ten gelmişse doğrulama step'i deploy'u durduruyor.
Check'ler için bir adım daha var. bookstore-production environment'ındaki ve bookstore-azure-production connection'ındaki required template check'ine ikinci bir şablon olarak pipelines/bookstore-redeploy.yml'ı ekliyoruz; aksi hâlde redeploy pipeline'ı production'a giremiyor. Approval, branch control ve exclusive lock aynen geçerli. Template'lerin bu sürümü v1.6.0.
Paralel Çalıştırma ve Classic'i Kapatmak
Geçişi tek seferde yapmak yerine bir süre iki yolu yan yana çalıştırdık. İlk hafta YAML pipeline'ı yalnızca dev ve staging'e deploy etti, production hâlâ classic release'teydi; aynı build'in iki yoldan çıkan paketlerini manifest'teki commit ve dosya sayılarıyla karşılaştırdık. Production'ı YAML'a geçirdiğimiz gün classic release'in trigger'larını kapattık ama tanımı silmedik; geri dönüş gerekirse orada duruyordu. İki sprint sonra classic tanımları sildik.
Son adım classic'in geri gelmesini engellemek. Organization ya da project ayarlarında "Disable creation of classic build pipelines" ve "Disable creation of classic release pipelines" ayrı ayrı açılabiliyor; ikisi birden açıkken classic build, classic release, task group ve deployment group ne arayüzden ne REST (HTTP üzerinden kaynak odaklı API tarzı) API'den oluşturulabiliyor. Belgelerin gerekçesi güvenlik: YAML ve classic pipeline'lar aynı service connection'ları paylaşabildiği için, classic bir tanım YAML'daki check'lerin etrafından dolaşan bir yol açabiliyor. Sprint 226'dan beri yeni organization'larda bu ayar varsayılan olarak açık geliyor. Classic release'ler için ayrı bir job authorization scope ayarı da var; geçiş bitene kadar onu da project'e daraltmak gerekiyor.
2023–2026'da Azure Pipelines'ta Değişenler
Serinin dayandığı değişiklikleri tarih sırasıyla toplayalım. Her madde sürüm notlarından ya da ilgili belge sayfasından:
- Ağustos 2023, Sprint 226: yeni organization'larda classic build ve release oluşturma varsayılan olarak kapalı (Sprint 225'te önceden duyuruldu).
- Şubat 2024, Sprint 234: Azure Resource Manager service connection'ları için workload identity federation GA (genel kullanıma açık).
- 18 Kasım 2024: Managed DevOps Pools GA olarak duyuruldu; Sprint 251 sürüm notları da GA'yı listeliyor. Roadmap'e göre yeni özellikler Scale Set pool'larına değil buraya geliyor.
- Mart 2025, Sprint 253: yeni Azure ve Docker service connection'ları Microsoft Entra issuer'ı ile oluşturuluyor.
- 31 Aralık 2025:
windows-2019hosted image'ı emekliye ayrıldı. - 1 Temmuz 2026: Azure DevOps issuer'ı deprecated; 1 Temmuz 2027'de emekliye ayrılıyor.
- 29 Eylül 2026:
ubuntu-26.04vewindows-2025-vs2026image'ları GA;ubuntu-latestşu anubuntu-24.04,ubuntu-22.0417 Nisan 2027'de kaldırılacak. - 24 Kasım 2026: Node.js 6, 10 ve 16 agent'tan kaldırılıyor; agent Node.js 24'ü içeriyor, resmî task'ların Node.js 24'e geçişi roadmap'te tarihsiz.
- 2027: public project'ler private'a çevriliyor.
Roadmap'in "YAML and release pipelines feature parity" bölümü Microsoft'un yönünü açıkça yazıyor: son yıllarda bütün pipeline yatırımları ve bütün güvenlik iyileştirmeleri YAML tarafında yapıldı ve classic release'ten YAML'a geçişi zorlaştıran CD eksiklerini kapatmak hedefleniyor. Bu bölümdeki iki madde serinin ilgilendiği eksiklere dokunuyor: "On-demand out of order execution of stages", yani bağımlılıklarını beklemeden bir sonraki stage'i elle başlatabilmek, 2027 Q1 (yılın ilk çeyreği) olarak görünüyor. "Stage-level traceability", yani bir stage'i en son hangi run'ın çalıştırdığını gösteren stage odaklı görünüm ise sayfada iki farklı yerde iki farklı zamanla geçiyor: tüm özellikler tablosunda 2026 Q4 (yılın son çeyreği) altında, aynı bölümün kendi tablosunda 2027 Q1 olarak. "Service connections in checks" ve "Checks extensibility" tarihsiz "Future" maddeleri.
Karar Notu: Azure DevOps'ta Kalmak mı, GitHub Actions'a Geçmek mi
Classic'ten çıkan bir ekip bu soruyu da soruyor: madem bir geçiş yapılıyor, doğrudan GitHub Actions'a mı gidilmeli? İki seçeneği karşılaştıralım.
Azure DevOps'ta kalıp YAML'a geçmek: Boards, Repos ve Artifacts ile mevcut entegrasyonlar, izinler ve Entra ID yapısı yerinde kalıyor; geçişin kapsamı yalnızca pipeline'lar. Microsoft'un yatırımı da sürüyor: roadmap'te Azure Repos için Copilot code review'ı 2026 Q3 (üçüncü çeyrek) içinde public preview oldu, GitHub Advanced Security for Azure DevOps için 2026 Q4'e planlı maddeler var, Managed DevOps Pools düzenli yeni özellik alıyor. Bedeli, bazı CD özelliklerinin hâlâ roadmap'te beklemesi.
GitHub Actions'a geçmek: kod ve CI aynı yerde, marketplace ve topluluk geniş. Ama bu bir pipeline geçişi değil, bir platform geçişi: repository'ler, izinler, paket feed'leri ve iş takibi birlikte taşınıyor. Kavramların birebir karşılıkları ilk yazıdaki tabloda; Actions'ın kendisi sitedeki GitHub Actions serisinde anlatıldı. Bookstore ekibi için karar Azure DevOps'ta kalmak oldu: geçişin riski pipeline'larla sınırlı kaldı ve bu seride kurduğumuz iskelet, check'ler ve federation connection'ları zaten YAML tarafındaki yatırımın üzerinde duruyor.
Azure DevOps Server kullananlar için bir not: bu seri Services'ı anlattı. Belgelere göre Microsoft-hosted agent'lar Server'da yok, self-hosted agent gerekiyor. Azure service connection belgesinin Server sürümü de secret ya da sertifikayla çalışan bir service principal'ı anlatıyor; workload identity federation bölümleri Services için yazılmış. Azure DevOps Server 2022'de agent kaydı için belgeler PAT (kişisel erişim token'ı) ve Alternate kimlik doğrulamasını sayıyor.
Üretimde Dikkat
Classic tanımı silmeden önce geçmişini dışarı al. Release'lerin kim tarafından, hangi artifact'la, hangi onayla yapıldığı denetim için gerekebiliyor; YAML tarafındaki environment geçmişi geçiş gününden başlıyor.
Gate'leri birebir taşıyamayabilirsin. Query work items ve Azure Policy compliance gate'lerinin check karşılığı yok; bunları ya Invoke REST API check'iyle kendi servisine taşıman ya da süreçten çıkarman gerekiyor.
Zamanlamaları UTC'ye çevirirken yaz saati uygulayan ülkeleri unutma. UTC sabit kalıyor, yerel saat değişiyor; böyle bir ofisle çalışıyorsan cron'u yılda iki kez gözden geçirmek gerekebilir.
Sık Düşülen Tuzaklar
Release'i de dışa aktarmayı beklemek. Export to YAML yalnızca classic build designer'daki pipeline'larda var ve tanımın kendisinde görünüyor, belirli bir run'da değil.
Classic değişkenleri unutmak. Dışa aktarılan dosya classic editörde tanımlanmış değişkenleri içermiyor; ilk YAML run'ı boş bir değişkenle sessizce yanlış bir şey yapabilir.
Classic'i açık bırakmak. Geçiş bittikten sonra classic oluşturma kapatılmazsa biri yeni bir classic release açıp YAML'daki check'lerin dışından aynı service connection'ı kullanabilir.
Redeploy pipeline'ını required template check'ine eklemeyi unutmak. Pipeline doğru yazılsa da production'da check'e takılıyor; hata mesajı bir şablon eksikliğini söylüyor, pipeline'ın kendisini değil.
Küçük Bir Deneme
★☆☆ Hafta içi her sabah İstanbul saatiyle 07:30'da çalışması gereken bir build için YAML cron ifadesini yaz.
★★☆ Bir classic release'inin envanterini bu yazıdaki tabloya göre çıkar: stage'ler, approval'lar, gate'ler, task group'lar, değişkenler, service connection'lar. Her satırın YAML karşılığını yaz.
★★★ Redeploy pipeline'ına ikinci bir runtime parameter ekle: yalnızca API'yi ya da yalnızca web'i deploy etmeyi seçtirsin. Bunu deploy template'inde koşullu ekleme ile yap ve production check'lerinin bundan nasıl etkileneceğini düşün.
Seri burada bitiyor. Dokuz yazıda Bookstore'un pipeline'larını kodla yazdık; web arayüzünde yalnızca resource'ları, izinleri ve check'leri tanımladık: ortak template'ler, .NET ve Angular CI, Azure Artifacts feed'i, onaylı ve check'li deploy stage'leri, şifresiz Azure bağlantıları ve sıkılaştırılmış agent ayarları. Buradan devam etmek isteyenler için Azure kaynaklarını kodla kurmak Infrastructure as Code: Terraform serisinin, dependency ve code scanning ise DevSecOps serisinin konusu.