Jenkins, CI/CD dünyasının en eski ve en yaygın araçlarından biri. Bulut tabanlı seçeneklerin popülerleştiği bir dönemde bile hâlâ ayakta olmasının somut bir sebebi var: kendi sunucunda çalışır, dış bir servise bağımlı değildir, eklenti ekosistemi neredeyse her sisteme bağlanır ve dakika kotası diye bir kavramı yoktur. Özel ağdaki bir veritabanına erişmesi gereken ya da kaynak kodunu dışarı çıkarmak istemeyen ekipler için hâlâ ilk akla gelen araç.
Karşılığında Jenkins seni bir sunucunun sorumluluğuyla baş başa bırakır: sürüm yükseltmeleri, eklenti güncellemeleri, disk temizliği ve güvenlik sıkılaştırması senin işindir. Bu rehberde Jenkins kurulumunu Docker ile temiz bir şekilde yapacağız, ilk açılıştaki eklenti kararlarını doğru vereceğiz, Jenkinsfile ile deponun içinde yaşayan bir pipeline yazacağız, kimlik bilgilerini güvenli biçimde saklayacağız ve işleri agent'lara dağıtacağız.
Jenkins Ne Zaman Doğru Seçim#
Karar vermeden önce net olalım. Kodun GitHub'daysa ve özel bir gereksinimin yoksa, GitHub Actions ile CI/CD kurulumu neredeyse her zaman daha az sürtünmeli olacaktır; sunucu işletmezsin, yetkilendirme deponun kendisinden gelir. Aynı şekilde GitLab kullanıyorsan GitLab CI pipeline doğal tercihtir.
Jenkins şu üç durumda öne çıkar. Birincisi, hattın özel ağdaki kaynaklara erişmesi gerektiğinde: dış bir CI servisine veritabanı ya da iç kayıt defteri açmak istemiyorsan Jenkins zaten ağın içinde durur. İkincisi, çok çeşitli sistemlerle konuşman gerektiğinde: eski bir uygulama sunucusu, bir SAP kurulumu, Windows tabanlı bir derleme adımı ya da özel bir donanım — eklenti ekosistemi bu tür bağlantılarda hâlâ eşsizdir. Üçüncüsü, kullanım hacmi yüksekse: dakika başına ücretlendirilmeyen, sadece sunucu maliyeti olan bir hat, günde yüzlerce derlemede belirgin biçimde ucuzlar.
| Kriter | Jenkins | Barındırılan CI (Actions/GitLab CI) |
|---|---|---|
| Sunucu bakımı | Sende | Sağlayıcıda |
| Özel ağ erişimi | Doğrudan | Tünel/self-hosted runner gerekir |
| Maliyet modeli | Sunucu kirası | Dakika kotası |
| İlk kurulum süresi | Yarım gün | Dakikalar |
| Eklenti çeşitliliği | Çok geniş | Sınırlı ama yeterli |
Docker ile Kurulum#
Jenkins'i paket yöneticisiyle de kurabilirsin ama Docker ile kurmak sürüm yükseltmelerini ve geri almayı çok kolaylaştırır. Önce kalıcı veri için bir volume oluştur — Jenkins'in tüm yapılandırması, iş tanımları ve eklentileri bu dizinde yaşar:
# Kalıcı veri hacmi
docker volume create jenkins-veri
# Jenkins'i başlat
docker run -d --name jenkins \
--restart unless-stopped \
-p 8080:8080 \
-p 50000:50000 \
-v jenkins-veri:/var/jenkins_home \
-e JAVA_OPTS="-Djenkins.install.runSetupWizard=true" \
jenkins/jenkins:lts
# İlk açılış parolasını al
docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
8080 web arayüzü, 50000 ise uzak agent'ların bağlandığı porttur; agent kullanmayacaksan ikinci portu hiç yayınlama. Volume'ün gerçekten kalıcı olduğundan emin ol; /var/jenkins_home dizinini kaybetmek, tüm iş tanımlarını ve kimlik bilgilerini kaybetmek demektir. Veri hacimlerinin nasıl yönetildiğini ve yedeklendiğini Docker volume veri yönetimi yazısında ayrıntılı anlattım.
Üretimde Jenkins'i doğrudan 8080 portunda yayına açma. Önüne bir ters vekil koy, TLS'i orada sonlandır ve arayüzü yalnızca HTTPS üzerinden servis et:
server {
listen 443 ssl;
server_name jenkins.firmaniz.com;
ssl_certificate /etc/letsencrypt/live/jenkins.firmaniz.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/jenkins.firmaniz.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Konsol çıktısının canlı akması için tamponlamayı kapat
proxy_buffering off;
proxy_read_timeout 300s;
}
}
İlk Açılış ve Eklenti Kararları#
Tarayıcıdan adrese gittiğinde Jenkins ilk kurulum sihirbazını açar ve yukarıda aldığın parolayı ister. Ardından iki seçenek sunar: önerilen eklentileri kur ya da kendin seç. Yeni başlıyorsan önerilen eklentiler doğru tercihtir; Git, Pipeline, Credentials Binding gibi olmazsa olmazları getirir.
Sihirbaz bitince şu dört eklentiyi ayrıca değerlendir:
- Pipeline: Stage View — pipeline aşamalarını görsel olarak gösterir, hata ayıklamayı ciddi biçimde kolaylaştırır.
- Docker Pipeline —
Jenkinsfileiçindedocker.buildvedocker.image().inside {}gibi adımları kullanmanı sağlar. - Configuration as Code (JCasC) — Jenkins yapılandırmasını bir YAML dosyasından okur; sunucuyu sıfırdan kurmak zorunda kaldığında hayat kurtarır.
- Role-based Authorization Strategy — kullanıcı yetkilerini rol bazında yönetir; varsayılan matris yetkilendirmesinden çok daha yönetilebilir.
Eklenti konusunda tek bir uyarım var: her eklenti bir bakım yüküdür. Jenkins'te yaşanan güvenlik açıklarının önemli bir kısmı çekirdekten değil, eklentilerden gelir. İhtiyacın olmayan eklentiyi kurma, kurduğunu güncel tut ve arayüzdeki güvenlik uyarılarını ciddiye al.
Jenkinsfile ile Pipeline Yazmak#
Jenkins'te işleri arayüzden tıklayarak da tanımlayabilirsin ama bunu yapma. Pipeline tanımını deponun köküne Jenkinsfile olarak koy; böylece hattın da sürüm kontrolünde yaşar, kod incelemesinden geçer ve dal bazında farklılaşabilir. İki söz dizimi vardır; declarative olanı okunabilir ve yeni başlayanlar için doğru tercihtir:
pipeline {
agent any
options {
timeout(time: 30, unit: 'MINUTES') // takılan işi kes
buildDiscarder(logRotator(numToKeepStr: '20')) // eski derlemeleri sil
disableConcurrentBuilds() // aynı işten iki tane çalışmasın
}
environment {
IMAJ = "kayit.firmaniz.com/api:${env.GIT_COMMIT.take(8)}"
}
stages {
stage('Testler') {
agent { docker { image 'node:22-alpine' } }
steps {
sh 'npm ci'
sh 'npm run lint'
sh 'npm test'
}
}
stage('İmaj') {
when { branch 'main' } // yalnızca ana dalda
steps {
sh 'docker build -t $IMAJ .'
withCredentials([usernamePassword(
credentialsId: 'kayit-defteri',
usernameVariable: 'KULLANICI',
passwordVariable: 'PAROLA')]) {
sh 'echo "$PAROLA" | docker login kayit.firmaniz.com -u "$KULLANICI" --password-stdin'
sh 'docker push $IMAJ'
}
}
}
stage('Dağıtım') {
when { branch 'main' }
steps {
// Üretime çıkmadan önce insan onayı
timeout(time: 15, unit: 'MINUTES') {
input message: 'Üretime dağıtılsın mı?', ok: 'Dağıt'
}
sshagent(['uretim-ssh']) {
sh '''
ssh -o StrictHostKeyChecking=accept-new [email protected] \
"cd /srv/uygulama && docker compose pull && docker compose up -d"
'''
}
}
}
}
post {
always { cleanWs() } // çalışma alanını temizle
failure { echo 'Derleme başarısız; logları inceleyin.' }
}
}
Bu dosyada dört alışkanlığa dikkat çekmek isterim. buildDiscarder olmadan Jenkins her derlemenin log ve artifact'ını sonsuza kadar saklar ve disk yavaşça dolar. timeout olmadan takılan bir test executor'ı kilitler. disableConcurrentBuilds olmadan arka arkaya iki push aynı sunucuya iki dağıtım gönderebilir. cleanWs() olmadan çalışma alanı büyür ve önceki derlemeden kalan dosyalar sonrakini kirletir.
Depoyu Jenkins'e tanıtmak için arayüzde New Item → Multibranch Pipeline seç; Jenkins depodaki tüm dalları tarar, Jenkinsfile bulduğu her dal için otomatik bir iş oluşturur. Depoyu kendi sunucunda barındırıyorsan Gitea ile kendi Git sunucun Jenkins'e webhook göndererek bu taramayı anlık hâle getirebilir.
Kimlik Bilgilerini Doğru Saklamak#
Jenkins'in Credentials deposu, parolaları Jenkinsfile içine yazmanı önleyen mekanizmadır. Arayüzde Manage Jenkins → Credentials yolundan tanımlarsın ve pipeline'da yalnızca kimlik id'sini kullanırsın. Beş tip vardır ve doğru tipi seçmek işini kolaylaştırır:
| Tip | Ne için | Pipeline'da kullanım |
|---|---|---|
| Secret text | API anahtarı, token | withCredentials([string(...)]) |
| Username with password | Kayıt defteri, veritabanı | usernamePassword(...) |
| SSH Username with private key | Sunucuya dağıtım | sshagent(['id']) |
| Secret file | kubeconfig, servis hesabı | file(credentialsId: ...) |
| Certificate | İstemci sertifikası | Özel eklentilerle |
Kritik kural şudur: kimlik bilgilerini withCredentials bloğunun dışına taşıma. Blok içinde değişkenler tanımlıdır ve Jenkins bunların log'da geçen değerlerini maskeler; bloğun dışında maskeleme yoktur. Ayrıca sh "echo $PAROLA" gibi çift tırnaklı Groovy dizeleri değişkeni Groovy tarafında genişletir ve parola komut satırına yazılır; tek tırnak kullan ki kabuk genişletsin ve ps çıktısında görünmesin.
Kapsam ayarına da dikkat et. Global kapsamdaki bir kimlik tüm işlerden erişilebilir; üretim SSH anahtarını yalnızca ilgili klasöre ya da işe tanımlamak blast radius'u ciddi biçimde küçültür.
Agent'lar ve İş Dağıtımı#
Küçük kurulumlarda her şeyi controller (eski adıyla master) üzerinde çalıştırmak cazip gelir ama bu, üretimde kaçınman gereken bir kalıptır. Controller üzerinde derleme yapmak iki sorun yaratır: derlemeler Jenkins'in kendi kaynağını tüketir ve pipeline kodu controller'ın dosya sistemine, dolayısıyla tüm kimlik bilgilerine erişir.
Doğru yapı, işleri agent'lara dağıtmaktır. En kolay yöntem Docker agent'ıdır; Jenkinsfile içindeki agent { docker { image '...' } } bloğu her aşamayı temiz bir konteynerde çalıştırır. Ayrı bir sunucuyu kalıcı agent yapmak istersen SSH üzerinden bağlarsın:
# Agent sunucusunda hazırlık
sudo useradd -m -s /bin/bash jenkins
sudo usermod -aG docker jenkins # Docker kullanacaksa
sudo mkdir -p /var/jenkins && sudo chown jenkins:jenkins /var/jenkins
# Java gerekir (agent JVM ile çalışır)
sudo apt-get install -y openjdk-17-jre-headless
Ardından Jenkins arayüzünde Manage Jenkins → Nodes → New Node ile düğümü tanımlar, bağlantı yöntemi olarak SSH seçer ve yukarıda oluşturduğun kullanıcının anahtarını Credentials'tan gösterirsin. Düğüme etiket vermeyi unutma (linux, docker, windows gibi); Jenkinsfile içinde agent { label 'docker' } yazarak işi doğru makineye yönlendirirsin.
Docker grubuna kullanıcı eklemenin aslında root'a denk bir yetki olduğunu unutma; bu konudaki ayrıntılar ve daha güvenli alternatifler Docker daemon socket permission denied yazısında.
Sık Yapılan Hatalar ve Tuzaklar#
Controller üzerinde derleme yapmak. Controller'ın executor sayısını sıfıra çekmek, işlerin mutlaka agent'a düşmesini garanti eder ve hem güvenlik hem performans açısından doğrusudur.
Eski derlemeleri temizlememek. buildDiscarder tanımsızsa Jenkins her derlemenin log'unu ve artifact'ını sonsuza kadar saklar. Aylar sonra /var/jenkins_home gigabaytlarca yer kaplar ve arayüz yavaşlar. Her işe bir saklama politikası koy.
Eklentileri güncellemeyi ertelemek. Jenkins güvenlik uyarılarının büyük kısmı eklentilerle ilgilidir ve arayüzde açıkça listelenir. Güncellemeden önce /var/jenkins_home dizininin yedeğini almak, bir eklentinin bozulması hâlinde geri dönmeni sağlar.
Jenkins'i doğrudan internete açmak. Arayüz TLS olmadan yayınlandığında oturum çerezleri açıkta gider. Ters vekil arkasına al, mümkünse yalnızca VPN veya belirli IP'lerden erişime izin ver.
Anonim kullanıcıya okuma yetkisi bırakmak. Varsayılan bazı yapılandırmalarda iş adları ve konsol çıktıları oturum açmadan görülebilir. Konsol çıktısı sık sık dosya yolları, sunucu adları ve bazen maskelenmemiş değerler içerir.
Pipeline'ı arayüzden yazmak. Arayüzde tanımlanan bir pipeline sürüm kontrolünde değildir; kim ne zaman değiştirdi bilinmez ve sunucu kaybolduğunda gider. Jenkinsfile bunun için var.
Sıkça Sorulan Sorular#
Jenkins ücretsiz mi#
Evet, Jenkins açık kaynaklıdır ve MIT lisansıyla ücretsiz dağıtılır; kullanıcı sayısı, iş sayısı veya derleme dakikası için hiçbir ücret ödemezsin. Tek maliyetin çalıştığı sunucudur. Ticari destek isteyen kurumlar için üçüncü taraf sağlayıcıların paketleri vardır, ancak yazılımın kendisi her zaman ücretsizdir.
Jenkins için ne kadar kaynak gerekir#
Küçük bir ekipte, günde birkaç düzine derleme için 2 çekirdek ve 4 GB bellek makul bir başlangıçtır; JVM tabanlı olduğu için bellek asıl darboğazdır. Derlemeler agent'larda çalışıyorsa controller daha az kaynakla idare eder. Disk tarafında /var/jenkins_home beklenenden hızlı büyür; en az 40 GB ile başlayıp saklama politikası uygulamanı öneririm.
İlk açılış parolasını kaybettim, ne yapmalıyım#
Parola, Jenkins ana dizinindeki secrets/initialAdminPassword dosyasında durur. Docker ile kurduysan docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword komutu yeterlidir; paketle kurduysan dosya genellikle /var/lib/jenkins/secrets/ altındadır. Kurulum tamamlandıktan sonra bu dosya artık kullanılmaz; yönetici parolasını unuttuysan yapılandırma dosyasından güvenliği geçici olarak kapatıp yeniden ayarlaman gerekir.
Jenkins mi GitHub Actions mı seçmeliyim#
Kodun GitHub'daysa ve özel ağ erişimi gerektiren bir adımın yoksa Actions daha az bakım ister ve daha hızlı kurulur. Jenkins'i şu üç durumda tercih et: hattın iç ağdaki kaynaklara erişmeli, çok sayıda farklı sistemle konuşmalı ya da derleme hacmin dakika kotalarını ekonomik olmaktan çıkarmalı. İkisini birlikte kullanan ekipler de var; testler Actions'ta, iç dağıtım Jenkins'te çalışır.
Jenkinsfile'ı nasıl test ederim#
Küçük değişiklikleri denemek için ayrı bir dalda çalışmak en pratik yöntemdir; Multibranch Pipeline o dal için otomatik bir iş oluşturur ve üretim işini etkilemezsin. Söz dizimini önceden doğrulamak için Jenkins'in sunduğu declarative doğrulama uç noktasını ya da arayüzdeki "Replay" özelliğini kullanabilirsin; Replay, mevcut derlemenin pipeline kodunu düzenleyip yeniden çalıştırmanı sağlar ve depoya commit atmadan deneme yapmanın en hızlı yoludur.
Jenkins'i nasıl yedeklerim#
Tek bir dizini yedeklemen yeterlidir: /var/jenkins_home. İş tanımları, eklentiler, kimlik bilgileri ve derleme geçmişi hepsi buradadır. Yedeği alırken Jenkins'i durdurmak tutarlılığı garanti eder; duraklatamıyorsan en azından yedek sırasında derleme çalışmadığından emin ol. Kimlik bilgileri şifreli saklandığı için secrets/ klasörünü de mutlaka yedeğe dahil et — o klasör olmadan geri yüklenen bir Jenkins parolaları çözemez.
Kapanış#
Jenkins'i sağlıklı işletmenin özeti şu alışkanlıklarda: pipeline'ı Jenkinsfile ile depoda tut, derlemeleri controller'da değil agent'larda çalıştır, her işe buildDiscarder ve timeout koy, kimlik bilgilerini yalnızca withCredentials blokları içinde kullan ve /var/jenkins_home dizinini düzenli yedekle. Bu beşi yerindeyse Jenkins yıllarca sorunsuz çalışır; eksik olduğunda ise sorunlar sessizce birikir ve genellikle disk dolduğunda fark edilir.
Jenkins controller'ını ve agent'larını barındırmak için tam root erişimli VDS ya da yük arttıkça büyüyebilen bulut sunucu paketlerimiz uygun bir zemin sunar; agent'ları ayrı makinelerde tutmak istersen sanal sunucu seçeneği ekonomik bir başlangıçtır. Sunucu kurulumu, güncellemeler ve yedekleme planıyla uğraşmak istemiyorsan sunucu yönetimi ve yedekleme hizmetlerimiz bu işi sizin yerinize yürütür.