Jenkins ile Slack ve E-posta Bildirimleri Nasıl Yapılandırılır
CI/CD pipeline’larınızda bir şeyler ters gittiğinde, bunu ilk siz öğrenmek istersiniz, değil mi? Build kırıldığında ya da deployment başarısız olduğunda ekibinize anında haber vermek, sorunları hızlı çözmenin temel taşlarından biri. Jenkins’in Slack ve e-posta entegrasyonları tam bu noktada devreye giriyor. Bu yazıda hem Slack hem de e-posta bildirimlerini gerçek dünya senaryolarıyla birlikte nasıl yapılandıracağınızı adım adım göstereceğim.
Neden Bildirim Entegrasyonu Bu Kadar Önemli?
Birkaç yıl önce bir müşteri projesinde çalışırken şöyle bir durumla karşılaştım: Gece 11’de production build kırılmış, sabah 9’a kadar kimsenin haberi olmamış. O 10 saatlik gecikme, ekibe ciddi bir iş kaybı olarak geri döndü. Sonrasında kurduğumuz bildirim sistemi sayesinde benzer durumlar artık dakikalar içinde çözülür hale geldi.
Jenkins bildirimleri şu açılardan kritik:
- Anlık farkındalık: Build başarısız olduğunda ekip saniyeler içinde haberdar olur
- Doğru kişiye doğru bildirim: Geliştirici kendi commit’ini kırdığında önce o görür
- Tarihsel bağlam: E-posta ile kalıcı kayıt tutulur
- Takım koordinasyonu: Slack üzerinden hızlı tartışma ve çözüm imkanı
Gereksinimler
Başlamadan önce şunların hazır olduğundan emin olun:
- Jenkins 2.x kurulu ve çalışıyor
- Jenkins’e admin erişiminiz var
- Bir Slack workspace’i mevcut
- SMTP sunucusuna erişiminiz var (e-posta için)
Slack Entegrasyonu
Slack App ve Webhook Ayarları
Önce Slack tarafında bir Incoming Webhook oluşturmanız gerekiyor. Slack’in API sayfasına gidin, yeni bir app oluşturun ve “Incoming Webhooks” özelliğini aktifleştirin. Size şuna benzer bir URL verecek:
https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX
Bu URL’yi güvenli bir yere kaydedin, ileride Jenkins’e tanımlayacağız.
Jenkins Slack Plugin Kurulumu
Jenkins yönetim panelinde “Manage Jenkins > Manage Plugins” yolunu izleyin. “Available” sekmesinde “Slack Notification” plugin’ini aratın ve kurun. Kurulum sonrası Jenkins’i yeniden başlatmanız gerekebilir.
# Jenkins CLI ile plugin kurulumu (alternatif yöntem)
java -jar jenkins-cli.jar -s http://localhost:8080/
-auth admin:your_api_token
install-plugin slack
Global Slack Yapılandırması
“Manage Jenkins > Configure System” bölümüne gidin. Sayfada “Slack” bölümünü bulacaksınız. Şu alanları doldurun:
- Workspace: Slack workspace adınız (örneğin: mycompany)
- Credential: Webhook URL’nizi buraya ekleyeceksiniz
- Default channel: Bildirimlerin gönderileceği varsayılan kanal (örneğin: #jenkins-builds)
Webhook URL’sini credential olarak eklemek için “Add > Jenkins” seçeneğine tıklayın ve “Secret text” türünü seçin. URL’yi buraya yapıştırın.
Freestyle Job’da Slack Bildirimi
Basit bir freestyle job için post-build action olarak Slack bildirimi ekleyebilirsiniz. Ama asıl güç Jenkinsfile’da gizli.
Declarative Pipeline ile Slack Bildirimleri
Gerçek dünyada en çok kullanılan yöntem Declarative Pipeline. Temel bir örnek:
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'mvn clean package -DskipTests'
}
}
stage('Test') {
steps {
sh 'mvn test'
}
}
stage('Deploy') {
steps {
sh './scripts/deploy.sh staging'
}
}
}
post {
success {
slackSend(
channel: '#deployments',
color: 'good',
message: """
*Build Basarili* :white_check_mark:
Job: ${env.JOB_NAME}
Build: #${env.BUILD_NUMBER}
Branch: ${env.GIT_BRANCH}
Suran: ${currentBuild.durationString}
Detay: ${env.BUILD_URL}
""".stripIndent()
)
}
failure {
slackSend(
channel: '#deployments',
color: 'danger',
message: """
*Build Basarisiz* :x:
Job: ${env.JOB_NAME}
Build: #${env.BUILD_NUMBER}
Branch: ${env.GIT_BRANCH}
Hata Linki: ${env.BUILD_URL}console
""".stripIndent()
)
}
unstable {
slackSend(
channel: '#deployments',
color: 'warning',
message: "*Dikkat* :warning: ${env.JOB_NAME} #${env.BUILD_NUMBER} unstable durumda."
)
}
}
}
Gelismis Slack Mesaj Formatlama
Slack’in Block Kit formatını kullanarak daha zengin bildirimler gönderebilirsiniz. Özellikle production deployment’larında kim ne deploy etti, hangi commit’ten bilgisi kritik:
def sendSlackNotification(String status, String color) {
def commitMsg = sh(
script: 'git log -1 --pretty=%B',
returnStdout: true
).trim()
def commitAuthor = sh(
script: 'git log -1 --pretty=%an',
returnStdout: true
).trim()
def commitHash = sh(
script: 'git rev-parse --short HEAD',
returnStdout: true
).trim()
slackSend(
channel: '#deployments',
color: color,
blocks: """
[
{
"type": "header",
"text": {
"type": "plain_text",
"text": "Jenkins Build: ${status}"
}
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*Job:*\n${env.JOB_NAME}"
},
{
"type": "mrkdwn",
"text": "*Build:*\n#${env.BUILD_NUMBER}"
},
{
"type": "mrkdwn",
"text": "*Gelistirici:*\n${commitAuthor}"
},
{
"type": "mrkdwn",
"text": "*Commit:*\n${commitHash}"
}
]
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Commit Mesaji:*\n${commitMsg}"
}
}
]
"""
)
}
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'make build'
}
}
}
post {
success {
script {
sendSlackNotification('BASARILI :rocket:', 'good')
}
}
failure {
script {
sendSlackNotification('BASARISIZ :fire:', 'danger')
}
}
}
}
Farkli Kanallar icin Farklı Bildirimler
Gerçek dünyada production, staging ve development ortamları için farklı Slack kanalları kullanmak çok daha temiz bir yapı sağlar:
def getSlackChannel() {
if (env.GIT_BRANCH == 'main' || env.GIT_BRANCH == 'master') {
return '#production-alerts'
} else if (env.GIT_BRANCH == 'develop') {
return '#staging-builds'
} else {
return '#dev-builds'
}
}
pipeline {
agent any
stages {
stage('Build & Test') {
steps {
sh 'npm install && npm test'
}
}
}
post {
always {
script {
def channel = getSlackChannel()
def buildStatus = currentBuild.currentResult
def color = buildStatus == 'SUCCESS' ? 'good' :
buildStatus == 'UNSTABLE' ? 'warning' : 'danger'
slackSend(
channel: channel,
color: color,
message: "${buildStatus}: ${env.JOB_NAME} #${env.BUILD_NUMBER} | ${env.GIT_BRANCH} | ${env.BUILD_URL}"
)
}
}
}
}
E-posta Bildirimleri
SMTP Yapılandırması
“Manage Jenkins > Configure System” bölümünde “E-mail Notification” ve “Extended E-mail Notification” bölümlerini bulun. Önce temel SMTP ayarlarını yapın:
# Jenkins sistem yapılandırmasını test etmek için
# SMTP bağlantısını doğrulamak adına basit bir test maili gönderebilirsiniz
curl -s --url 'smtps://smtp.gmail.com:465'
--ssl-reqd
--mail-from '[email protected]'
--mail-rcpt '[email protected]'
--user '[email protected]:your_password'
-T /dev/stdin <<< "Subject: Jenkins Test Mail
Bu bir test mailidir."
Gmail kullanıyorsanız şu ayarları girin:
- SMTP Server: smtp.gmail.com
- Use SSL: Isaretli
- SMTP Port: 465
- Reply-To Address: [email protected]
- Charset: UTF-8
Kurumsal ortamda genellikle şirketin kendi SMTP relay’i kullanılır. O durumda IT ekibinizden SMTP host adresi, port ve gerekiyorsa kimlik bilgilerini alın.
Extended Email Plugin Kurulumu
Temel e-posta plugin’inin ötesinde zengin içerikli mailler için “Email Extension Plugin” şart. Bu plugin varsayılan olarak çoğu Jenkins kurulumunda geliyor ama yoksa Manage Plugins’den kurabilirsiniz.
Basit E-posta Bildirimi (Declarative Pipeline)
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'gradle build'
}
}
stage('Test') {
steps {
sh 'gradle test'
junit 'build/test-results/**/*.xml'
}
}
}
post {
failure {
mail(
to: '[email protected]',
subject: "[JENKINS-HATA] ${env.JOB_NAME} #${env.BUILD_NUMBER}",
body: """
Build basarisiz oldu!
Job: ${env.JOB_NAME}
Build No: ${env.BUILD_NUMBER}
Branch: ${env.GIT_BRANCH}
Baslangic: ${currentBuild.startTimeInMillis}
Build logunu incelemek icin:
${env.BUILD_URL}console
Bu mail otomatik olarak Jenkins tarafindan gonderilmistir.
"""
)
}
success {
mail(
to: '[email protected]',
subject: "[JENKINS-OK] ${env.JOB_NAME} #${env.BUILD_NUMBER} Basarili",
body: "Build basariyla tamamlandi. Detay: ${env.BUILD_URL}"
)
}
}
}
Extended E-mail ile HTML Mail Sablonlari
Kurumsal ortamlarda sade metin yerine HTML formatli mailler çok daha profesyonel görünür. Test sonuçları, coverage raporu gibi bilgileri de ekleyebilirsiniz:
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'mvn clean package'
}
}
stage('Test') {
steps {
sh 'mvn test'
junit allowEmptyResults: true, testResults: 'target/surefire-reports/*.xml'
jacoco(
execPattern: 'target/jacoco.exec',
classPattern: 'target/classes',
sourcePattern: 'src/main/java'
)
}
}
}
post {
always {
emailext(
to: '[email protected]',
subject: "[Jenkins] ${currentBuild.currentResult}: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
mimeType: 'text/html',
body: """
<html>
<head>
<style>
body { font-family: Arial, sans-serif; }
.header { background-color: #336791; color: white; padding: 10px; }
.success { color: #28a745; }
.failure { color: #dc3545; }
.info { background-color: #f8f9fa; padding: 10px; border-left: 4px solid #336791; }
</style>
</head>
<body>
<div class="header">
<h2>Jenkins Build Raporu</h2>
</div>
<div class="info">
<p><strong>Job:</strong> ${env.JOB_NAME}</p>
<p><strong>Build:</strong> #${env.BUILD_NUMBER}</p>
<p><strong>Durum:</strong>
<span class="${currentBuild.currentResult == 'SUCCESS' ? 'success' : 'failure'}">
${currentBuild.currentResult}
</span>
</p>
<p><strong>Branch:</strong> ${env.GIT_BRANCH ?: 'Bilinmiyor'}</p>
<p><strong>Sure:</strong> ${currentBuild.durationString}</p>
</div>
<p><a href="${env.BUILD_URL}">Build detaylarini gormek icin tiklayin</a></p>
<p><a href="${env.BUILD_URL}testReport">Test raporunu gormek icin tiklayin</a></p>
<hr>
<small>Bu mail Jenkins tarafindan otomatik gonderilmistir.</small>
</body>
</html>
""",
attachLog: currentBuild.currentResult == 'FAILURE',
compressLog: true
)
}
}
}
Akilli E-posta Stratejisi: Sadece Degistiğinde Bildir
Her build’de mail atmak ekibi yorar ve maillerle ilgilenmeyi bırakırlar. En iyi strateji sadece durum değiştiğinde bildirmek:
def shouldSendEmail() {
def previousResult = currentBuild.previousBuild?.result
def currentResult = currentBuild.currentResult
// Ilk kez basarisiz oluyorsa bildir
if (currentResult == 'FAILURE' && previousResult != 'FAILURE') {
return true
}
// Basarisiz durumdan kurtulduysa bildir
if (currentResult == 'SUCCESS' && previousResult == 'FAILURE') {
return true
}
// Unstable duruma dustuyse bildir
if (currentResult == 'UNSTABLE') {
return true
}
return false
}
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'make all'
}
}
}
post {
always {
script {
if (shouldSendEmail()) {
def subject = currentBuild.currentResult == 'SUCCESS' ?
"[COZULDU] ${env.JOB_NAME} tekrar calisiyor" :
"[HATA] ${env.JOB_NAME} basarisiz"
emailext(
to: '[email protected]',
subject: subject,
body: """
Build durumu degisti!
Onceki durum: ${currentBuild.previousBuild?.result ?: 'Yok'}
Yeni durum: ${currentBuild.currentResult}
Detay: ${env.BUILD_URL}
"""
)
}
}
}
}
}
Slack ve E-posta’yi Birlikte Kullanmak
Gerçek projelerde ikisini birden, farklı amaçlar için kullanmak en sağlıklı yaklaşım. Slack anlık farkındalık için, e-posta ise kalıcı kayıt ve yöneticilere raporlama için:
def notifyTeam(String status) {
def isProduction = env.GIT_BRANCH == 'main' || env.GIT_BRANCH == 'master'
def color = status == 'SUCCESS' ? 'good' : status == 'UNSTABLE' ? 'warning' : 'danger'
def emoji = status == 'SUCCESS' ? ':white_check_mark:' :
status == 'UNSTABLE' ? ':warning:' : ':x:'
// Her durumda Slack'e bildir
slackSend(
channel: isProduction ? '#production-alerts' : '#dev-builds',
color: color,
message: "${emoji} *${status}* | ${env.JOB_NAME} #${env.BUILD_NUMBER} | ${env.GIT_BRANCH} | ${env.BUILD_URL}"
)
// Sadece production'da ya da hata durumunda mail at
if (isProduction || status == 'FAILURE') {
def recipients = isProduction ?
'[email protected],[email protected]' :
'[email protected]'
emailext(
to: recipients,
subject: "[Jenkins-${status}] ${env.JOB_NAME} #${env.BUILD_NUMBER}",
body: """
Build tamamlandi.
Durum: ${status}
Job: ${env.JOB_NAME}
Build: #${env.BUILD_NUMBER}
Ortam: ${isProduction ? 'PRODUCTION' : 'Development'}
Branch: ${env.GIT_BRANCH}
Detay: ${env.BUILD_URL}
"""
)
}
}
pipeline {
agent any
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Build') {
steps {
sh 'docker build -t myapp:${BUILD_NUMBER} .'
}
}
stage('Test') {
steps {
sh 'docker run --rm myapp:${BUILD_NUMBER} npm test'
}
}
stage('Deploy') {
when {
anyOf {
branch 'main'
branch 'develop'
}
}
steps {
sh './deploy.sh ${GIT_BRANCH}'
}
}
}
post {
success {
script { notifyTeam('SUCCESS') }
}
failure {
script { notifyTeam('FAILURE') }
}
unstable {
script { notifyTeam('UNSTABLE') }
}
}
}
Sık Karşılaşılan Sorunlar ve Çözümleri
Slack Webhook 403 Hatası
Webhook URL’sinin doğru credential tipinde saklandığından emin olun. “Secret text” tipini kullanın. Ayrıca Jenkins’in dış internete çıkabildiğini kontrol edin:
# Jenkins sunucusundan Slack'e erişim testi
curl -s -o /dev/null -w "%{http_code}"
-X POST
-H 'Content-type: application/json'
--data '{"text":"Jenkins test mesaji"}'
https://hooks.slack.com/services/YOUR/WEBHOOK/URL
# 200 donmeli
SMTP SSL/TLS Sertifika Sorunu
Kurumsal ortamlarda self-signed sertifika kullanan SMTP sunucularında sorun yaşanabilir:
# Java keystore'a sertifika eklemek icin
keytool -import
-alias smtp-server
-keystore $JAVA_HOME/lib/security/cacerts
-file smtp-cert.crt
-storepass changeit
-noprompt
# Jenkins'i yeniden baslat
systemctl restart jenkins
Pipeline’da Bildirim Gelmemesi
Post bloğunun agent tanımlamasından bağımsız çalıştığından emin olun. Bazen agent none tanımlandığında post bloğunda script çalıştırılamayabilir:
pipeline {
agent none
stages {
stage('Build') {
agent { label 'build-server' }
steps {
sh 'make build'
}
}
}
post {
// agent none olduğunda bu blok master'da calisir
// slackSend burada calismayabilir, agent belirtmek gerekebilir
failure {
node('master') {
slackSend channel: '#alerts', message: "Build basarisiz: ${env.JOB_NAME}"
}
}
}
}
Guvenlik ve En Iyi Uygulamalar
Bildirim sistemi kurarken güvenlik açısından dikkat edilmesi gerekenler:
- Kimlik bilgilerini asla Jenkinsfile’a yazmayın: Webhook URL’leri ve SMTP şifreleri her zaman Jenkins Credentials Manager’da tutun
- Mail listelerini sınırlı tutun: Herkesin her build’den haberdar olması bildirim yorgunluğuna yol açar
- Kanal stratejisi belirleyin: Production, staging, dev için ayrı kanallar oluşturun
- Rate limiting’e dikkat edin: Paralel çok sayıda build varsa Slack API rate limit’ine takılabilirsiniz
- Log eklerini dikkatli kullanın:
attachLog: trueayarı büyük projelerde çok büyük mail eklerine neden olabilir, bunu sadece hata durumunda aktif edin
# Jenkins credentials'larini CLI ile listeleme (audit amacli)
java -jar jenkins-cli.jar
-s http://localhost:8080/
-auth admin:your_token
list-credentials system::system::jenkins
Sonuç
Jenkins’in Slack ve e-posta entegrasyonu, görünürde basit ama doğru yapılandırıldığında ekip verimliliğine ciddi katkı sağlayan bir konu. Temel prensipler şunlar: Slack anlık iletişim için, e-posta ise kalıcı kayıt ve üst yönetim raporlaması için kullanın. Her build’de bildirim göndermek yerine durum değişikliklerinde bildirin. Production ortamı için daha agresif bir bildirim politikası uygularken development branch’leri için daha sessiz bir yapı tercih edin.
Kurduğunuz sistem ne kadar zeki olursa, ekibiniz o kadar az “bildirim körlüğü” yaşar ve gerçek sorunlara odaklanabilir. Webhook URL’lerinizi ve SMTP kimlik bilgilerinizi her zaman Credentials Manager’da saklayın, bunları Jenkinsfile içine gömmekten kaçının. Zamanla bu yapıyı shared library’ye taşıyarak tüm projelerinizde ortak bir bildirim standardı oluşturabilirsiniz, bu ise ayrı bir yazı konusu.
