
1. ํน์ EC2 ์ธ์คํด์ค ๋ด Docker๋ก Jenkins ์ปจํ ์ด๋ ์ด์
2. Jenkins Pipeline ๋ด์์ Git Branch Checkout ์ ์
3. Jenkins Pipeline ๋ด์์ AWS CLI ์ฌ์ฉ์ ์ ์
4. Jenkins Pipeline ๋ด์์ Dockerfile ์ ์
5. Jenkins Pipeline ๋ด์์ Slack Notification ์ ์
6. Jenkins Pipeline ๋ด์์ Build Gradle ์ ์
7. Jenkins Pipeline ๋ด์์ ECR Registry & ECS Deploy ์ ์
8. Jenkins Pipeline ๋ด์์ ์ปค๋ฐ ๋ก๊ทธ ์ถ์ถ Slack WebWook ์ ์
- agent ๐ ์ด๋์ ์คํํ ์ง๋ฅผ ์ ์ (any, label, docker, ๋ฑ)
- environment ๐ ๊ณตํต ํ๊ฒฝ๋ณ์ ์ค์
- stages ๐ ๋จ๊ณ๋ค์ ๊ทธ๋ฃนํ
- stage ๐ ๊ฐ๋ณ ์์ ๋จ๊ณ (์: ๋น๋, ํ ์คํธ, ๋ฐฐํฌ ๋ฑ)
- steps ๐ ํด๋น ๋จ๊ณ์์ ์ํํ ์์ ๋ค
- post ๐ ์ฑ๊ณต/์คํจ ํ์ ํ์ฒ๋ฆฌ ์์ ์ ์


