Skip to content

Commit 4e3b0a5

Browse files
committed
Merge branch 'feature/bigbang' into develop
빅뱅 배포 테라폼 코드 & 환경설정/배포/백업 스크립트 추가
2 parents db71e44 + 96ed3b8 commit 4e3b0a5

28 files changed

+1432
-0
lines changed

.gitignore

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# 상태 파일
2+
*.tfstate
3+
*.tfstate.backup
4+
.terraform/
5+
6+
# 변수 값
7+
terraform.tfvars
8+
*.tfvars
9+
10+
# GCP/SSH 키
11+
*.json
12+
*.pem
13+
*.key
14+
id_rsa*
15+
google-credentials.json
16+
17+
# 로그, 충돌
18+
crash.log
19+
*.log
20+
21+
# 배포 디렉토리 무시
22+
*/deploy/ai-server/
23+
*/deploy/backend/
24+
*/deploy/frontend/
25+
26+
# 환경변수 스크립트 파일 무시
27+
app-variables.sh

README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,16 @@
11
# CareerBee Cloud
2+
3+
## 커밋 형식
4+
5+
<타입>: <변경 요약>
6+
7+
### 타입 예시
8+
9+
- feat: 새로운 기능 추가
10+
- fix: 버그 수정
11+
- refactor: 리팩토링 (기능 변화 없음)
12+
- chore: 빌드, 설정, 스크립트 등 기타 변경
13+
- docs: 문서 수정
14+
- test: 테스트 코드 추가/수정
15+
- ci: CI 관련 수정
16+
- revert: 이전 커밋 롤백

bigbang/deploy/scripts/backup.sh

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#!/bin/bash
2+
set -euo pipefail
3+
source ./app-variables.sh
4+
exec > >(gawk '{ print strftime("[%Y-%m-%d %H:%M:%S]"), $0; fflush(); }' >> ../logs/backup.log) 2>&1
5+
6+
echo "🔧 백업 시작..."
7+
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
8+
# 1️⃣ 서버 내부 백업 작업
9+
echo "🔹 원격 서버 백업 생성 중..."
10+
ssh -i ${SSH_KEY} ubuntu@$SERVER_IP <<EOF
11+
set -euo pipefail
12+
mkdir -p ~/tmp
13+
14+
echo " 📦 MySQL 덤프 생성 중..."
15+
if ! mysqldump -u root -p"${DB_PASSWORD}" "${DB_NAME}" | gsutil cp - "$BUCKET_BACKUP/mysql/careerbee_backup_${TIMESTAMP}.sql"; then
16+
echo "❌ MySQL 백업 실패"
17+
exit 1
18+
fi
19+
20+
echo " 🔐 SSL 인증서 백업 중..."
21+
sudo tar czf ~/tmp/cert-backup.tar.gz /etc/letsencrypt/live/${DOMAIN} /etc/letsencrypt/archive/${DOMAIN} /etc/letsencrypt/renewal/${DOMAIN}.conf /etc/letsencrypt/options-ssl-nginx.conf /etc/letsencrypt/ssl-dhparams.pem|| echo "⚠️ 인증서 압축 실패, 파일이 없을 수 있음"
22+
gsutil cp ~/tmp/cert-backup.tar.gz $BUCKET_BACKUP/ssl/cert-backup_${TIMESTAMP}.tar.gz
23+
rm -f ~/tmp/cert-backup.tar.gz
24+
25+
echo "✅ 서버 백업 파일 생성 완료"
26+
27+
echo "🔹 GCS 업로드 결과 확인 중..."
28+
gsutil ls "${BUCKET_BACKUP}/mysql/" | grep "careerbee_backup_${TIMESTAMP}.sql" >/dev/null \
29+
&& echo "✅ MySQL 백업 GCS 업로드 완료" || echo "❌ MySQL 백업 GCS 업로드 실패"
30+
gsutil ls "${BUCKET_BACKUP}/ssl/" | grep "cert-backup_${TIMESTAMP}.tar.gz" >/dev/null \
31+
&& echo "✅ 인증서 GCS 업로드 완료" || echo "❌ 인증서 GCS 업로드 실패"
32+
33+
echo "🎉 백업 스크립트 완료!"
34+
EOF

bigbang/deploy/scripts/certbot.sh

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#!/bin/bash
2+
source ./app-variables.sh
3+
4+
ssh -i $SSH_KEY ubuntu@$SERVER_IP <<EOF
5+
# 8-1. Certbot 및 HTTPS 인증서 발급
6+
echo "🔹 Certbot 설치 및 HTTPS 인증서 발급 중..."
7+
# sudo snap install --classic certbot
8+
# sudo ln -sf /snap/bin/certbot /usr/bin/certbot
9+
10+
# # Certbot 인증서 발급
11+
# sudo certbot --nginx --non-interactive --agree-tos --no-redirect -m ${EMAIL} \
12+
# -d ${DOMAIN} -d www.${DOMAIN} -d api.${DOMAIN} || echo "⚠️ Certbot 인증 실패 또는 이미 인증됨"
13+
14+
# 8-2. Nginx SPA fallback 설정 + HTTPS listen 추가
15+
sudo tee /etc/nginx/sites-available/default > /dev/null <<EOF_NGINX
16+
# HTTP → HTTPS 리디렉트
17+
server {
18+
listen 80 default_server;
19+
listen [::]:80 default_server;
20+
21+
server_name *.${DOMAIN};
22+
23+
return 301 https://\\\$host\\\$request_uri;
24+
}
25+
26+
# HTTPS 블록
27+
server {
28+
listen 443 ssl;
29+
server_name ${DOMAIN};
30+
31+
ssl_certificate /etc/letsencrypt/live/${DOMAIN}/fullchain.pem;
32+
ssl_certificate_key /etc/letsencrypt/live/${DOMAIN}/privkey.pem;
33+
include /etc/letsencrypt/options-ssl-nginx.conf;
34+
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
35+
36+
return 301 https://www.${DOMAIN}\\\$request_uri;
37+
}
38+
39+
server {
40+
listen 443 ssl;
41+
listen [::]:443 ssl;
42+
43+
server_name www.${DOMAIN};
44+
45+
root /var/www/html;
46+
index index.html;
47+
48+
ssl_certificate /etc/letsencrypt/live/${DOMAIN}/fullchain.pem;
49+
ssl_certificate_key /etc/letsencrypt/live/${DOMAIN}/privkey.pem;
50+
include /etc/letsencrypt/options-ssl-nginx.conf;
51+
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
52+
53+
location / {
54+
try_files \\\$uri \\\$uri/ /index.html;
55+
}
56+
}
57+
58+
server {
59+
listen 443 ssl;
60+
server_name api.${DOMAIN};
61+
62+
location / {
63+
proxy_pass http://localhost:8080;
64+
proxy_set_header Host \\\$host;
65+
proxy_set_header X-Real-IP \\\$remote_addr;
66+
}
67+
}
68+
EOF_NGINX
69+
70+
echo "✅ HTTPS 설정 추가 완료."
71+
sudo nginx -t && sudo systemctl reload nginx
72+
73+
echo "✅ HTTPS 인증 완료 및 자동 갱신 설정됨."
74+
EOF

bigbang/deploy/scripts/deploy.sh

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#!/bin/bash
2+
source ./app-variables.sh # cd deploy/scripts
3+
4+
exec > >(gawk '{ print strftime("[%Y-%m-%d %H:%M:%S]"), $0; fflush(); }' >> ../logs/deploy.log) 2>&1
5+
6+
BACKEND_DIR=../backend
7+
FRONTEND_DIR=../frontend
8+
AI_DIR=../ai-server
9+
VERSION_TAG=$(date +v%Y%m%d%H%M%S)
10+
11+
echo "========== [0] 코드 rsync로 서버로 전송 =========="
12+
13+
rsync -avz -e "ssh -i $SSH_KEY" --exclude=node_modules $BACKEND_DIR ubuntu@$SERVER_IP:~/tmp/
14+
rsync -avz -e "ssh -i $SSH_KEY" --exclude=node_modules $FRONTEND_DIR ubuntu@$SERVER_IP:~/tmp/
15+
rsync -avz -e "ssh -i $SSH_KEY" $AI_DIR ubuntu@$SERVER_IP:~/tmp/
16+
17+
echo "✅ 임시 디렉토리로 코드 전송 완료"
18+
19+
echo "========== [1] 서버 내 빌드/배포 및 롤백 준비 =========="
20+
21+
ssh -i $SSH_KEY ubuntu@$SERVER_IP << EOF
22+
sudo cp -r ~/tmp/backend ~/release/
23+
sudo cp -r ~/tmp/frontend ~/release/
24+
sudo cp -r ~/tmp/ai-server ~/release/
25+
sudo chown -R ubuntu:ubuntu ~/release
26+
echo "✅ release 디렉토리로 복사 완료"
27+
28+
echo "[1-1] 백엔드 빌드 시작..."
29+
cd ~/release/backend
30+
./gradlew clean build -x test || {
31+
echo "❌ Gradle 빌드 실패. 배포 중단."
32+
exit 1
33+
}
34+
35+
echo "[1-2] 백엔드 실행 중단 및 새로운 JAR 연결..."
36+
pkill -f 'app.jar' || echo "기존 백엔드 없음"
37+
38+
JAR_PATH=\$(ls -t build/libs/*.jar | grep -v plain | head -n 1)
39+
# echo "[디버그] 선택된 JAR_PATH: \$JAR_PATH"
40+
41+
cp \$JAR_PATH ~/release/app-${VERSION_TAG}.jar
42+
ln -sfn ~/release/app-${VERSION_TAG}.jar ~/app.jar
43+
44+
if [ -L ~/app.jar ]; then
45+
TARGET=\$(readlink -f ~/app.jar)
46+
# echo "[디버그] 현재 TARGET 심볼릭 링크 대상: \$TARGET"
47+
echo "$VERSION_TAG\$TARGET" >> ~/release/deployment-history.log
48+
echo "버전 기록 완료: $VERSION_TAG\$TARGET"
49+
fi
50+
51+
echo "[1-2-1] 새로운 백엔드 실행..."
52+
nohup java \
53+
-Dspring.profiles.active=dev \
54+
-DDB_URL="${DB_URL}" \
55+
-DDB_USERNAME="${DB_USERNAME}" \
56+
-DDB_PASSWORD="${DB_PASSWORD}" \
57+
-DJWT_SECRETS="${JWT_SECRETS}" \
58+
-DKAKAO_CLIENT_ID="${KAKAO_CLIENT_ID}" \
59+
-DKAKAO_REDIRECT_URI="${KAKAO_REDIRECT_URI}" \
60+
-jar ~/app.jar > ~/logs/backend.log 2>&1 &
61+
62+
sleep 5
63+
RUNNING=\$(pgrep -f 'app.jar' || true)
64+
65+
if [ -z "\$RUNNING" ]; then
66+
echo "❌ 새 백엔드 실행 실패 → 롤백 시작..."
67+
PREVIOUS_LINE=$(tail -n 2 ~/release/deployment-history.log | head -n 1)
68+
PREVIOUS_VERSION=\$(echo "\$PREVIOUS_LINE" | awk '{print $3}')
69+
70+
if [ -f "\$PREVIOUS_VERSION" ]; then
71+
echo "🔄 이전 버전 (\$PREVIOUS_VERSION)으로 롤백 중..."
72+
ln -sfn "\$PREVIOUS_VERSION" ~/app.jar
73+
74+
nohup java \
75+
-Dspring.profiles.active=dev \
76+
-DDB_URL="${DB_URL}" \
77+
-DDB_USERNAME="${DB_USERNAME}" \
78+
-DDB_PASSWORD="${DB_PASSWORD}" \
79+
-DJWT_SECRETS="${JWT_SECRETS}" \
80+
-DKAKAO_CLIENT_ID="${KAKAO_CLIENT_ID}" \
81+
-DKAKAO_REDIRECT_URI="${KAKAO_REDIRECT_URI}" \
82+
-jar ~/app.jar > ~/logs/backend.log 2>&1 &
83+
84+
echo "✅ 이전 버전으로 롤백 완료."
85+
else
86+
echo "⚠️ 롤백 불가: 이전 JAR 없음."
87+
fi
88+
else
89+
echo "✅ 백엔드 새 버전 정상 실행됨."
90+
fi
91+
92+
echo "[1-3] 프론트엔드 빌드 시작..."
93+
cd ~/release/frontend
94+
pnpm install
95+
96+
echo "[1-3-1] 환경변수 파일(.env) 생성..."
97+
echo "VITE_KAKAOMAP_KEY=${VITE_KAKAOMAP_KEY}" > ~/release/frontend/.env
98+
echo "VITE_API_URL=\"https://api.${DOMAIN}\"" >> ~/release/frontend/.env
99+
100+
pnpm build
101+
102+
echo "[1-4] 프론트엔드 파일 배포..."
103+
sudo rm -rf /var/www/html/*
104+
sudo cp -r dist/* /var/www/html/
105+
106+
echo "[1-5] AI 서버 준비 및 패키지 설치..."
107+
cd ~/release/ai-server/summarizer_pipeline
108+
if [ ! -d "venv" ]; then
109+
python3.12 -m venv venv
110+
fi
111+
source venv/bin/activate
112+
pip install -r requirements.txt
113+
114+
EOF
115+
116+
echo "✅ 서버 내 빌드 및 배포 완료 🎉"

bigbang/deploy/scripts/restore.sh

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#!/bin/bash
2+
set -euo pipefail
3+
source ./app-variables.sh
4+
# 키 캐시 삭제
5+
ssh-keygen -R $SERVER_IP || true
6+
# 로그 설정
7+
exec > >(gawk '{ print strftime("[%Y-%m-%d %H:%M:%S]"), $0; fflush(); }' >> ../logs/restore.log) 2>&1
8+
9+
echo "🔁 복원 스크립트 시작..."
10+
11+
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
12+
13+
ssh -i ${SSH_KEY} ubuntu@$SERVER_IP <<EOF
14+
set -euo pipefail
15+
mkdir -p ~/tmp
16+
17+
echo "========================================="
18+
echo "🔹 MySQL 복원 시작"
19+
echo "========================================="
20+
21+
LATEST_SQL_FILE=\$(gsutil ls ${BUCKET_BACKUP}/mysql/ | sort | tail -n 1 || true)
22+
23+
if [ -z "\${LATEST_SQL_FILE:-}" ]; then
24+
echo "❌ MySQL 백업 파일이 존재하지 않습니다. 복원을 건너뜁니다."
25+
else
26+
echo "📥 SQL 백업 다운로드: \$LATEST_SQL_FILE"
27+
gsutil cp "\$LATEST_SQL_FILE" ~/tmp/restore.sql
28+
29+
echo "🛠️ MySQL 복원 실행 중..."
30+
if sudo mysql -uroot -p"${DB_PASSWORD}" "${DB_NAME}" < ~/tmp/restore.sql; then
31+
echo "✅ MySQL 복원 완료"
32+
33+
echo "📊 복원된 테이블 정보:"
34+
sudo mysql -uroot -p"${DB_PASSWORD}" -e "USE ${DB_NAME}; SHOW TABLES;" | tail -n +2 | while read table; do
35+
count=\$(sudo mysql -uroot -p"${DB_PASSWORD}" -e "SELECT COUNT(*) FROM ${DB_NAME}.\\\\`\${table}\\\\\`;" | tail -n 1)
36+
echo " - \${table}: \${count} rows"
37+
done
38+
else
39+
echo "❌ MySQL 복원 실패"
40+
fi
41+
fi
42+
43+
echo "========================================="
44+
echo "🔹 SSL 인증서 복원 시작"
45+
echo "========================================="
46+
47+
LATEST_CERT_FILE=\$(gsutil ls ${BUCKET_BACKUP}/ssl/cert-backup_*.tar.gz | sort | tail -n 1 || true)
48+
49+
if [ -z "\${LATEST_CERT_FILE:-}" ]; then
50+
echo "⚠️ 인증서 백업 파일이 존재하지 않습니다. 복원을 건너뜁니다."
51+
else
52+
echo "📥 인증서 다운로드: \$LATEST_CERT_FILE"
53+
gsutil cp "\$LATEST_CERT_FILE" ~/tmp/cert-backup.tar.gz
54+
55+
echo "📦 인증서 압축 해제 중..."
56+
sudo tar xzf ~/tmp/cert-backup.tar.gz -C /
57+
58+
echo "🔐 퍼미션 설정..."
59+
sudo chown -R root:root /etc/letsencrypt
60+
sudo find /etc/letsencrypt -type d -exec chmod 755 {} \;
61+
sudo find /etc/letsencrypt -type f -exec chmod 644 {} \;
62+
63+
echo "🔁 nginx 재시작..."
64+
sudo systemctl restart nginx && echo "✅ nginx 재시작 완료" || echo "⚠️ nginx 재시작 실패"
65+
fi
66+
67+
echo "🎉 복원 스크립트 완료!"
68+
EOF

bigbang/deploy/scripts/rollback.sh

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!/bin/bash
2+
3+
SERVER_USER=ubuntu
4+
SERVER_IP=<GCP-VM-IP>
5+
SSH_KEY=~/.ssh/gcp-ssmu-dev-key
6+
7+
echo "[1] 최신 이전 버전으로 롤백 중..."
8+
9+
ssh -i $SSH_KEY $SERVER_USER@$SERVER_IP <<EOF
10+
PREV_JAR=\$(ls -t ~/release/app-*.jar | sed -n 2p)
11+
if [ -z "\$PREV_JAR" ]; then
12+
echo "❌ 롤백 가능한 이전 버전이 없습니다."
13+
exit 1
14+
fi
15+
echo "🔁 롤백 대상: \$PREV_JAR"
16+
pkill -f 'app.jar'
17+
ln -sf \$PREV_JAR ~/app.jar
18+
nohup java -jar ~/app.jar > ~/logs/backend_rollback.log 2>&1 &
19+
EOF
20+
21+
echo "✅ 롤백 완료"
22+

0 commit comments

Comments
 (0)