Jenkins Pipeline Parametre Yönetimi: Dinamik ve Yeniden Kullanılabilir Build Yapılandırması
Büyük takımlarda ya da çok ortamlı projelerde Jenkins pipeline’ları yönetmek başlı başına bir iş haline gelir. Her branch için ayrı Jenkinsfile, her ortam için ayrı job konfigürasyonu, her geliştirici isteği için yeniden baştan yazılan pipeline’lar… Bu kaosa bir son vermek istiyorsanız, parametre yönetimini doğru öğrenmek tam da ihtiyacınız olan şey. Bu yazıda Jenkins pipeline parametrelerini derinlemesine ele alacağız; basit string parametrelerinden dinamik choice listelerine, aktif seçim eklentilerine kadar gerçek dünya senaryolarıyla konuyu işleyeceğiz.
Jenkins Parametre Sistemine Genel Bakış
Jenkins’te parametreler, pipeline çalışmadan önce kullanıcıdan ya da tetikleyici sistemden değer alan değişkenlerdir. parameters bloğu Declarative Pipeline’da pipeline bloğunun hemen altında tanımlanır. Bu sayede her build, farklı konfigürasyonlarla çalıştırılabilir; aynı Jenkinsfile’ı hem development hem staging hem de production ortamı için kullanabilirsiniz.
Parametre tipleri şunlardır:
- string: Serbest metin girişi
- text: Çok satırlı metin girişi
- booleanParam: Açık/kapalı toggle
- choice: Önceden tanımlı seçenekler listesi
- password: Maskelenmiş şifre girişi
- file: Dosya yükleme parametresi
Şimdi bunları tek tek gerçek senaryolarla görelim.
Temel Parametre Tanımlaması
En basit haliyle bir parametre bloğu şöyle görünür:
pipeline {
agent any
parameters {
string(
name: 'APP_VERSION',
defaultValue: '1.0.0',
description: 'Deploy edilecek uygulama versiyonu'
)
booleanParam(
name: 'RUN_TESTS',
defaultValue: true,
description: 'Build sonrası testler çalıştırılsın mı?'
)
choice(
name: 'DEPLOY_ENV',
choices: ['dev', 'staging', 'production'],
description: 'Hedef deployment ortamı'
)
password(
name: 'DB_PASSWORD',
defaultValue: '',
description: 'Veritabanı şifresi (vault kullanımı önerilir)'
)
}
stages {
stage('Parametre Kontrolü') {
steps {
script {
echo "Versiyon: ${params.APP_VERSION}"
echo "Ortam: ${params.DEPLOY_ENV}"
echo "Test: ${params.RUN_TESTS}"
}
}
}
}
}
Önemli not: İlk çalıştırmada parametreler henüz build UI’da görünmez. Jenkins’in parametreleri tanıması için pipeline’ın bir kez çalışması gerekir. İlk çalıştırma default değerlerle gerçekleşir; ikinci çalıştırmadan itibaren “Build with Parameters” ekranı belirir.
Çok Ortamlı Deployment Senaryosu
Gerçek dünyada en sık karşılaştığım senaryo: Aynı uygulama kodunun dev, staging ve production ortamlarına farklı konfigürasyonlarla deploy edilmesi. Bunu parametrik hale getirmek hem hata riskini azaltır hem de pipeline’ı yeniden kullanılabilir kılar.
pipeline {
agent any
parameters {
choice(
name: 'ENVIRONMENT',
choices: ['dev', 'staging', 'production'],
description: 'Deploy ortamı seçin'
)
string(
name: 'DOCKER_TAG',
defaultValue: 'latest',
description: 'Docker image tag (örn: v1.2.3 veya commit hash)'
)
booleanParam(
name: 'FORCE_DEPLOY',
defaultValue: false,
description: 'Health check başarısız olsa bile deploy et'
)
}
environment {
DEV_K8S_CLUSTER = 'k8s-dev.internal'
STAGING_K8S_CLUSTER = 'k8s-staging.internal'
PROD_K8S_CLUSTER = 'k8s-prod.internal'
}
stages {
stage('Ortam Konfigürasyonu') {
steps {
script {
switch(params.ENVIRONMENT) {
case 'dev':
env.K8S_CLUSTER = env.DEV_K8S_CLUSTER
env.REPLICA_COUNT = '1'
env.NAMESPACE = 'app-dev'
break
case 'staging':
env.K8S_CLUSTER = env.STAGING_K8S_CLUSTER
env.REPLICA_COUNT = '2'
env.NAMESPACE = 'app-staging'
break
case 'production':
env.K8S_CLUSTER = env.PROD_K8S_CLUSTER
env.REPLICA_COUNT = '5'
env.NAMESPACE = 'app-production'
break
}
echo "Hedef cluster: ${env.K8S_CLUSTER}"
echo "Namespace: ${env.NAMESPACE}"
echo "Replica sayısı: ${env.REPLICA_COUNT}"
}
}
}
stage('Production Onay Adımı') {
when {
expression { params.ENVIRONMENT == 'production' }
}
steps {
input message: 'Production deploy onayı gerekiyor!',
ok: 'Onayla ve Deploy Et',
submitter: 'lead-dev,devops-team'
}
}
stage('Deploy') {
steps {
sh """
kubectl config use-context ${env.K8S_CLUSTER}
kubectl set image deployment/myapp \
myapp=registry.internal/myapp:${params.DOCKER_TAG} \
-n ${env.NAMESPACE}
kubectl scale deployment/myapp \
--replicas=${env.REPLICA_COUNT} \
-n ${env.NAMESPACE}
"""
}
}
}
}
Bu yapıda production deploy’u için ekstra bir input adımı ekledik. Böylece yanlışlıkla production’a deploy etme riski ortadan kalkar.
Dinamik Parametreler: Active Choices Eklentisi
Jenkins’in varsayılan choice parametresi statiktir. Ancak gerçek dünyada çoğu zaman dinamik listelere ihtiyaç duyarsınız: “Şu anda mevcut Docker tag’leri neler?”, “Hangi branch’ler var?” gibi sorular için Active Choices Plugin devreye girer.
Eklentiyi kurmak için Jenkins > Manage Jenkins > Plugin Manager yolunu izleyip “Active Choices” araması yeterli.
Eklenti kurulduktan sonra Groovy script’leriyle dinamik listeler oluşturabilirsiniz:
// Bu kısım Jenkinsfile içinde değil, Jenkins UI'da
// "Active Choices Parameter" olarak tanımlanır.
// Burada konsept gösterimi için Groovy bloğu paylaşıyoruz.
// Docker Registry'den tag listesi çeken örnek:
import groovy.json.JsonSlurper
def response = "curl -s https://registry.internal/v2/myapp/tags/list".execute().text
def json = new JsonSlurper().parseText(response)
return json.tags.sort().reverse()
Aynı dinamik yaklaşımı şu şekilde bir pipeline’da shared library üzerinden kullanabilirsiniz:
// vars/getDockerTags.groovy - Shared Library fonksiyonu
def call(String imageName) {
def tags = sh(
script: """
curl -s -u ${REGISTRY_USER}:${REGISTRY_PASS} \
https://registry.internal/v2/${imageName}/tags/list \
| python3 -c "import sys,json; \
data=json.load(sys.stdin); \
[print(t) for t in sorted(data['tags'], reverse=True)[:10]]"
""",
returnStdout: true
).trim().split('n')
return tags
}
Shared Library ile Yeniden Kullanılabilir Parametre Setleri
Birden fazla projede aynı parametre setini tekrar tekrar yazmak anti-pattern’dir. Jenkins Shared Library bu sorunu temelden çözer.
Shared Library yapısı:
# Repo dizin yapısı
jenkins-shared-lib/
├── vars/
│ ├── standardParams.groovy
│ ├── deployPipeline.groovy
│ └── buildAndTest.groovy
└── src/
└── org/
└── mycompany/
└── PipelineConfig.groovy
Standart parametre setini tanımlayan shared library fonksiyonu:
// vars/standardParams.groovy
def call() {
return [
choice(
name: 'ENVIRONMENT',
choices: ['dev', 'staging', 'production'],
description: 'Hedef ortam'
),
string(
name: 'APP_VERSION',
defaultValue: 'latest',
description: 'Uygulama versiyonu veya Docker tag'
),
booleanParam(
name: 'SKIP_TESTS',
defaultValue: false,
description: 'Test aşamasını atla (acil durum için)'
),
booleanParam(
name: 'NOTIFY_SLACK',
defaultValue: true,
description: 'Slack bildirimi gönder'
),
string(
name: 'CUSTOM_JVM_OPTS',
defaultValue: '-Xms512m -Xmx2g',
description: 'JVM başlatma parametreleri'
)
]
}
Bu shared library’yi kullanan Jenkinsfile:
// Projenin Jenkinsfile'ı
@Library('jenkins-shared-lib') _
pipeline {
agent {
label 'docker-enabled'
}
parameters {
// Standart parametre setini import ediyoruz
// Not: Bu yaklaşım properties() ile birlikte kullanılır
}
stages {
stage('Konfigürasyon Yükle') {
steps {
script {
// Shared library'den parametreleri properties olarak set et
properties([
parameters(standardParams())
])
// Parametre değerlerini ortam değişkenlerine aktar
env.TARGET_ENV = params.ENVIRONMENT ?: 'dev'
env.BUILD_TAG = params.APP_VERSION ?: 'latest'
env.JVM_OPTS = params.CUSTOM_JVM_OPTS
}
}
}
stage('Build') {
steps {
sh """
docker build \
--build-arg APP_VERSION=${env.BUILD_TAG} \
--build-arg ENV=${env.TARGET_ENV} \
-t registry.internal/myapp:${env.BUILD_TAG} .
"""
}
}
stage('Test') {
when {
expression { !params.SKIP_TESTS }
}
steps {
sh "mvn test -DENV=${env.TARGET_ENV} ${env.JVM_OPTS}"
}
}
}
post {
always {
script {
if (params.NOTIFY_SLACK) {
slackSend(
channel: '#deployments',
message: "Build ${currentBuild.result}: ${env.JOB_NAME} #${env.BUILD_NUMBER} - Ortam: ${env.TARGET_ENV}"
)
}
}
}
}
}
Parametre Doğrulama ve Güvenlik
Parametreleri kabul etmek yetmez; doğrulamak da gerekir. Özellikle production pipeline’larında yanlış bir değer ciddi sorunlara yol açabilir.
pipeline {
agent any
parameters {
string(
name: 'SEMVER_TAG',
defaultValue: '',
description: 'Semantic versiyon (örn: 1.2.3 veya 2.0.0-rc1)'
)
string(
name: 'TARGET_NAMESPACE',
defaultValue: 'app-dev',
description: 'Kubernetes namespace'
)
choice(
name: 'DEPLOY_REGION',
choices: ['eu-west-1', 'us-east-1', 'ap-southeast-1'],
description: 'AWS deployment bölgesi'
)
}
stages {
stage('Parametre Doğrulama') {
steps {
script {
// Semver formatı kontrolü
def semverPattern = /^d+.d+.d+(-[a-zA-Z0-9]+)?$/
if (!params.SEMVER_TAG.matches(semverPattern)) {
error("Geçersiz versiyon formatı: ${params.SEMVER_TAG}. Beklenen format: X.Y.Z veya X.Y.Z-suffix")
}
// Namespace güvenlik kontrolü
def allowedNamespaces = ['app-dev', 'app-staging', 'app-production']
if (!allowedNamespaces.contains(params.TARGET_NAMESPACE)) {
error("İzin verilmeyen namespace: ${params.TARGET_NAMESPACE}")
}
// Production için ek kontrol
if (params.TARGET_NAMESPACE == 'app-production' &&
params.SEMVER_TAG.contains('-')) {
error("Production'a RC/beta sürüm deploy edilemez: ${params.SEMVER_TAG}")
}
echo "Doğrulama başarılı. Tag: ${params.SEMVER_TAG}, Namespace: ${params.TARGET_NAMESPACE}"
}
}
}
stage('Deploy') {
steps {
sh """
helm upgrade --install myapp ./charts/myapp \
--namespace ${params.TARGET_NAMESPACE} \
--set image.tag=${params.SEMVER_TAG} \
--set aws.region=${params.DEPLOY_REGION} \
--atomic \
--timeout 5m
"""
}
}
}
}
Doğrulama mantığını pipeline başında toplamak çok kritik. Sonradan bir stage’de patlayan hata yerine, kullanıcıya hemen geri bildirim verirsiniz ve gereksiz kaynak tüketiminin önüne geçersiniz.
Parametreleri Dosyadan veya Harici Kaynaktan Yönetmek
Büyük projelerde parametre setleri zaman içinde şişer. Bu durumda parametreleri bir YAML ya da JSON dosyasında tutmak ve pipeline’a yüklemek çok daha temiz bir yaklaşımdır:
// config/pipeline-config.yaml (repo içinde)
environments:
dev:
cluster: k8s-dev.internal
replicas: 1
namespace: app-dev
autoDeploy: true
staging:
cluster: k8s-staging.internal
replicas: 2
namespace: app-staging
autoDeploy: false
production:
cluster: k8s-prod.internal
replicas: 5
namespace: app-production
autoDeploy: false
Bu dosyayı pipeline’da kullanan örnek:
pipeline {
agent any
parameters {
choice(
name: 'TARGET_ENV',
choices: ['dev', 'staging', 'production'],
description: 'Deployment ortamı'
)
}
stages {
stage('Konfigürasyon Yükle') {
steps {
script {
// YAML dosyasını oku ve parse et
def config = readYaml file: 'config/pipeline-config.yaml'
def envConfig = config.environments[params.TARGET_ENV]
// Değerleri ortam değişkenlerine aktar
env.K8S_CLUSTER = envConfig.cluster
env.K8S_REPLICAS = envConfig.replicas.toString()
env.K8S_NAMESPACE = envConfig.namespace
env.AUTO_DEPLOY = envConfig.autoDeploy.toString()
echo """
=== Yüklenen Konfigürasyon ===
Ortam : ${params.TARGET_ENV}
Cluster : ${env.K8S_CLUSTER}
Namespace: ${env.K8S_NAMESPACE}
Replica : ${env.K8S_REPLICAS}
"""
}
}
}
stage('Otomatik Deploy Kontrolü') {
when {
expression { env.AUTO_DEPLOY == 'true' }
}
steps {
echo "Bu ortam için otomatik deploy aktif, onay beklenmeden devam ediliyor."
}
}
stage('Manuel Onay') {
when {
expression { env.AUTO_DEPLOY == 'false' }
}
steps {
timeout(time: 30, unit: 'MINUTES') {
input message: "${params.TARGET_ENV} ortamına deploy onayı",
ok: 'Devam Et'
}
}
}
stage('Kubernetes Deploy') {
steps {
sh """
kubectl config use-context ${env.K8S_CLUSTER}
kubectl apply -f k8s/${params.TARGET_ENV}/ -n ${env.K8S_NAMESPACE}
kubectl scale deployment/myapp \
--replicas=${env.K8S_REPLICAS} \
-n ${env.K8S_NAMESPACE}
kubectl rollout status deployment/myapp \
-n ${env.K8S_NAMESPACE} \
--timeout=5m
"""
}
}
}
post {
failure {
sh """
kubectl rollout undo deployment/myapp \
-n ${env.K8S_NAMESPACE}
echo "Deploy başarısız, rollback yapıldı."
"""
}
}
}
Sık Yapılan Hatalar ve Çözümleri
Parametre yönetiminde karşılaşılan yaygın sorunları şöyle sıralayabilirim:
- İlk çalıştırmada parametre eksikliği: Pipeline ilk çalıştırıldığında parametreler kayıt altına alınmamıştır. Çözüm: Pipeline’ı bir kez “default değerlerle” çalıştırın ya da
properties()bloğunu kullanın.
paramsvsenvkarışıklığı:params.FOOkullanıcıdan gelen değerdir,env.FOOise ortam değişkenidir. Parametreden ortam değişkenine taşıma yaparken dikkatli olun; özellikle boolean parametreler string olarak taşınır.
- Password parametrelerinin log’a yazılması:
echo "${params.DB_PASSWORD}"kesinlikle yazmayın. Masking için Jenkins Credentials ya dawithCredentialsbloğu kullanın.
- Choice listesinin güncellenmemesi: Jenkinsfile’da choice listesini güncellediniz ama UI’da eski liste görünüyor. Bu durum pipeline’ın bir kez daha çalışmasını gerektirir.
Scan Multibranch Pipeline Nowya daReplayözelliği işe yarar.
- Parametre tipinin yanlış kullanımı: Boolean parametre
true/falsedöner ama Groovy’de"false"string’i truthy’dir. Her zamanparams.MY_BOOL == trueveya!params.MY_BOOLşeklinde karşılaştırın.
Sonuç
Jenkins’te parametre yönetimi, başlangıçta basit görünse de büyük takımlarda ve çok ortamlı projelerde gerçek bir mimari kararlar bütününe dönüşür. Doğru yapılandırılmış parametreler sayesinde tek bir Jenkinsfile onlarca farklı senaryo için çalışabilir; hem bakım maliyeti düşer hem de insan kaynaklı hatalar azalır.
Özet olarak uygulamanız gereken pratikler şunlardır:
- Parametre setlerini Shared Library’de merkezileştirin, her projede tekrarlamayın
- Doğrulamayı pipeline’ın en başında yapın, geç patlayan hatalardan kaçının
- Hassas değerler için Jenkins Credentials kullan, password parametresine gerçek şifre koyma
- Konfigürasyonları YAML dosyalarına taşı, pipeline kodunu yalın tut
- Production gibi kritik ortamlar için her zaman
inputadımı ekle - Boolean parametreleri string karşılaştırmasında dikkatli kullan
Bu prensipleri bir kez oturttuğunuzda, ekibinizin Jenkins’e olan güveni artar; “acaba doğru ortama mı deploy ettim?” kaygısı tarihe karışır.