- AWS Access Key Id : ๊ณต๊ฐ์ ์ผ๋ก ์๋ณ ๊ฐ๋ฅํ ํค
- AWS Secret Access Key : ํด๋น Access Key ID์ ๋์ํ๋ ๋น๋ฐ๋ฒํธ ๊ฐ์ ๋น๋ฐ ํค
โป ์ ํจ์ค ํ์ดํ๋ผ์ธ ECR Registry & ECS Deploy ํด๋น Stage ์์ ์ฌ์ฉ ์์
ex) withAWS(credentials: '{AWS Credentials ID}', region: {AWS REGION}

pipeline {
agent any
environment {
BITBUCKET_CREDENTIALS = 'bc2fa053-e540-48bc-b7f7-b504430a63c9' // Bitbucket ์๊ฒฉ ์ฆ๋ช
ID
AWS_REGION = 'ap-northeast-2' // AWS ๋ฆฌ์
ECR_URI = '998251115309.dkr.ecr.ap-northeast-2.amazonaws.com' // ECR URI
ECR_REPOSITORY_NAME = 'test' // ECR ๋ฆฌํฌ์งํ ๋ฆฌ ์ด๋ฆ
ECS_CLUSTER_NAME = 'test-cluster' // ECS ํด๋ฌ์คํฐ ์ด๋ฆ
ECS_SERVICE_NAME = 'test-service' // ECS ์๋น์ค ์ด๋ฆ
ECR_IMAGE_TAG = 'latest' // ์ด๋ฏธ์ง ํ๊ทธ
SLACK_CREDENTIALS = 'slack' // Slack ์๊ฒฉ ์ฆ๋ช
ID
SLACK_CHANNEL = '#test-notification' // Slack ์ฑ๋
COMMIT_FILE = "previous_commit_hash.txt" // ์ปค๋ฐ ํด์ ์ ์ฅ ํ์ผ
PREVIOUS_COMMIT = '' // ์ด์ ์ปค๋ฐ ํด์ (๋์ ํ ๋น์ฉ)
CURRENT_COMMIT = '' // ํ์ฌ ์ปค๋ฐ ํด์ (๋์ ํ ๋น์ฉ)
}
stages {
stage('Checkout Bitbucket') {
steps {
git branch: 'test',
credentialsId: BITBUCKET_CREDENTIALS,
url: '{๋ธ๋์น ์ฃผ์}'
}
}
stage('Write Dockerfile') {
steps {
script {
// ๋์ ์ผ๋ก Dockerfile ์์ฑ
writeFile file: 'Dockerfile', text: '''
FROM amazoncorretto:21
ARG JAR_FILE=./build/libs/test-0.0.1-SNAPSHOT.jar
COPY ${JAR_FILE} app.jar
ENV SPRING_PROFILES_ACTIVE=dev
ENTRYPOINT ["java", "-Xms3g", "-Xmx3g", "-XX:ActiveProcessorCount=2", "-XX:MaxRAMPercentage=75.0", "-XX:InitialRAMPercentage=75.0", "-jar", "app.jar"]
'''
}
}
}
stage('Prepare Slack Notification') {
steps {
script {
// ์ด์ ์ปค๋ฐ ํด์ ํ์ธ (ํ์ผ์์ ์ฝ๊ฑฐ๋ git์์ ๊ฐ์ ธ์ด)
if (fileExists(COMMIT_FILE)) {
PREVIOUS_COMMIT = readFile(COMMIT_FILE).trim()
} else {
PREVIOUS_COMMIT = sh(
script: "git rev-parse HEAD~1",
returnStdout: true
).trim()
}
// ํ์ฌ ์ปค๋ฐ ํด์ ๊ฐ์ ธ์ค๊ธฐ
CURRENT_COMMIT = sh(
script: "git rev-parse HEAD",
returnStdout: true
).trim()
}
}
}
stage('Slack Build Notification') {
steps {
script {
// ๋น๋ ์์ ์๋ฆผ
slackSend(
color: "#439FE0",
channel: SLACK_CHANNEL,
message: "*ํ๋ก์ ํธ ์ด๋ฆ : ${env.JOB_NAME}*\n*๋น๋๋ฒํธ : ${env.BUILD_NUMBER}*\n*๋น๋์คํ :jenkins_pepe_1:*",
tokenCredentialId: SLACK_CREDENTIALS
)
}
}
}
stage('Build Gradle') {
steps {
// Gradle ๋น๋ ์คํ
sh 'chmod +x ./gradlew'
sh './gradlew clean build -Dorg.gradle.java.home=/usr/lib/jvm/jdk-21'
}
}
stage('ECR Registry & ECS Deploy') {
steps {
// AWS ์ธ์ฆ ๋ฐ ๋ฐฐํฌ ์์
withAWS(credentials: 'aws-credentials-id', region: AWS_REGION) {
sh '''
aws ecr get-login-password --region ${AWS_REGION} | docker login --username AWS --password-stdin ${ECR_URI}
docker build -t ${ECR_REPOSITORY_NAME} .
docker tag ${ECR_REPOSITORY_NAME}:${ECR_IMAGE_TAG} ${ECR_URI}/${ECR_REPOSITORY_NAME}:${ECR_IMAGE_TAG}
docker push ${ECR_URI}/${ECR_REPOSITORY_NAME}:${ECR_IMAGE_TAG}
docker rmi ${ECR_URI}/${ECR_REPOSITORY_NAME}:${ECR_IMAGE_TAG}
docker rmi ${ECR_REPOSITORY_NAME}:${ECR_IMAGE_TAG}
aws ecs update-service --cluster ${ECS_CLUSTER_NAME} --service ${ECS_SERVICE_NAME} --force-new-deployment
'''
}
}
}
}
post {
success {
script {
// ๋ณ๊ฒฝ๋ ์ปค๋ฐ ๋ก๊ทธ ์ถ์ถ
def newCommits = sh(
script: "git log ${PREVIOUS_COMMIT}..${CURRENT_COMMIT} --pretty=format:'%s [%an]'",
returnStdout: true
).trim()
// ์ต์ ์ปค๋ฐ ํด์ ์ ์ฅ
writeFile file: COMMIT_FILE, text: CURRENT_COMMIT
// Slack ์๋ฆผ - ๋น๋ ์ฑ๊ณต
def message = newCommits ?
newCommits.split('\n').collect { it + " :jenkins_pepe_2:" }.join('\n') :
"*๋ฐ์๋ ์ปค๋ฐ ์์*"
slackSend(
color: "#36a64f",
channel: SLACK_CHANNEL,
message: "*๋น๋์ฑ๊ณต : ${env.JOB_NAME}*\n*๋น๋๋ฒํธ : ${env.BUILD_NUMBER}*\n*๋ฐ์๋ ์ปค๋ฐ ๋ชฉ๋ก*\n${message}",
tokenCredentialId: SLACK_CREDENTIALS
)
}
}
aborted {
slackSend(
color: "#ffcc00",
channel: SLACK_CHANNEL,
message: "*Build Aborted: ${env.JOB_NAME} - ${env.BUILD_NUMBER}*",
tokenCredentialId: SLACK_CREDENTIALS
)
}
unstable {
slackSend(
color: "#ffcc00",
channel: SLACK_CHANNEL,
message: "*Build Unstable: ${env.JOB_NAME} - ${env.BUILD_NUMBER}*",
tokenCredentialId: SLACK_CREDENTIALS
)
}
failure {
script {
// ์คํจํ ๋น๋์ ์ปค๋ฐ ๋ก๊ทธ ์ถ์ถ
def newCommits = sh(
script: "git log ${PREVIOUS_COMMIT}..${CURRENT_COMMIT} --pretty=format:'%s [%an]'",
returnStdout: true
).trim()
// ์ปค๋ฐ ํด์ ์ ์ฅ
writeFile file: COMMIT_FILE, text: CURRENT_COMMIT
// Slack ์๋ฆผ - ๋น๋ ์คํจ
def message = newCommits ?
newCommits.split('\n').collect { it + " :pepe2:" }.join('\n') :
"*๋ฐ์๋ ์ปค๋ฐ ์์*"
slackSend(
color: "#ff0000",
channel: SLACK_CHANNEL,
message: "*๋น๋์คํจ : ${env.JOB_NAME}*\n*๋น๋๋ฒํธ : ${env.BUILD_NUMBER}*\n*๋ฐ์๋ ์ปค๋ฐ ๋ชฉ๋ก*\n${message}",
tokenCredentialId: SLACK_CREDENTIALS
)
}
}
}
}