Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/dev-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ jobs:
-p 8080:8080 \
--restart unless-stopped \
-e TZ=Asia/Seoul \
-e SPRING_PROFILES_ACTIVE=dev \
-v /var/log/nuntteo-was:/app/logs \
$IMAGE

Expand Down
8 changes: 4 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,18 @@ RUN ./gradlew bootJar --no-daemon
FROM eclipse-temurin:17-jre-alpine AS runtime

# 비루트 사용자 생성 (보안)
RUN addgroup -g 1000 noonddu && adduser -u 1000 -G noonddu -s /bin/sh -D noonddu
RUN addgroup -g 1000 nuntteo && adduser -u 1000 -G nuntteo -s /bin/sh -D nuntteo

WORKDIR /app

# 빌드된 JAR 복사
COPY --from=build /app/build/libs/*.jar app.jar

RUN chown noonddu:noonddu app.jar
RUN chown nuntteo:nuntteo app.jar

USER noonddu
USER nuntteo

EXPOSE 8080

# dev 프로필로 실행
ENTRYPOINT ["java", "-Dspring.profiles.active=dev", "-jar", "/app/app.jar"]
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
120 changes: 120 additions & 0 deletions Jenkinsfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// Jenkinsfile
pipeline {
agent any

tools {
jdk 'jdk17' // Jenkins Tools 설정에 등록된 JDK 이름
}

stages {
// 1. 소스 코드 체크아웃
stage('Checkout') {
steps {
git branch: 'main',
credentialsId: 'GITHUB_TOKEN', // GitHub PAT Credential ID
url: 'https://github.com/Central-MakeUs/Whiplash-Server.git'
}
}

// 2. Git Commit SHA 추출 (Docker 이미지 태그로 사용)
stage('Extract SHA') {
steps {
script {
env.SHORT_SHA = sh(script: 'git rev-parse --short HEAD', returnStdout: true).trim()
echo "Current commit SHA: ${env.SHORT_SHA}"
}
}
}

// withCredentials 블록으로 Jenkins에 등록된 모든 Secret 값을 변수로 로드
stage('Run CI/CD with Credentials') {
steps {
withCredentials([
// Docker & Server Info
string(credentialsId: 'DOCKERHUB_USERNAME', variable: 'DOCKERHUB_USERNAME'),
string(credentialsId: 'IMAGE_NAME', variable: 'IMAGE_NAME'),
string(credentialsId: 'PROD_HOST', variable: 'PROD_HOST'),
string(credentialsId: 'PROD_USERNAME', variable: 'PROD_USERNAME'),
// Application Config Files
string(credentialsId: 'PROD_ENV_PROPERTIES', variable: 'ENV_PROPERTIES'),
string(credentialsId: 'PROD_GOOGLE_JSON_BASE64', variable: 'GOOGLE_JSON_B64'),
string(credentialsId: 'PROD_FIREBASE_KEY_JSON_BASE64', variable: 'FIREBASE_KEY_B64')
]) {
script {
// 3. 운영 환경 설정 파일 생성
stage('Generate Config Files') {
sh '''
mkdir -p src/main/resources
echo "${ENV_PROPERTIES}" > src/main/resources/env.properties
echo "${GOOGLE_JSON_B64}" | base64 -d > src/main/resources/google.json
echo "${FIREBASE_KEY_B64}" | base64 -d > src/main/resources/whiplash-firebase-key.json
'''
}

// 4. Gradle 빌드
stage('Build') {
sh 'chmod +x ./gradlew'
sh './gradlew bootJar --no-daemon'
}

// 5. Docker 이미지 빌드 및 푸시
stage('Build and Push Docker Image') {
withCredentials([usernamePassword(credentialsId: 'DOCKERHUB_CREDENTIALS', usernameVariable: 'DOCKER_USER', passwordVariable: 'DOCKER_PASS')]) {
sh "echo ${DOCKER_PASS} | docker login -u ${DOCKER_USER} --password-stdin"
sh "docker build -t ${IMAGE_NAME}:${env.SHORT_SHA} ."
sh "docker push ${IMAGE_NAME}:${env.SHORT_SHA}"
}
}

// 6. 운영 서버에 무중단 배포 실행
stage('Deploy Blue/Green to Production') {
sshagent(credentials: ['PROD_PRIVATE_KEY']) {
// deploy.sh 스크립트에 이미지 태그와 이미지 이름을 인자로 전달
sh """
ssh -o StrictHostKeyChecking=no ${PROD_USERNAME}@${PROD_HOST} 'cd /opt/app/scripts && ./deploy.sh ${env.SHORT_SHA} ${IMAGE_NAME}'
"""
}
}
}
}
}
}
}

// 파이프라인 종료 후 실행될 작업 (성공/실패 알림)
post {
always {
script {
withCredentials([string(credentialsId: 'DISCORD_WEBHOOK_URL', variable: 'HOOK_URL')]) {
def message
def color

// currentBuild.result는 SUCCESS, UNSTABLE, FAILURE 등의 값을 가짐
if (currentBuild.result == 'SUCCESS') {
color = '3066993' // Green
message = "✅ **[${env.JOB_NAME}]** 빌드 성공! ( #${env.BUILD_NUMBER} )"
} else if (currentBuild.result == 'UNSTABLE') {
color = '15105570' // Yellow
message = "⚠️ **[${env.JOB_NAME}]** 빌드 불안정. ( #${env.BUILD_NUMBER} )"
} else {
color = '15158332' // Red
message = "❌ **[${env.JOB_NAME}]** 빌드 실패! ( #${env.BUILD_NUMBER} )"
}

// Discord Notifier 플러그인의 discordSend 스텝 사용
discordSend(
webhookURL: "${HOOK_URL}",
embeds: [[
"title": "Build Status: ${currentBuild.result}",
"description": "${message}\n[Jenkins 빌드 로그 보기](${env.BUILD_URL})",
"color": color
]]
)
}
}
// 정리 작업
echo 'Pipeline finished. Cleaning up...'
sh 'docker logout'
}
}
}
15 changes: 15 additions & 0 deletions src/main/resources/oauth.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,21 @@ oauth:
---
spring.config.activate.on-profile: prod

oauth:
google:
client-id:
android: ${GOOGLE_CLIENT_ID_ANDROID}
ios: ${GOOGLE_CLIENT_ID_IOS}
sheet:
id: ${GOOGLE_SHEET_ID}
credentials-path: ${GOOGLE_SHEET_CREDENTIALS}
range: "알람 삭제 이유-운영!A:C"

apple:
client-id: ${APPLE_CLIENT_ID}
# kakao:
# client-id: ${KAKAO_CLIENT_ID}

---
spring.config.activate.on-profile: test

Expand Down
4 changes: 2 additions & 2 deletions src/main/resources/sentry.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ sentry:
logging:
minimum-event-level: error
minimum-breadcrumb-level: info
traces-sample-rate: 1.0 # 트랜잭션 100% 수집
traces-sample-rate: 0.3 # 트랜잭션 100% 수집
environment: dev
release: nuntteo-api@1.0.0

Expand All @@ -32,7 +32,7 @@ sentry:
logging:
minimum-event-level: error
minimum-breadcrumb-level: info
traces-sample-rate: 1.0 # 트랜잭션 100% 수집
traces-sample-rate: 0.3 # 트랜잭션 100% 수집
environment: prod

---
Expand Down
Loading