Jenkins 빌드 실패 시 Discord로 알림 받기 - Webhook 5분 설정
Jenkins 빌드가 실패했는데 나중에 확인하면 시간 낭비다. Discord Webhook을 사용하면 빌드 실패 즉시 알림 을 받을 수 있다.
설정은 5분이면 끝 난다. 플러그인 설치도 필요 없고, 그냥 curl로 Discord API 호출하면 된다.
왜 Discord Webhook인가
다른 방법들과 비교
| 방법 | 장점 | 단점 |
|---|---|---|
| Discord Webhook | 설정 간단, 플러그인 불필요, 무료 | - |
| Jenkins 이메일 | 기본 기능 | 스팸함 가능성, 확인 느림 |
| Slack Webhook | 업무용 좋음 | 유료 플랜 필요 (무료는 90일 제한) |
| Jenkins Plugin | 기능 많음 | 설치/설정 복잡 |
Discord Webhook의 장점:
- ✅ 무료
- ✅ 플러그인 설치 불필요
- ✅ 5분 설정
- ✅ 실시간 알림 (모바일 앱)
- ✅ 예쁜 Embed 메시지
설정 방법
1단계: Discord Webhook 생성
1-1. Discord 채널 설정
알림을 받고 싶은 채널(예: #ci-cd, #alerts)에서:
- 채널 설정 (톱니바퀴 아이콘) 클릭
- 연동 탭 클릭
- 웹후크 클릭
- 새 웹후크 클릭
1-2. Webhook 설정
- 이름:
Jenkins Bot(원하는 이름) - 아바타: 원하는 이미지 (선택사항)
웹후크 URL 복사 클릭
URL 형식: https://discord.com/api/webhooks/123456789012345678/abcdefghijklmnopqrstuvwxyz...
⚠️ 주의: 이 URL은 비밀번호처럼 관리해야 한다. 누구나 이 URL로 메시지를 보낼 수 있다.
2단계: Jenkinsfile 설정
기본 설정 (빌드 실패 알림)
pipeline {
agent any
environment {
DISCORD_WEBHOOK = 'https://discord.com/api/webhooks/YOUR_WEBHOOK_URL'
}
stages {
stage('Build') {
steps {
sh 'npm run build'
}
}
stage('Test') {
steps {
sh 'npm test'
}
}
}
post {
failure {
sh """
curl -X POST \${DISCORD_WEBHOOK} \
-H "Content-Type: application/json" \
-d '{
"content": "🚨 **빌드 실패!**",
"embeds": [{
"title": "${JOB_NAME} #${BUILD_NUMBER}",
"url": "${BUILD_URL}console",
"color": 15158332,
"fields": [
{
"name": "브랜치",
"value": "${GIT_BRANCH}",
"inline": true
},
{
"name": "커밋",
"value": "${GIT_COMMIT}",
"inline": true
}
]
}]
}'
"""
}
}
}
성공/실패 알림 모두 받기
post {
success {
sh """
curl -X POST \${DISCORD_WEBHOOK} \
-H "Content-Type: application/json" \
-d '{
"content": "✅ **빌드 성공!**",
"embeds": [{
"title": "${JOB_NAME} #${BUILD_NUMBER}",
"url": "${BUILD_URL}",
"color": 3066993,
"description": "모든 테스트 통과"
}]
}'
"""
}
failure {
sh """
curl -X POST \${DISCORD_WEBHOOK} \
-H "Content-Type: application/json" \
-d '{
"content": "🚨 **빌드 실패!**",
"embeds": [{
"title": "${JOB_NAME} #${BUILD_NUMBER}",
"url": "${BUILD_URL}console",
"color": 15158332,
"description": "빌드 또는 테스트 실패"
}]
}'
"""
}
}
3단계: 테스트
의도적으로 빌드 실패시키기
stage('Test') {
steps {
sh 'exit 1' // 강제로 실패
}
}
빌드를 실행하면 Discord 채널에 알림이 와야 한다!
고급 설정
특정 사용자 멘션
빌드 실패 시 특정 사용자에게 알림:
failure {
sh """
curl -X POST \${DISCORD_WEBHOOK} \
-H "Content-Type: application/json" \
-d '{
"content": "<@YOUR_USER_ID> 🚨 빌드 실패!",
"embeds": [{
"title": "${JOB_NAME} #${BUILD_NUMBER}",
"url": "${BUILD_URL}console",
"color": 15158332
}]
}'
"""
}
User ID 확인 방법:
- Discord에서 사용자 설정 → 고급 → 개발자 모드 켜기
- 자신의 프로필 우클릭 → 사용자 ID 복사
에러 로그 포함
마지막 20줄의 에러 로그를 포함:
failure {
script {
def log = sh(
script: "tail -20 ${WORKSPACE}/build.log || echo 'No log available'",
returnStdout: true
).trim()
sh """
curl -X POST \${DISCORD_WEBHOOK} \
-H "Content-Type: application/json" \
-d '{
"content": "🚨 **빌드 실패!**",
"embeds": [{
"title": "${JOB_NAME} #${BUILD_NUMBER}",
"url": "${BUILD_URL}console",
"color": 15158332,
"fields": [{
"name": "에러 로그 (마지막 20줄)",
"value": "\\`\\`\\`${log}\\`\\`\\`"
}]
}]
}'
"""
}
}
브랜치별 다른 채널
main 브랜치는 중요한 채널, develop은 일반 채널:
environment {
DISCORD_WEBHOOK_MAIN = 'https://discord.com/api/webhooks/MAIN_WEBHOOK'
DISCORD_WEBHOOK_DEV = 'https://discord.com/api/webhooks/DEV_WEBHOOK'
}
post {
failure {
script {
def webhook = env.GIT_BRANCH == 'main' ?
env.DISCORD_WEBHOOK_MAIN : env.DISCORD_WEBHOOK_DEV
sh """
curl -X POST ${webhook} \
-H "Content-Type: application/json" \
-d '{
"content": "🚨 빌드 실패!",
"embeds": [{
"title": "${JOB_NAME} #${BUILD_NUMBER}",
"url": "${BUILD_URL}console",
"color": 15158332
}]
}'
"""
}
}
}
빌드 시간 표시
post {
always {
script {
def duration = currentBuild.durationString.replace(' and counting', '')
def status = currentBuild.result == 'SUCCESS' ? '✅' : '🚨'
def color = currentBuild.result == 'SUCCESS' ? 3066993 : 15158332
sh """
curl -X POST \${DISCORD_WEBHOOK} \
-H "Content-Type: application/json" \
-d '{
"content": "${status} 빌드 ${currentBuild.result}",
"embeds": [{
"title": "${JOB_NAME} #${BUILD_NUMBER}",
"url": "${BUILD_URL}",
"color": ${color},
"fields": [
{
"name": "소요 시간",
"value": "${duration}",
"inline": true
},
{
"name": "브랜치",
"value": "${GIT_BRANCH}",
"inline": true
}
],
"timestamp": "${new Date().format("yyyy-MM-dd\'T\'HH:mm:ss.SSS\'Z\'")}"
}]
}'
"""
}
}
}
Discord Embed 색상 코드
| 상태 | 색상 | 코드 |
|---|---|---|
| 성공 | 🟢 초록색 | 3066993 |
| 실패 | 🔴 빨간색 | 15158332 |
| 경고 | 🟡 노란색 | 16776960 |
| 정보 | 🔵 파란색 | 3447003 |
보안 고려사항
Webhook URL 보호
Webhook URL이 노출되면 누구나 메시지를 보낼 수 있다.
Jenkins Credentials 사용
방법 1: Jenkins Credentials Store
- Jenkins 관리 → Manage Credentials
- Add Credentials 클릭
- Kind: Secret text
- Secret: Webhook URL 입력
- ID:
discord-webhook
Jenkinsfile:
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'npm run build'
}
}
}
post {
failure {
withCredentials([string(credentialsId: 'discord-webhook', variable: 'WEBHOOK_URL')]) {
sh """
curl -X POST \${WEBHOOK_URL} \
-H "Content-Type: application/json" \
-d '{
"content": "🚨 빌드 실패!",
"embeds": [{
"title": "${JOB_NAME} #${BUILD_NUMBER}",
"url": "${BUILD_URL}console",
"color": 15158332
}]
}'
"""
}
}
}
}
방법 2: 환경 변수
Jenkins 시스템 설정에서 환경 변수로 등록:
Jenkins 관리 → 시스템 설정 → Global properties → Environment variables
- Name:
DISCORD_WEBHOOK - Value: Webhook URL
Jenkinsfile에서 ${DISCORD_WEBHOOK} 사용
Webhook URL 재생성
혹시 URL이 노출되었다면:
- Discord 채널 설정 → 연동 → 웹후크
- 기존 Webhook 삭제
- 새 Webhook 생성
- Jenkins 설정 업데이트
실전 팁
알림 피로 방지
모든 빌드에 알림을 보내면 알림 피로 가 생긴다.
추천 설정:
- ✅ main 브랜치 빌드 실패: 즉시 알림
- ✅ 첫 빌드 실패: 알림
- ❌ 연속 실패: 첫 실패만 알림
- ✅ 실패 후 성공: 알림 (복구 확인)
post {
failure {
script {
// 이전 빌드가 성공이었을 때만 알림
if (currentBuild.getPreviousBuild()?.result == 'SUCCESS') {
sh """
curl -X POST \${DISCORD_WEBHOOK} \
-H "Content-Type: application/json" \
-d '{
"content": "🚨 빌드 실패! (이전 빌드는 성공)",
"embeds": [{
"title": "${JOB_NAME} #${BUILD_NUMBER}",
"url": "${BUILD_URL}console",
"color": 15158332
}]
}'
"""
}
}
}
success {
script {
// 이전 빌드가 실패였을 때만 알림
if (currentBuild.getPreviousBuild()?.result == 'FAILURE') {
sh """
curl -X POST \${DISCORD_WEBHOOK} \
-H "Content-Type: application/json" \
-d '{
"content": "✅ 빌드 복구됨!",
"embeds": [{
"title": "${JOB_NAME} #${BUILD_NUMBER}",
"url": "${BUILD_URL}",
"color": 3066993
}]
}'
"""
}
}
}
}
멀티 브랜치 파이프라인
여러 브랜치를 동시에 빌드하는 경우:
post {
failure {
sh """
curl -X POST \${DISCORD_WEBHOOK} \
-H "Content-Type: application/json" \
-d '{
"content": "🚨 **${env.BRANCH_NAME}** 브랜치 빌드 실패!",
"embeds": [{
"title": "${JOB_NAME} #${BUILD_NUMBER}",
"url": "${BUILD_URL}console",
"color": 15158332,
"fields": [
{
"name": "브랜치",
"value": "${env.BRANCH_NAME}",
"inline": true
},
{
"name": "커밋 메시지",
"value": "$(git log -1 --pretty=%B | head -1)",
"inline": false
}
]
}]
}'
"""
}
}
스테이지별 실패 알림
어느 스테이지에서 실패했는지 알림:
stage('Build') {
steps {
script {
try {
sh 'npm run build'
} catch (Exception e) {
sh """
curl -X POST \${DISCORD_WEBHOOK} \
-H "Content-Type: application/json" \
-d '{
"content": "🚨 **Build 스테이지** 실패!",
"embeds": [{
"title": "${JOB_NAME} #${BUILD_NUMBER}",
"url": "${BUILD_URL}console",
"color": 15158332,
"description": "빌드 중 오류 발생"
}]
}'
"""
throw e
}
}
}
}
트러블슈팅
curl 명령어가 실행되지 않음
증상: curl: command not found
해결:
// Docker agent 사용 시
agent {
docker {
image 'node:18'
args '-u root' // curl 설치 권한
}
}
stages {
stage('Install curl') {
steps {
sh 'apt-get update && apt-get install -y curl'
}
}
}
JSON 파싱 에러
증상: Discord에서 Invalid JSON 에러
해결:
- JSON 내부의 따옴표를 이스케이프:
\" - Groovy 변수를 문자열에 포함할 때 주의
- JSON validator로 검증: jsonlint.com
Webhook URL이 작동하지 않음
확인 사항:
- Webhook URL이 정확한지
- Webhook이 삭제되지 않았는지
- Discord 채널 권한 확인
테스트:
curl -X POST https://discord.com/api/webhooks/YOUR_WEBHOOK_URL \
-H "Content-Type: application/json" \
-d '{"content": "테스트 메시지"}'
한글이 깨짐
해결:
sh """
curl -X POST \${DISCORD_WEBHOOK} \
-H "Content-Type: application/json; charset=utf-8" \
-d '{
"content": "🚨 빌드 실패!"
}'
"""
응용: Slack 대신 Discord 사용
회사에서 Slack 유료 플랜을 쓰지 않는다면 Discord가 좋은 대안이다.
Discord의 장점:
- ✅ 무료 무제한 메시지 히스토리
- ✅ Webhook 무료
- ✅ 모바일 알림 좋음
- ✅ 음성 채널 무료
단점:
- ❌ 업무용 이미지 (게임 메신저 느낌)
- ❌ 엔터프라이즈 기능 부족
마무리
Jenkins Discord Webhook 알림은:
- ✅ 5분 설정
- ✅ 무료
- ✅ 플러그인 불필요
- ✅ 실시간 알림
빌드 실패를 놓치지 말고, 지금 바로 설정해보자!