docs(DOC): ops-manual 2-Branch 전략 반영 — stage 브랜치 제거, Jenkins 승인 기반 배포
- 04-service-cicd: credential 타입 수정, Nginx 설정 추가, 동기화 브랜치 테이블 업데이트 - 05-deployment: 파이프라인 설정/흐름도/Jenkinsfile 전면 개편 (develop+main 2-Branch) - React/API: main push → Stage 자동배포 → Jenkins 승인 → Production 배포 - MNG/Sales: main push → Production 직접 배포 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -48,7 +48,7 @@ sudo journalctl -u jenkins --since "2 hours ago" --no-pager
|
||||
| Credential ID | 유형 | 용도 |
|
||||
|--------------|------|------|
|
||||
| deploy-ssh-key | SSH Username with private key | 운영/개발서버 SSH 배포 |
|
||||
| gitea-api-token | Secret text | Gitea API 연동 |
|
||||
| gitea-api-token | Username with password | Gitea API 연동 (token을 username, 비밀번호 빈값) |
|
||||
|
||||
**Credential 위치:** Jenkins 관리 > Credentials > System > Global credentials
|
||||
|
||||
@@ -181,18 +181,24 @@ sudo -u git /usr/local/bin/gitea admin user create \
|
||||
|
||||
**토큰 파일 (개발서버):** `/data/GIT/.cicd-env` (chmod 600, owner: git)
|
||||
|
||||
| 저장소 | 동기화 브랜치 |
|
||||
|--------|-------------|
|
||||
| sam-react-prod | stage, develop |
|
||||
| sam-api | stage |
|
||||
| sam-sales | main |
|
||||
| sam-manage | 없음 (배포관리자 수동 push) |
|
||||
| 저장소 | 동기화 브랜치 | 비고 |
|
||||
|--------|-------------|------|
|
||||
| sam-react-prod | main, develop | post-update hook 비활성화 (CI/CD가 개발서버 배포 담당) |
|
||||
| sam-api | main | develop은 기존 post-update hook 유지 |
|
||||
| sam-sales | main | |
|
||||
| sam-manage | main | 2026-02-24 hook 추가 |
|
||||
|
||||
> **참고:** react의 개발서버 배포는 Jenkins CI/CD 파이프라인이 처리한다.
|
||||
> 기존 post-update hook의 git pull 방식(`pull_react.sh`)은 비활성화됨 (2026-02-24).
|
||||
> 스크립트 위치: `/home/webservice/script/pull_react.sh`
|
||||
|
||||
**동기화 로그 확인:**
|
||||
|
||||
```bash
|
||||
ssh sam-dev "tail -20 /home/webservice/logs/cicd_push_sam-react-prod.log"
|
||||
ssh sam-dev "tail -20 /home/webservice/logs/cicd_push_sam-api.log"
|
||||
ssh sam-dev "tail -20 /home/webservice/logs/cicd_push_react-prod.log"
|
||||
ssh sam-dev "tail -20 /home/webservice/logs/cicd_push_api.log"
|
||||
ssh sam-dev "tail -20 /home/webservice/logs/cicd_push_sales.log"
|
||||
ssh sam-dev "tail -20 /home/webservice/logs/cicd_push_manage.log"
|
||||
```
|
||||
|
||||
---
|
||||
@@ -303,6 +309,13 @@ sudo systemctl status nginx
|
||||
| /etc/nginx/sites-available/ci.sam.it.kr | Jenkins 리버스 프록시 |
|
||||
| /etc/nginx/sites-available/monitor.sam.it.kr | Grafana 리버스 프록시 |
|
||||
|
||||
**git.sam.it.kr 주요 설정:**
|
||||
|
||||
```nginx
|
||||
client_max_body_size 500M; # 대용량 Git push 허용
|
||||
proxy_request_buffering off; # 스트리밍 전송 (413 방지)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## node_exporter / Certbot / fail2ban / UFW
|
||||
|
||||
@@ -17,28 +17,28 @@
|
||||
|
||||
| 저장소 | 파이프라인 | 트리거 브랜치 | 배포 대상 |
|
||||
|--------|-----------|-------------|----------|
|
||||
| sam-react-prod | React 빌드+배포 | develop, stage, main | 개발/Stage/운영 |
|
||||
| sam-api | Laravel API 배포 | stage, main | Stage/운영 |
|
||||
| sam-manage | Laravel Admin 배포 | main | 운영 |
|
||||
| sam-sales | 레거시 PHP 배포 | main | 운영 |
|
||||
| sam-react-prod | React 빌드+배포 | develop, main | 개발 / Stage→승인→운영 |
|
||||
| sam-api | Laravel API 배포 | main | Stage→승인→운영 |
|
||||
| sam-manage | Laravel Admin 배포 | main | 운영 (직접) |
|
||||
| sam-sales | 레거시 PHP 배포 | main | 운영 (직접) |
|
||||
|
||||
### 브랜치별 동작
|
||||
### 2-Branch 전략 (develop + main)
|
||||
|
||||
> **stage 브랜치 없음.** main 브랜치 push 시 Stage 자동 배포 → Jenkins 승인 → Production 배포.
|
||||
|
||||
| 브랜치 | react | api | mng | sales |
|
||||
|--------|-------|-----|-----|-------|
|
||||
| develop | Jenkins 빌드 -> 개발서버 | 기존 hook | 기존 hook | 기존 hook |
|
||||
| stage | Jenkins 빌드 -> 운영 Stage | Jenkins -> 운영 Stage | - | - |
|
||||
| main | Jenkins 빌드 -> 운영 Production | Jenkins -> 운영 Production | Jenkins -> 운영 Production | Jenkins -> 운영 pull |
|
||||
| develop | Jenkins 빌드 → 개발서버 | 기존 post-update hook | 기존 post-update hook | 기존 post-update hook |
|
||||
| main | Stage 배포 → **승인** → Production 배포 | Stage 배포 → **승인** → Production 배포 | Production 직접 배포 | Production 직접 배포 |
|
||||
|
||||
**main 브랜치 배포:** 배포관리자가 CI/CD Gitea에 수동 push 후 자동 실행
|
||||
**main 브랜치 배포 흐름 (react/api):**
|
||||
1. 개발자가 develop → main 머지 후 push
|
||||
2. post-receive hook → CI/CD Gitea 자동 push
|
||||
3. Jenkins 빌드 → Stage 자동 배포
|
||||
4. Jenkins UI에서 **승인 클릭** → Production 배포 (24시간 타임아웃)
|
||||
|
||||
```bash
|
||||
# 1회 remote 등록
|
||||
git remote add production https://git.sam.it.kr/SamProject/sam-react-prod.git
|
||||
|
||||
# 운영 배포 시
|
||||
git push production main
|
||||
```
|
||||
**main 브랜치 배포 흐름 (mng/sales):**
|
||||
1. 개발자가 main push → hook → CI/CD Gitea → Jenkins → Production 직접 배포
|
||||
|
||||
---
|
||||
|
||||
@@ -51,7 +51,7 @@ git push production main
|
||||
|
||||
```
|
||||
개발자 로컬
|
||||
│ git push origin (develop/stage/main)
|
||||
│ git push origin (develop / main)
|
||||
▼
|
||||
개발서버 Gitea (114.203.209.83:3000) ← 모든 개발자의 origin
|
||||
│
|
||||
@@ -59,30 +59,21 @@ git push production main
|
||||
│ ├─ api/mng/sales: 기존 post-update hook (개발서버 pull) ← 현행 유지
|
||||
│ └─ react: hook → CI/CD Gitea push → Jenkins 빌드 → 개발서버 배포
|
||||
│
|
||||
├─ stage push 시
|
||||
│ ├─ react: hook → CI/CD Gitea push → Jenkins 빌드 → 운영서버 Stage 배포
|
||||
│ └─ api: hook → CI/CD Gitea push → Jenkins → 운영서버 Stage pull
|
||||
│
|
||||
└─ main push 시 (react/mng/api)
|
||||
└─ ❌ CI/CD Gitea에 자동 push 안함
|
||||
→ 배포관리자가 수동으로 CI/CD Gitea에 push
|
||||
→ Jenkins 자동 배포
|
||||
|
||||
별도 처리:
|
||||
sales/www(landing): hook → CI/CD Gitea → Jenkins → 운영서버 pull
|
||||
└─ main push 시
|
||||
├─ react: hook → CI/CD Gitea → Jenkins 빌드 → Stage 배포 → 승인 → Production 배포
|
||||
├─ api: hook → CI/CD Gitea → Jenkins → Stage 배포 → 승인 → Production 배포
|
||||
├─ mng: hook → CI/CD Gitea → Jenkins → Production 직접 배포
|
||||
└─ sales: hook → CI/CD Gitea → Jenkins → Production 직접 배포
|
||||
```
|
||||
|
||||
### 브랜치별 배포 정책 상세
|
||||
|
||||
| 브랜치 | 저장소 | CI/CD Gitea 동기화 | Jenkins 배포 | 배포 대상 |
|
||||
|--------|--------|-------------------|-------------|----------|
|
||||
| **stage** | react | 자동 (hook) | 빌드 + rsync | 운영서버 Stage |
|
||||
| **stage** | api | 자동 (hook) | SSH pull | 운영서버 Stage |
|
||||
| **main** | react | 수동 (배포관리자) | 빌드 + rsync | 운영서버 Production |
|
||||
| **main** | mng | 수동 (배포관리자) | SSH deploy | 운영서버 Production |
|
||||
| **main** | api | 수동 (배포관리자) | SSH deploy | 운영서버 Production |
|
||||
| **main** | sales | 자동 (hook) | SSH pull | 운영서버 Production |
|
||||
| **main** | www | 자동 (hook) | SSH pull | 운영서버 Production |
|
||||
| **main** | react | 자동 (hook) | 빌드 → Stage → **승인** → 재빌드 → Production | Stage + Production |
|
||||
| **main** | api | 자동 (hook) | rsync → Stage → **승인** → rsync → Production | Stage + Production |
|
||||
| **main** | mng | 자동 (hook) | rsync + npm build → Production | Production |
|
||||
| **main** | sales | 자동 (hook) | rsync → Production | Production |
|
||||
| **develop** | react | 자동 (hook) | 빌드 → 개발서버 배포 | 개발서버 |
|
||||
| **develop** | api/mng/sales | ❌ (현행 유지) | ❌ | 개발서버 (post-update hook) |
|
||||
|
||||
@@ -90,11 +81,11 @@ git push production main
|
||||
|
||||
| 저장소 | hook 대상 브랜치 | 동작 |
|
||||
|--------|-----------------|------|
|
||||
| sam-react-prod | stage, develop | CI/CD Gitea에 push |
|
||||
| sam-api | stage | CI/CD Gitea에 push |
|
||||
| sam-react-prod | main, develop | CI/CD Gitea에 push |
|
||||
| sam-api | main | CI/CD Gitea에 push |
|
||||
| sam-manage | main | CI/CD Gitea에 push |
|
||||
| sam-sales | main | CI/CD Gitea에 push |
|
||||
| sam-landing | main | CI/CD Gitea에 push |
|
||||
| sam-manage | ❌ 없음 | main만 사용, 배포관리자 수동 push |
|
||||
|
||||
hook 스크립트 경로: `/data/GIT/samproject/<repo>.git/hooks/post-receive.d/push-to-cicd`
|
||||
토큰 환경변수: `/data/GIT/.cicd-env` (chmod 600, owner: git)
|
||||
@@ -117,7 +108,7 @@ Repository Settings → Webhooks → Add Webhook (Gitea)
|
||||
|
||||
```
|
||||
개발자 로컬
|
||||
│ git push origin (develop / stage / main)
|
||||
│ git push origin (develop / main)
|
||||
▼
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ 개발서버 Gitea (114.203.209.83:3000) ← 모든 개발자 origin │
|
||||
@@ -132,46 +123,42 @@ Repository Settings → Webhooks → Add Webhook (Gitea)
|
||||
│ │ sales → 기존 post-update hook (pull) │ │
|
||||
│ └───────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─ stage push ──────────────────────────────────────────┐ │
|
||||
│ │ react → hook: CI/CD Gitea push ──→ Jenkins 빌드 │ │
|
||||
│ │ → rsync → 운영서버 Stage + PM2 reload │ │
|
||||
│ ┌─ main push (모든 저장소 자동) ────────────────────────┐ │
|
||||
│ │ react → hook: CI/CD Gitea push ──→ Jenkins │ │
|
||||
│ │ → Stage 빌드+배포 → 승인 → Production 재빌드 │ │
|
||||
│ │ api → hook: CI/CD Gitea push ──→ Jenkins │ │
|
||||
│ │ → 운영서버 Stage Release + 심링크 │ │
|
||||
│ └───────────────────────────────────────────────────────┘ │
|
||||
│ │
|
||||
│ ┌─ main push (sales/www만 자동) ────────────────────────┐ │
|
||||
│ │ → Stage rsync+배포 → 승인 → Production 배포 │ │
|
||||
│ │ mng → hook: CI/CD Gitea push ──→ Jenkins │ │
|
||||
│ │ → Production rsync + build │ │
|
||||
│ │ sales → hook: CI/CD Gitea push ──→ Jenkins │ │
|
||||
│ │ → 운영서버 rsync │ │
|
||||
│ │ www → hook: CI/CD Gitea push ──→ Jenkins │ │
|
||||
│ │ → 운영서버 pull │ │
|
||||
│ │ react/mng/api → ❌ 자동 push 안함 │ │
|
||||
│ │ → Production rsync │ │
|
||||
│ └───────────────────────────────────────────────────────┘ │
|
||||
└───────────────────────────────────────────────────────────────┘
|
||||
|
||||
┌─ 운영 배포 (main - react/mng/api) ──────────────────────────┐
|
||||
┌─ Jenkins 승인 흐름 (react/api main) ─────────────────────────┐
|
||||
│ │
|
||||
│ 배포관리자 로컬 │
|
||||
│ │ git push production main (CI/CD Gitea remote) │
|
||||
│ ▼ │
|
||||
│ CI/CD Gitea (git.sam.it.kr) │
|
||||
│ │ Webhook │
|
||||
│ ▼ │
|
||||
│ Jenkins → 운영서버 배포 │
|
||||
│ react: CI/CD 빌드 → rsync → PM2 reload │
|
||||
│ api: Release + 심링크 → PHP-FPM reload │
|
||||
│ mng: Release + 심링크 → PHP-FPM reload │
|
||||
│ Jenkins 빌드 시작 │
|
||||
│ │ │
|
||||
│ ├─ Stage 자동 배포 (react: .env.stage 빌드) │
|
||||
│ │ │
|
||||
│ ├─ ⏸️ 승인 대기 (24시간 타임아웃) │
|
||||
│ │ https://ci.sam.it.kr 에서 "운영 배포 진행" 클릭 │
|
||||
│ │ │
|
||||
│ ├─ Production 배포 (react: .env.main 재빌드) │
|
||||
│ │ │
|
||||
│ └─ 완료 │
|
||||
│ │
|
||||
└───────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 환경별 배포 비교
|
||||
|
||||
| 항목 | 운영 (main) | Stage (stage) | 개발 (develop) |
|
||||
|------|------------|---------------|----------------|
|
||||
| **트리거** | 배포관리자 수동 push | 자동 (hook) | react만 자동 (hook), 나머지 기존 hook |
|
||||
| **react 전략** | CI/CD 빌드 → rsync | CI/CD 빌드 → rsync | CI/CD 빌드 → rsync |
|
||||
| **api 전략** | Release + 심링크 | Release + 심링크 | 기존 post-update (pull) |
|
||||
| **mng 전략** | Release + 심링크 | - | 기존 post-update (pull + build) |
|
||||
| 항목 | Production (main→승인) | Stage (main→자동) | 개발 (develop) |
|
||||
|------|----------------------|------------------|----------------|
|
||||
| **트리거** | main push → Jenkins 승인 | main push → 자동 | react만 자동 (hook), 나머지 기존 hook |
|
||||
| **react 전략** | CI/CD 빌드(.env.main) → rsync | CI/CD 빌드(.env.stage) → rsync | CI/CD 빌드(.env.develop) → rsync |
|
||||
| **api 전략** | rsync + Release 심링크 | rsync + Release 심링크 | 기존 post-update (pull) |
|
||||
| **mng 전략** | rsync + npm build + Release 심링크 | - | 기존 post-update (pull + build) |
|
||||
| **롤백** | 이전 릴리즈 심링크 | 이전 릴리즈 심링크 | git revert |
|
||||
| **릴리즈 보관** | 최근 5개 | 최근 3개 | - |
|
||||
|
||||
@@ -188,11 +175,11 @@ CI/CD Gitea push -> Webhook -> Jenkins
|
||||
|
||||
**브랜치별 배포 대상:**
|
||||
|
||||
| 브랜치 | 대상 서버 | 대상 경로 | PM2 이름 | 트리거 |
|
||||
|--------|----------|----------|----------|--------|
|
||||
| develop | 개발서버 (114.203.209.83) | /home/webservice/react/ | sam-react | 자동 (hook) |
|
||||
| stage | 운영서버 (211.117.60.189) | /home/webservice/react-stage/releases/ | sam-front-stage | 자동 (hook) |
|
||||
| main | 운영서버 (211.117.60.189) | /home/webservice/react/releases/ | sam-front | 수동 push |
|
||||
| 브랜치 | 배포 단계 | 대상 서버 | 대상 경로 | PM2 이름 |
|
||||
|--------|----------|----------|----------|----------|
|
||||
| develop | 개발서버 | 114.203.209.83 | /home/webservice/react/ | sam-react |
|
||||
| main | Stage (자동) | 211.117.60.189 | /home/webservice/react-stage/releases/ | sam-front-stage |
|
||||
| main | Production (승인 후) | 211.117.60.189 | /home/webservice/react/releases/ | sam-front |
|
||||
|
||||
**환경변수 파일 (CI/CD 서버):** /var/lib/jenkins/env-files/react/
|
||||
|
||||
@@ -225,8 +212,13 @@ pipeline {
|
||||
stage('Prepare Env') {
|
||||
steps {
|
||||
script {
|
||||
def envFile = "/var/lib/jenkins/env-files/react/.env.${env.BRANCH_NAME}"
|
||||
sh "cp ${envFile} .env.local"
|
||||
if (env.BRANCH_NAME == 'main') {
|
||||
// main: Stage 빌드 먼저 (승인 후 Production 재빌드)
|
||||
sh "cp /var/lib/jenkins/env-files/react/.env.stage .env.local"
|
||||
} else {
|
||||
def envFile = "/var/lib/jenkins/env-files/react/.env.${env.BRANCH_NAME}"
|
||||
sh "cp ${envFile} .env.local"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -256,9 +248,9 @@ pipeline {
|
||||
}
|
||||
}
|
||||
|
||||
// ── stage → 운영서버 Stage 배포 ──
|
||||
// ── main → 운영서버 Stage 배포 ──
|
||||
stage('Deploy Stage') {
|
||||
when { branch 'stage' }
|
||||
when { branch 'main' }
|
||||
steps {
|
||||
sshagent(credentials: ['deploy-ssh-key']) {
|
||||
sh """
|
||||
@@ -277,6 +269,26 @@ pipeline {
|
||||
}
|
||||
}
|
||||
|
||||
// ── 운영 배포 승인 ──
|
||||
stage('Production Approval') {
|
||||
when { branch 'main' }
|
||||
steps {
|
||||
timeout(time: 24, unit: 'HOURS') {
|
||||
input message: 'Stage 확인 후 운영 배포를 진행하시겠습니까?\nStage: https://stage.sam.it.kr',
|
||||
ok: '운영 배포 진행'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── main → Production 재빌드 (운영 환경변수) ──
|
||||
stage('Rebuild for Production') {
|
||||
when { branch 'main' }
|
||||
steps {
|
||||
sh "cp /var/lib/jenkins/env-files/react/.env.main .env.local"
|
||||
sh 'npm run build'
|
||||
}
|
||||
}
|
||||
|
||||
// ── main → 운영서버 Production 배포 ──
|
||||
stage('Deploy Production') {
|
||||
when { branch 'main' }
|
||||
@@ -306,6 +318,10 @@ pipeline {
|
||||
}
|
||||
```
|
||||
|
||||
> **참고:** Next.js는 `NEXT_PUBLIC_*` 환경변수가 빌드 시 바인딩되므로,
|
||||
> Stage(.env.stage)와 Production(.env.main)에서 별도 빌드가 필요하다.
|
||||
> main 빌드 시 Stage용으로 먼저 빌드 → 승인 후 Production용으로 재빌드.
|
||||
|
||||
### PM2 수동 재시작
|
||||
|
||||
```bash
|
||||
@@ -329,16 +345,16 @@ pm2 save
|
||||
|
||||
```
|
||||
CI/CD Gitea push -> Webhook -> Jenkins
|
||||
-> SSH: git clone -> composer install -> artisan cache -> migrate -> 심링크 전환 -> PHP-FPM reload
|
||||
-> checkout -> rsync → Stage 배포 → 승인 → rsync → Production 배포
|
||||
```
|
||||
|
||||
**브랜치별 배포 대상:**
|
||||
|
||||
| 브랜치 | 대상 서버 | 대상 경로 | 트리거 |
|
||||
|--------|----------|----------|--------|
|
||||
| stage | 운영서버 | /home/webservice/api-stage/releases/ | 자동 (hook) |
|
||||
| main | 운영서버 | /home/webservice/api/releases/ | 수동 push |
|
||||
| develop | 개발서버 | - (기존 post-update hook) | 기존 hook |
|
||||
| 브랜치 | 배포 단계 | 대상 서버 | 대상 경로 |
|
||||
|--------|----------|----------|----------|
|
||||
| main | Stage (자동) | 운영서버 | /home/webservice/api-stage/releases/ |
|
||||
| main | Production (승인 후) | 운영서버 | /home/webservice/api/releases/ |
|
||||
| develop | 개발서버 | 개발서버 | 기존 post-update hook |
|
||||
|
||||
### Jenkinsfile (api/Jenkinsfile)
|
||||
|
||||
@@ -348,8 +364,7 @@ pipeline {
|
||||
|
||||
environment {
|
||||
DEPLOY_USER = 'hskwon'
|
||||
APP_NAME = 'api'
|
||||
RELEASE_ID = new Date().format('yyyyMMdd_HHmmss')
|
||||
RELEASE_ID = new Date().format('yyyyMMdd_HHmmss')
|
||||
}
|
||||
|
||||
stages {
|
||||
@@ -357,18 +372,63 @@ pipeline {
|
||||
steps { checkout scm }
|
||||
}
|
||||
|
||||
// ── main → 운영서버 (배포관리자 수동 push 후 트리거) ──
|
||||
// ── main → 운영서버 Stage 배포 ──
|
||||
stage('Deploy Stage') {
|
||||
when { branch 'main' }
|
||||
steps {
|
||||
sshagent(credentials: ['deploy-ssh-key']) {
|
||||
sh """
|
||||
ssh ${DEPLOY_USER}@211.117.60.189 'mkdir -p /home/webservice/api-stage/releases/${RELEASE_ID}'
|
||||
rsync -az --delete \
|
||||
--exclude='.git' --exclude='.env' \
|
||||
--exclude='storage/app' --exclude='storage/logs' \
|
||||
--exclude='storage/framework/sessions' --exclude='storage/framework/cache' \
|
||||
. ${DEPLOY_USER}@211.117.60.189:/home/webservice/api-stage/releases/${RELEASE_ID}/
|
||||
ssh ${DEPLOY_USER}@211.117.60.189 '
|
||||
cd /home/webservice/api-stage/releases/${RELEASE_ID} &&
|
||||
ln -sfn /home/webservice/api-stage/shared/.env .env &&
|
||||
ln -sfn /home/webservice/api-stage/shared/storage/app storage/app &&
|
||||
composer install --no-dev --optimize-autoloader --no-interaction &&
|
||||
php artisan config:cache &&
|
||||
php artisan route:cache &&
|
||||
php artisan view:cache &&
|
||||
php artisan migrate --force &&
|
||||
ln -sfn /home/webservice/api-stage/releases/${RELEASE_ID} /home/webservice/api-stage/current &&
|
||||
sudo systemctl reload php8.4-fpm &&
|
||||
cd /home/webservice/api-stage/releases && ls -1dt */ | tail -n +4 | xargs rm -rf 2>/dev/null || true
|
||||
'
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── 운영 배포 승인 ──
|
||||
stage('Production Approval') {
|
||||
when { branch 'main' }
|
||||
steps {
|
||||
timeout(time: 24, unit: 'HOURS') {
|
||||
input message: 'Stage 확인 후 운영 배포를 진행하시겠습니까?\nStage API: https://stage-api.sam.it.kr',
|
||||
ok: '운영 배포 진행'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── main → 운영서버 Production 배포 ──
|
||||
stage('Deploy Production') {
|
||||
when { branch 'main' }
|
||||
steps {
|
||||
sshagent(credentials: ['deploy-ssh-key']) {
|
||||
sh """
|
||||
ssh ${DEPLOY_USER}@211.117.60.189 'mkdir -p /home/webservice/api/releases/${RELEASE_ID}'
|
||||
rsync -az --delete \
|
||||
--exclude='.git' --exclude='.env' \
|
||||
--exclude='storage/app' --exclude='storage/logs' \
|
||||
--exclude='storage/framework/sessions' --exclude='storage/framework/cache' \
|
||||
. ${DEPLOY_USER}@211.117.60.189:/home/webservice/api/releases/${RELEASE_ID}/
|
||||
ssh ${DEPLOY_USER}@211.117.60.189 '
|
||||
cd /home/webservice/api/releases &&
|
||||
git clone --depth 1 --branch main https://git.sam.it.kr/SamProject/sam-api.git ${RELEASE_ID} &&
|
||||
ln -sfn /home/webservice/api/shared/storage /home/webservice/api/releases/${RELEASE_ID}/storage &&
|
||||
ln -sfn /home/webservice/api/shared/.env /home/webservice/api/releases/${RELEASE_ID}/.env &&
|
||||
cd /home/webservice/api/releases/${RELEASE_ID} &&
|
||||
ln -sfn /home/webservice/api/shared/.env .env &&
|
||||
ln -sfn /home/webservice/api/shared/storage/app storage/app &&
|
||||
composer install --no-dev --optimize-autoloader --no-interaction &&
|
||||
php artisan config:cache &&
|
||||
php artisan route:cache &&
|
||||
@@ -377,35 +437,7 @@ pipeline {
|
||||
ln -sfn /home/webservice/api/releases/${RELEASE_ID} /home/webservice/api/current &&
|
||||
sudo systemctl reload php8.4-fpm &&
|
||||
sudo supervisorctl restart sam-queue-worker:* &&
|
||||
cd /home/webservice/api/releases &&
|
||||
ls -1dt */ | tail -n +6 | xargs rm -rf 2>/dev/null || true
|
||||
'
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ── stage → 운영서버 Stage ──
|
||||
stage('Deploy Stage') {
|
||||
when { branch 'stage' }
|
||||
steps {
|
||||
sshagent(credentials: ['deploy-ssh-key']) {
|
||||
sh """
|
||||
ssh ${DEPLOY_USER}@211.117.60.189 '
|
||||
cd /home/webservice/api-stage/releases &&
|
||||
git clone --depth 1 --branch stage https://git.sam.it.kr/SamProject/sam-api.git ${RELEASE_ID} &&
|
||||
ln -sfn /home/webservice/api-stage/shared/storage /home/webservice/api-stage/releases/${RELEASE_ID}/storage &&
|
||||
ln -sfn /home/webservice/api-stage/shared/.env /home/webservice/api-stage/releases/${RELEASE_ID}/.env &&
|
||||
cd /home/webservice/api-stage/releases/${RELEASE_ID} &&
|
||||
composer install --no-dev --optimize-autoloader --no-interaction &&
|
||||
php artisan config:cache &&
|
||||
php artisan route:cache &&
|
||||
php artisan view:cache &&
|
||||
php artisan migrate --force &&
|
||||
ln -sfn /home/webservice/api-stage/releases/${RELEASE_ID} /home/webservice/api-stage/current &&
|
||||
sudo systemctl reload php8.4-fpm &&
|
||||
cd /home/webservice/api-stage/releases &&
|
||||
ls -1dt */ | tail -n +4 | xargs rm -rf 2>/dev/null || true
|
||||
cd /home/webservice/api/releases && ls -1dt */ | tail -n +6 | xargs rm -rf 2>/dev/null || true
|
||||
'
|
||||
"""
|
||||
}
|
||||
@@ -420,17 +452,14 @@ pipeline {
|
||||
failure {
|
||||
echo "❌ api 배포 실패 (${env.BRANCH_NAME})"
|
||||
script {
|
||||
if (env.BRANCH_NAME in ['main', 'stage']) {
|
||||
def baseDir = env.BRANCH_NAME == 'main'
|
||||
? '/home/webservice/api'
|
||||
: '/home/webservice/api-stage'
|
||||
if (env.BRANCH_NAME == 'main') {
|
||||
sshagent(credentials: ['deploy-ssh-key']) {
|
||||
sh """
|
||||
ssh ${DEPLOY_USER}@211.117.60.189 '
|
||||
PREV=\$(ls -1dt ${baseDir}/releases/*/ | sed -n "2p" | xargs basename) &&
|
||||
[ -n "\$PREV" ] && ln -sfn ${baseDir}/releases/\$PREV ${baseDir}/current &&
|
||||
PREV=\$(ls -1dt /home/webservice/api/releases/*/ | sed -n "2p" | xargs basename 2>/dev/null) &&
|
||||
[ -n "\$PREV" ] && ln -sfn /home/webservice/api/releases/\$PREV /home/webservice/api/current &&
|
||||
sudo systemctl reload php8.4-fpm
|
||||
'
|
||||
' || true
|
||||
"""
|
||||
}
|
||||
}
|
||||
@@ -440,8 +469,15 @@ pipeline {
|
||||
}
|
||||
```
|
||||
|
||||
> **참고:** Laravel은 런타임 .env를 사용하므로 Stage/Production 별도 빌드가 필요 없다.
|
||||
> 각 환경의 shared/.env가 심링크로 연결된다.
|
||||
|
||||
### 수동 배포 절차 (API Production)
|
||||
|
||||
> **참고:** CI/CD Gitea는 `REQUIRE_SIGNIN_VIEW = true` 설정이므로,
|
||||
> 수동 git clone 시 `https://사용자:비밀번호@git.sam.it.kr/...` 형식 또는
|
||||
> CI/CD 서버에서 rsync로 전송하는 방식을 사용한다.
|
||||
|
||||
```bash
|
||||
ssh sam-prod
|
||||
|
||||
@@ -511,6 +547,82 @@ ls -1dt */ | tail -n +4 | xargs rm -rf 2>/dev/null || true
|
||||
|
||||
API와 동일한 releases/shared 구조. 차이점: npm build 추가, Queue Worker 재시작 불필요.
|
||||
|
||||
### Jenkinsfile (mng/Jenkinsfile)
|
||||
|
||||
```groovy
|
||||
pipeline {
|
||||
agent any
|
||||
|
||||
environment {
|
||||
DEPLOY_USER = 'hskwon'
|
||||
RELEASE_ID = new Date().format('yyyyMMdd_HHmmss')
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Checkout') {
|
||||
steps { checkout scm }
|
||||
}
|
||||
|
||||
// ── main → 운영서버 Production ──
|
||||
stage('Deploy Production') {
|
||||
when { branch 'main' }
|
||||
steps {
|
||||
sshagent(credentials: ['deploy-ssh-key']) {
|
||||
sh """
|
||||
ssh ${DEPLOY_USER}@211.117.60.189 'mkdir -p /home/webservice/mng/releases/${RELEASE_ID}'
|
||||
rsync -az --delete \
|
||||
--exclude='.git' --exclude='.env' \
|
||||
--exclude='storage/app' --exclude='storage/logs' \
|
||||
--exclude='storage/framework/sessions' --exclude='storage/framework/cache' \
|
||||
--exclude='node_modules' \
|
||||
. ${DEPLOY_USER}@211.117.60.189:/home/webservice/mng/releases/${RELEASE_ID}/
|
||||
ssh ${DEPLOY_USER}@211.117.60.189 '
|
||||
cd /home/webservice/mng/releases/${RELEASE_ID} &&
|
||||
ln -sfn /home/webservice/mng/shared/.env .env &&
|
||||
ln -sfn /home/webservice/mng/shared/storage/app storage/app &&
|
||||
composer install --no-dev --optimize-autoloader --no-interaction &&
|
||||
npm install --production=false &&
|
||||
npm run build &&
|
||||
php artisan config:cache &&
|
||||
php artisan route:cache &&
|
||||
php artisan view:cache &&
|
||||
php artisan migrate --force &&
|
||||
ln -sfn /home/webservice/mng/releases/${RELEASE_ID} /home/webservice/mng/current &&
|
||||
sudo systemctl reload php8.4-fpm &&
|
||||
cd /home/webservice/mng/releases && ls -1dt */ | tail -n +6 | xargs rm -rf 2>/dev/null || true
|
||||
'
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// develop → Jenkins 관여 안함 (기존 post-update hook 유지)
|
||||
}
|
||||
|
||||
post {
|
||||
success { echo "✅ mng 배포 완료 (${env.BRANCH_NAME})" }
|
||||
failure {
|
||||
echo "❌ mng 배포 실패 (${env.BRANCH_NAME})"
|
||||
script {
|
||||
if (env.BRANCH_NAME == 'main') {
|
||||
sshagent(credentials: ['deploy-ssh-key']) {
|
||||
sh """
|
||||
ssh ${DEPLOY_USER}@211.117.60.189 '
|
||||
PREV=\$(ls -1dt /home/webservice/mng/releases/*/ | sed -n "2p" | xargs basename) &&
|
||||
[ -n "\$PREV" ] && ln -sfn /home/webservice/mng/releases/\$PREV /home/webservice/mng/current &&
|
||||
sudo systemctl reload php8.4-fpm
|
||||
'
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 수동 배포
|
||||
|
||||
```bash
|
||||
ssh sam-prod
|
||||
|
||||
|
||||
Reference in New Issue
Block a user