-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathJenkinsfile
More file actions
242 lines (218 loc) · 10.3 KB
/
Copy pathJenkinsfile
File metadata and controls
242 lines (218 loc) · 10.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
pipeline {
agent any
triggers {
pollSCM('H/3 * * * *')
}
environment {
DOCKER_COMPOSE_FILE = 'docker-compose.yml'
BACKEND_IMAGE = 'bluemarble-backend'
BRANCH_NAME = "${env.BRANCH_NAME ?: 'master'}"
EC2_HOST = 'j13d106.p.ssafy.io'
EC2_USER = 'ubuntu'
SSH_KEY_ID = 'J13D106T-pem' // Jenkins Credentials에서 설정할 SSH Key ID
}
// tools {
// gradle 'Gradle'
// }
stages {
stage('Checkout') {
steps {
echo 'Checking out source code...'
checkout scm
}
}
stage('Environment Setup') {
steps {
echo 'Setting up environment...'
script {
// Copy environment file if it doesn't exist
sh '''
if [ ! -f .env ]; then
if [ -f .env.example ]; then
cp .env.example .env
echo "Environment file created from example"
else
echo "Warning: .env.example not found, creating minimal .env"
echo "SPRING_PROFILE=docker" > .env
echo "SERVER_PORT=8081" >> .env
# Do not hardcode secrets in the repo. Use CI/CD secrets instead.
# If JWT_SECRET is provided by the CI environment, use it; otherwise set a placeholder.
echo "JWT_SECRET=${JWT_SECRET:-change-me}" >> .env
fi
else
echo ".env file already exists"
fi
'''
}
}
}
stage('Build & Test') {
steps {
echo 'Building and testing application...'
dir('finble-backend') {
sh './gradlew clean build -x test || echo "Build failed but continuing pipeline for testing"'
}
}
post {
always {
// Archive test results if they exist
script {
if (fileExists('finble-backend/build/test-results/test/*.xml')) {
junit 'finble-backend/build/test-results/test/*.xml'
}
}
}
}
}
stage('Docker Build') {
steps {
echo 'Building Docker images...'
script {
sh 'docker-compose build --no-cache backend'
}
}
}
stage('Deploy to EC2') {
when {
anyOf {
branch 'master'
branch 'main'
branch 'develop'
}
}
steps {
echo 'Deploying to EC2 server...'
script {
sshagent(credentials: [env.SSH_KEY_ID]) {
// Create project directory on EC2 if it doesn't exist
sh """
ssh -o StrictHostKeyChecking=no ${env.EC2_USER}@${env.EC2_HOST} '
mkdir -p /home/ubuntu/bluemarble &&
cd /home/ubuntu/bluemarble &&
sudo systemctl start docker &&
sudo systemctl enable docker &&
sudo usermod -aG docker ubuntu
'
"""
// Clean and copy project files to EC2 (preserve .env)
sh """
ssh -o StrictHostKeyChecking=no ${env.EC2_USER}@${env.EC2_HOST} '
cd /home/ubuntu/bluemarble &&
find . -name ".env" -prune -o -type f -exec rm -f {} + &&
find . -name ".env" -prune -o -type d -not -path "." -exec rm -rf {} + 2>/dev/null || true &&
mkdir -p finble-backend finble-frontend
'
"""
sh """
scp -o StrictHostKeyChecking=no -r ./docker-compose.yml ./docker-compose.green.yml ./finble-backend ./finble-frontend ./init.sql ./Jenkinsfile ${env.EC2_USER}@${env.EC2_HOST}:/home/ubuntu/bluemarble/
"""
// Blue-Green Deploy on EC2
sh """
ssh -o StrictHostKeyChecking=no ${env.EC2_USER}@${env.EC2_HOST} '
cd /home/ubuntu/bluemarble &&
# Clean up and build new version (볼륨도 삭제)
sudo docker-compose down -v --remove-orphans || true &&
sudo docker system prune -f &&
sudo docker-compose build --no-cache backend &&
# Start new version on port 8082 (Green)
export BACKEND_PORT=8082 &&
sudo -E docker-compose -f docker-compose.green.yml up -d &&
echo "Waiting for new version to start..." &&
sleep 30
'
"""
// Blue-Green Health check and switch
sh """
ssh -o StrictHostKeyChecking=no ${env.EC2_USER}@${env.EC2_HOST} '
cd /home/ubuntu/bluemarble &&
# Health check new version (Green - 8082)
echo "Testing new version on port 8082..."
max_attempts=15
attempt=0
health_check_passed=false
until curl -f http://localhost:8082/actuator/health || [ \$attempt -eq \$max_attempts ]; do
echo "Health check attempt \$((\$attempt + 1))/\$max_attempts"
attempt=\$((\$attempt + 1))
sleep 10
done
if [ \$attempt -lt \$max_attempts ]; then
echo "✅ New version health check passed!"
health_check_passed=true
else
echo "❌ New version health check failed"
health_check_passed=false
fi
if [ "\$health_check_passed" = true ]; then
echo "🔄 Switching to new version..."
# Stop old version (Blue - 8081) with volumes
sudo docker-compose down -v --remove-orphans || true
# Start new version on 8081 using the same image that passed health check
sudo docker-compose up -d --no-build
# Wait for new Blue to start
sleep 15
# Verify Blue is running on 8081
if curl -f http://localhost:8081/actuator/health; then
echo "✅ Blue version running successfully on 8081"
# Stop only Green backend container (8082)
sudo docker stop bluemarble-backend-green || true
sudo docker rm bluemarble-backend-green || true
echo "✅ Successfully deployed new version!"
else
echo "❌ Blue version failed to start on 8081"
# Keep Green running as fallback
echo "⚠️ Green version still running on 8082 as backup"
fi
else
echo "🔄 Rolling back - keeping old version..."
# Remove failed Green version only
sudo docker stop bluemarble-backend-green || true
sudo docker rm bluemarble-backend-green || true
echo "✅ Old version continues running on port 8081"
fi
'
"""
}
}
}
}
stage('Cleanup') {
steps {
echo 'Cleaning up...'
script {
// Remove unused Docker images and build cache
sh 'docker image prune -f'
sh 'docker builder prune -f'
}
}
}
}
post {
always {
echo 'Pipeline completed!'
// Clean workspace
cleanWs()
}
success {
echo 'Pipeline succeeded!'
script {
if (env.BRANCH_NAME == 'master' || env.BRANCH_NAME == 'main') {
echo 'Production deployment successful'
}
}
}
failure {
echo 'Pipeline failed!'
script {
// Show logs for debugging - check if docker-compose.yml exists first
if (fileExists('docker-compose.yml')) {
sh 'docker-compose -f docker-compose.yml logs --tail=50 || echo "Failed to get docker-compose logs"'
} else {
echo "docker-compose.yml not found, skipping logs"
}
}
}
unstable {
echo 'Pipeline unstable!'
}
}
}