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: true ayarı 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.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir