docs:배포 가이드 현행화 — 동시빌드방지, 승인알림, 환경파일 변경 반영
- 전체 Jenkinsfile에 disableConcurrentBuilds() 반영 - react/api Production Approval에 #product_deploy Slack 알림 추가 - react 환경파일 .env.local → .env.production 변경 반영 - Slack 알림 채널 테이블 추가 (#product_infra, #product_deploy) - 환경변수 파일 테이블 DEV_TOOLBAR 컬럼 추가 - 수동 배포 섹션 .env.production 반영 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -22,6 +22,13 @@
|
||||
| sam-manage | Laravel Admin 배포 | main | 운영 (직접) |
|
||||
| sam-sales | 레거시 PHP 배포 | main | 운영 (직접) |
|
||||
|
||||
### Slack 알림 채널
|
||||
|
||||
| 채널 | 용도 | 알림 내용 |
|
||||
|------|------|----------|
|
||||
| `#product_infra` | 빌드/배포 상태 | 빌드 시작, 배포 성공/실패 |
|
||||
| `#product_deploy` | 운영 배포 승인 | Stage 배포 완료 후 승인 대기 알림 (Jenkins 승인 링크 포함) |
|
||||
|
||||
### 2-Branch 전략 (develop + main)
|
||||
|
||||
> **stage 브랜치 없음.** main 브랜치 push 시 Stage 자동 배포 → Jenkins 승인 → Production 배포.
|
||||
@@ -35,7 +42,12 @@
|
||||
1. 개발자가 develop → main 머지 후 push
|
||||
2. post-receive hook → CI/CD Gitea 자동 push
|
||||
3. Jenkins 빌드 → Stage 자동 배포
|
||||
4. Jenkins UI에서 **승인 클릭** → Production 배포 (24시간 타임아웃)
|
||||
4. `#product_deploy` Slack 채널에 승인 대기 알림 전송
|
||||
5. Jenkins UI에서 **승인 클릭** → Production 배포 (24시간 타임아웃)
|
||||
|
||||
> **동시 빌드 방지:** 모든 파이프라인에 `disableConcurrentBuilds()` 적용.
|
||||
> 같은 프로젝트에서 빌드가 동시에 2개 이상 돌지 않음.
|
||||
> 승인 대기 중 새 push 시 → 기존 빌드 Abort 후 새 빌드 자동 시작.
|
||||
|
||||
**main 브랜치 배포 흐름 (mng/sales):**
|
||||
1. 개발자가 main push → hook → CI/CD Gitea → Jenkins → Production 직접 배포
|
||||
@@ -141,6 +153,8 @@ Repository Settings → Webhooks → Add Webhook (Gitea)
|
||||
│ │ │
|
||||
│ ├─ Stage 자동 배포 (react: .env.stage 빌드) │
|
||||
│ │ │
|
||||
│ ├─ 📢 #product_deploy Slack 알림 (승인 링크 포함) │
|
||||
│ │ │
|
||||
│ ├─ ⏸️ 승인 대기 (24시간 타임아웃) │
|
||||
│ │ https://ci.sam.it.kr 에서 "운영 배포 진행" 클릭 │
|
||||
│ │ │
|
||||
@@ -183,11 +197,11 @@ CI/CD Gitea push -> Webhook -> Jenkins
|
||||
|
||||
**환경변수 파일 (CI/CD 서버):** /var/lib/jenkins/env-files/react/
|
||||
|
||||
| 파일 | API URL | Frontend URL | APP_ENV |
|
||||
|------|---------|-------------|---------|
|
||||
| .env.develop | https://api.codebridge-x.com | https://dev.codebridge-x.com | development |
|
||||
| .env.stage | https://stage-api.sam.it.kr | https://stage.sam.it.kr | staging |
|
||||
| .env.main | https://api.sam.it.kr | https://sam.it.kr | production |
|
||||
| 파일 | API URL | Frontend URL | APP_ENV | DEV_TOOLBAR |
|
||||
|------|---------|-------------|---------|-------------|
|
||||
| .env.develop | https://api.codebridge-x.com | https://dev.codebridge-x.com | development | - |
|
||||
| .env.stage | https://stage-api.sam.it.kr | https://stage.sam.it.kr | staging | - |
|
||||
| .env.main | https://api.sam.it.kr | https://sam.it.kr | production | false |
|
||||
|
||||
> `NEXT_PUBLIC_APP_ENV` 값으로 타이틀 접두사 결정: `development` → `[D]`, `local` → `[L]`, 그 외 → 없음
|
||||
|
||||
@@ -201,6 +215,10 @@ CI/CD Gitea push -> Webhook -> Jenkins
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
options {
|
||||
disableConcurrentBuilds()
|
||||
}
|
||||
|
||||
environment {
|
||||
DEPLOY_USER = 'hskwon'
|
||||
RELEASE_ID = new Date().format('yyyyMMdd_HHmmss')
|
||||
@@ -220,10 +238,10 @@ pipeline {
|
||||
script {
|
||||
if (env.BRANCH_NAME == 'main') {
|
||||
// main: Stage 빌드 먼저 (승인 후 Production 재빌드)
|
||||
sh "cp /var/lib/jenkins/env-files/react/.env.stage .env.local"
|
||||
sh "cp /var/lib/jenkins/env-files/react/.env.stage .env.production"
|
||||
} else {
|
||||
def envFile = "/var/lib/jenkins/env-files/react/.env.${env.BRANCH_NAME}"
|
||||
sh "cp ${envFile} .env.local"
|
||||
sh "cp ${envFile} .env.production"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -247,7 +265,7 @@ pipeline {
|
||||
--exclude='.git' --exclude='.env*' --exclude='ecosystem.config.*' \
|
||||
.next package.json next.config.ts public node_modules \
|
||||
${DEPLOY_USER}@114.203.209.83:/home/webservice/react/
|
||||
scp .env.local ${DEPLOY_USER}@114.203.209.83:/home/webservice/react/.env.local
|
||||
scp .env.production ${DEPLOY_USER}@114.203.209.83:/home/webservice/react/.env.production
|
||||
ssh ${DEPLOY_USER}@114.203.209.83 'cd /home/webservice/react && pm2 restart sam-react'
|
||||
"""
|
||||
}
|
||||
@@ -264,7 +282,7 @@ pipeline {
|
||||
rsync -az --delete \
|
||||
.next package.json next.config.ts public node_modules \
|
||||
${DEPLOY_USER}@211.117.60.189:/home/webservice/react-stage/releases/${RELEASE_ID}/
|
||||
scp .env.local ${DEPLOY_USER}@211.117.60.189:/home/webservice/react-stage/releases/${RELEASE_ID}/.env.local
|
||||
scp .env.production ${DEPLOY_USER}@211.117.60.189:/home/webservice/react-stage/releases/${RELEASE_ID}/.env.production
|
||||
ssh ${DEPLOY_USER}@211.117.60.189 '
|
||||
ln -sfn /home/webservice/react-stage/releases/${RELEASE_ID} /home/webservice/react-stage/current &&
|
||||
cd /home/webservice && pm2 reload sam-front-stage 2>/dev/null || pm2 start react-stage/current/node_modules/.bin/next --name sam-front-stage -- start -p 3100 &&
|
||||
@@ -279,6 +297,8 @@ pipeline {
|
||||
stage('Production Approval') {
|
||||
when { branch 'main' }
|
||||
steps {
|
||||
slackSend channel: '#product_deploy', color: '#FF9800', tokenCredentialId: 'slack-token',
|
||||
message: "🔔 *react* 운영 배포 승인 대기 중\nStage: https://stage.sam.it.kr\n<${env.BUILD_URL}input|승인하러 가기>"
|
||||
timeout(time: 24, unit: 'HOURS') {
|
||||
input message: 'Stage 확인 후 운영 배포를 진행하시겠습니까?\nStage: https://stage.sam.it.kr',
|
||||
ok: '운영 배포 진행'
|
||||
@@ -290,7 +310,7 @@ pipeline {
|
||||
stage('Rebuild for Production') {
|
||||
when { branch 'main' }
|
||||
steps {
|
||||
sh "cp /var/lib/jenkins/env-files/react/.env.main .env.local"
|
||||
sh "cp /var/lib/jenkins/env-files/react/.env.main .env.production"
|
||||
sh 'npm run build'
|
||||
}
|
||||
}
|
||||
@@ -305,7 +325,7 @@ pipeline {
|
||||
rsync -az --delete \
|
||||
.next package.json next.config.ts public node_modules \
|
||||
${DEPLOY_USER}@211.117.60.189:/home/webservice/react/releases/${RELEASE_ID}/
|
||||
scp .env.local ${DEPLOY_USER}@211.117.60.189:/home/webservice/react/releases/${RELEASE_ID}/.env.local
|
||||
scp .env.production ${DEPLOY_USER}@211.117.60.189:/home/webservice/react/releases/${RELEASE_ID}/.env.production
|
||||
ssh ${DEPLOY_USER}@211.117.60.189 '
|
||||
ln -sfn /home/webservice/react/releases/${RELEASE_ID} /home/webservice/react/current &&
|
||||
cd /home/webservice && pm2 reload sam-front &&
|
||||
@@ -334,6 +354,10 @@ pipeline {
|
||||
> Stage(.env.stage)와 Production(.env.main)에서 별도 빌드가 필요하다.
|
||||
> main 빌드 시 Stage용으로 먼저 빌드 → 승인 후 Production용으로 재빌드.
|
||||
|
||||
> **환경파일:** Jenkins는 CI/CD 서버의 env-files를 `.env.production`으로 복사하여 빌드한다.
|
||||
> Next.js 우선순위: `.env.local` > `.env.production` > `.env`
|
||||
> 따라서 서버에 `.env.local`이 있으면 `.env.production`을 덮어쓰므로 `.env.local`은 사용하지 않는다.
|
||||
|
||||
### PM2 수동 재시작
|
||||
|
||||
```bash
|
||||
@@ -374,6 +398,10 @@ CI/CD Gitea push -> Webhook -> Jenkins
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
options {
|
||||
disableConcurrentBuilds()
|
||||
}
|
||||
|
||||
environment {
|
||||
DEPLOY_USER = 'hskwon'
|
||||
RELEASE_ID = new Date().format('yyyyMMdd_HHmmss')
|
||||
@@ -423,6 +451,8 @@ pipeline {
|
||||
stage('Production Approval') {
|
||||
when { branch 'main' }
|
||||
steps {
|
||||
slackSend channel: '#product_deploy', color: '#FF9800', tokenCredentialId: 'slack-token',
|
||||
message: "🔔 *api* 운영 배포 승인 대기 중\nStage API: https://stage-api.sam.it.kr\n<${env.BUILD_URL}input|승인하러 가기>"
|
||||
timeout(time: 24, unit: 'HOURS') {
|
||||
input message: 'Stage 확인 후 운영 배포를 진행하시겠습니까?\nStage API: https://stage-api.sam.it.kr',
|
||||
ok: '운영 배포 진행'
|
||||
@@ -583,6 +613,10 @@ API와 동일한 releases/shared 구조. 차이점: npm build 추가, Queue Work
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
options {
|
||||
disableConcurrentBuilds()
|
||||
}
|
||||
|
||||
environment {
|
||||
DEPLOY_USER = 'hskwon'
|
||||
RELEASE_ID = new Date().format('yyyyMMdd_HHmmss')
|
||||
@@ -813,7 +847,7 @@ ssh sam-prod "
|
||||
cd /tmp
|
||||
git clone --depth 1 --branch main https://git.sam.it.kr/SamProject/sam-react-prod.git react-build
|
||||
cd react-build
|
||||
cp /var/lib/jenkins/env-files/react/.env.main .env.local
|
||||
cp /var/lib/jenkins/env-files/react/.env.main .env.production
|
||||
npm install --prefer-offline
|
||||
npm run build
|
||||
|
||||
@@ -824,7 +858,7 @@ ssh sam-prod "mkdir -p /home/webservice/react/releases/${RELEASE_ID}"
|
||||
rsync -az --delete \
|
||||
.next package.json next.config.ts public node_modules \
|
||||
hskwon@211.117.60.189:/home/webservice/react/releases/${RELEASE_ID}/
|
||||
scp .env.local hskwon@211.117.60.189:/home/webservice/react/releases/${RELEASE_ID}/.env.local
|
||||
scp .env.production hskwon@211.117.60.189:/home/webservice/react/releases/${RELEASE_ID}/.env.production
|
||||
|
||||
# 심링크 전환 및 PM2 재시작
|
||||
ssh sam-prod "
|
||||
|
||||
Reference in New Issue
Block a user