docs: [guides] Jenkins 셋업 가이드 작성

- Jenkins 이해하기 (용어, CI/CD 개념)
- 사전 준비 (Swap, Java, 방화벽)
- 설치 및 초기 설정
- 필수 플러그인 설치
- Credential 설정 (SSH, Gitea, Slack)
- Gitea Webhook 연동
- Jenkinsfile 작성 가이드
- 트러블슈팅 & FAQ
This commit is contained in:
김보곤
2026-02-22 20:51:33 +09:00
parent c726e0852e
commit 86ea901de0
2 changed files with 278 additions and 0 deletions

View File

@@ -20,6 +20,7 @@
| **게시판** | `specs/board-system-spec.md` | 게시판 시스템 설계 |
| **단가관리** | `rules/pricing-policy.md` | 원가/판매가 계산, 리비전 관리 |
| **운영 배포** | `plans/production-deployment-plan.md` | 운영 환경 배포 계획 (CI/CD, 서버 아키텍처) |
| **서버 동작 원리** | `guides/server-how-it-works.md` | 요청 흐름, 배포 원리 이해 |
| **과금정책 (고객용)** | `rules/customer-pricing.md` | 고객 안내용 서비스 요금표 |
| **과금정책 (파트너)** | `rules/partner-commission.md` | 영업파트너 수당 체계 및 정산 |
| **과금정책 (내부용)** | `rules/billing-policy.md` | 내부용 원가/마진/코드참조 (CONFIDENTIAL) |
@@ -102,6 +103,8 @@ docs/
| [item-management-migration.md](guides/item-management-migration.md) | Item 시스템 전환 가이드 | 마이그레이션 작업 전 |
| [project-launch-roadmap.md](guides/project-launch-roadmap.md) | 런칭 준비 현황 | 런칭 관련 작업 시 |
| [production-env-sync.md](guides/production-env-sync.md) | 운영 전환 시 .env 동기화 절차 | 테스트→운영 전환 시 |
| [server-how-it-works.md](guides/server-how-it-works.md) | 서버 동작 원리 초보자 가이드 | 신규 합류 시 |
| [jenkins-setup-guide.md](guides/jenkins-setup-guide.md) | Jenkins CI/CD 셋업 가이드 | Jenkins 설치/설정 시 |
### quickstart/ - 빠른 시작
> 핵심 규칙 요약, 자주 쓰는 명령어
@@ -148,6 +151,7 @@ docs/
| [boards/mng-implementation.md](features/boards/mng-implementation.md) | MNG 게시판 구현 상세 |
| [hr/hr-api-analysis.md](features/hr/hr-api-analysis.md) | HR API 분석 (근태/직원/부서) |
| [quotes/README.md](features/quotes/README.md) | 견적 시스템 분석 (BOM 계산, 10단계 로직) |
| [academy/fire-shutter-image-prompts.md](features/academy/fire-shutter-image-prompts.md) | 방화셔터 백과사전 이미지 생성 프롬프트 (Gemini용) |
### projects/ - 프로젝트별 문서

View File

@@ -0,0 +1,274 @@
# Jenkins CI/CD 셋업 가이드
> **작성일**: 2026-02-22
> **상태**: 설계 확정
> **대상**: SAM 프로젝트 개발팀장
---
## 1. Jenkins 이해하기
### 1.1 Jenkins란
Jenkins는 오픈소스 자동화 서버다. 코드를 Push하면 자동으로 빌드, 테스트, 배포를 수행한다.
### 1.2 현재 수동 vs 자동화 비교
```
현재: 개발자 → git push → SSH 접속 → git pull → composer install → 재시작 (수동, 5~10분)
목표: 개발자 → git push → Jenkins 자동 감지 → 빌드/테스트/배포 (자동, Slack 알림)
```
### 1.3 핵심 용어
| 용어 | 설명 |
|------|------|
| **Job** | 하나의 작업 단위 (예: `sam-api-deploy`) |
| **Pipeline** | Stage를 순서대로 실행하는 흐름 |
| **Stage / Step** | Pipeline의 단계 / 단계 내 개별 명령 |
| **Credential** | Jenkins에 저장하는 비밀 정보 (SSH 키, 토큰) |
| **Webhook** | Gitea가 Push 이벤트를 Jenkins에 알려주는 HTTP 호출 |
---
## 2. 사전 준비
| 항목 | 값 |
|------|------|
| IP | `114.203.209.83` |
| CPU/RAM | 2코어 / 3.8GB |
| Gitea | `http://114.203.209.83:3000` |
> **경고: RAM이 부족하므로 Swap 추가가 필수다.**
### 2.1 Swap 4GB 추가
```bash
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
free -h # 확인
```
### 2.2 Java 17 + 방화벽
```bash
sudo apt update && sudo apt install -y openjdk-17-jdk
java -version # 17.x.x 확인
sudo ufw allow 8080/tcp # Jenkins 웹 UI 포트
```
---
## 3. Jenkins 설치
### 3.1 패키지 설치
```bash
curl -fsSL https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key | sudo tee \
/usr/share/keyrings/jenkins-keyring.asc > /dev/null
echo "deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc] \
https://pkg.jenkins.io/debian-stable binary/" | sudo tee \
/etc/apt/sources.list.d/jenkins.list > /dev/null
sudo apt update && sudo apt install -y jenkins
sudo systemctl start jenkins && sudo systemctl enable jenkins
```
### 3.2 초기 설정
```bash
sudo cat /var/lib/jenkins/secrets/initialAdminPassword # 초기 비밀번호
```
1. `http://114.203.209.83:8080` 접속 → 비밀번호 입력
2. **Install suggested plugins** 선택 → 설치 대기 (3~5분)
3. 관리자 계정 생성 (Username: `admin`)
4. Jenkins URL: `http://114.203.209.83:8080/`**Save and Finish**
---
## 4. 필수 플러그인 설치
**Jenkins 관리 → Plugins → Available plugins** 에서 설치한다.
| 플러그인 | 역할 | 필수 |
|---------|------|------|
| **Git plugin** | 소스 코드 체크아웃 | 🔴 |
| **Pipeline** | Jenkinsfile 지원 | 🔴 |
| **SSH Agent** | SSH 키로 운영 서버 배포 | 🔴 |
| **Generic Webhook Trigger** | Gitea Push 이벤트 수신 | 🔴 |
| **Slack Notification** | 배포 결과 Slack 알림 | 🟡 |
| **NodeJS** | React 빌드용 Node.js | 🟡 |
> **참고**: Git plugin, Pipeline은 suggested plugins에 포함되어 이미 설치되었을 수 있다.
NodeJS 설정: **Jenkins 관리 → Tools → NodeJS installations → Add NodeJS** → Name: `NodeJS-20`, Version: `20.x`
---
## 5. Credential 설정
### 5.1 SSH 키 생성 (Jenkins → 운영 서버)
```bash
# Jenkins 서버에서 실행
sudo su - jenkins
ssh-keygen -t ed25519 -C "jenkins@sam" -f ~/.ssh/id_ed25519 -N ""
cat ~/.ssh/id_ed25519.pub # 이 값을 운영 서버에 등록
exit
# 운영 서버에서 실행 (공개키 등록)
echo "ssh-ed25519 AAAA... jenkins@sam" >> /home/deploy/.ssh/authorized_keys
```
### 5.2 Jenkins Credential 등록
**Jenkins 관리 → Credentials → (global) → Add Credentials**
| Credential | Kind | ID | 내용 |
|-----------|------|-----|------|
| SSH 키 | SSH Username with private key | `prod-server-ssh` | `~jenkins/.ssh/id_ed25519` 비밀키 |
| Gitea 토큰 | Username with password | `gitea-token` | Gitea 사용자명 + API 토큰 |
| Slack URL | Secret text | `slack-webhook` | Slack Incoming Webhook URL |
```bash
# SSH 비밀키 확인 (Jenkins에 붙여넣기)
sudo cat /var/lib/jenkins/.ssh/id_ed25519
```
```
❌ Jenkinsfile에 비밀번호/토큰/키를 하드코딩 금지
✅ 모든 비밀 정보는 Jenkins Credential에 등록 후 credentials('ID')로 참조
```
---
## 6. Gitea Webhook 연동
### 6.1 Jenkins Pipeline Job 생성
1. **New Item** → 이름: `sam-api-deploy`**Pipeline** 선택
2. **Build Triggers**: Generic Webhook Trigger 체크, Token: `sam-api`
3. **Pipeline**: Pipeline script from SCM → Git
- URL: `http://114.203.209.83:3000/SamProject/sam-api.git`
- Credentials: `gitea-token`
- Branch: `*/main`
- Script Path: `Jenkinsfile`
### 6.2 전체 Job 목록
| Job 이름 | 저장소 | 브랜치 | Token |
|---------|--------|--------|-------|
| `sam-api-deploy` | `sam-api.git` | `*/main` | `sam-api` |
| `sam-mng-deploy` | `sam-manage.git` | `*/master` | `sam-mng` |
| `sam-react-deploy` | `sam-react-prod.git` | `*/master` | `sam-react` |
| `sam-sales-deploy` | `sam-sales.git` | `*/main` | `sam-sales` |
### 6.3 Gitea Webhook 설정
각 저장소: **Settings → Webhooks → Add Webhook → Gitea**
| 항목 | 값 |
|------|------|
| Target URL | `http://114.203.209.83:8080/generic-webhook-trigger/invoke?token=sam-api` |
| Content Type | `application/json` |
| Trigger On | **Push Events** |
| Branch filter | `main` |
**Test Delivery** → 응답 200이면 성공
---
## 7. Jenkinsfile 작성 가이드
### 7.1 기본 구조
```groovy
pipeline {
agent any
environment { KEY = 'value' }
stages {
stage('단계명') {
steps { sh 'command' }
}
}
post {
success { slackSend channel: '#sam-deploy', message: "성공" }
failure { slackSend channel: '#sam-alerts', message: "실패" }
}
}
```
### 7.2 SAM 저장소별 Jenkinsfile
> 상세 코드는 `plans/production-deployment-plan.md` 4.4절 참조
| 저장소 | Stage 흐름 | 특이사항 |
|--------|-----------|---------|
| **sam-api** | Checkout → Lint → Test → Deploy | `migrate --force` 포함 |
| **sam-manage** | Checkout → Lint → Build Assets → Deploy | 마이그레이션 없음 |
| **sam-react-prod** | Checkout → Install → Lint → Build → Package → Deploy | `tar.gz`로 전송 |
| **sam-sales** | Deploy | 간소화 (git pull + composer) |
### 7.3 배치 방법
각 저장소 **루트**에 `Jenkinsfile` 생성 → `git add Jenkinsfile && git commit -m "chore: Jenkinsfile 추가"` → push
---
## 8. 트러블슈팅
### 8.1 빌드 실패
Jenkins 대시보드 → Job → 빌드 번호 → **Console Output** 에서 에러 로그 확인
### 8.2 SSH 권한 오류 (`Permission denied`)
```bash
sudo su - jenkins && ssh deploy@운영서버IP # 수동 테스트
# 운영 서버에서 authorized_keys 등록 확인
chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys
```
### 8.3 메모리 부족
```bash
# Jenkins 힙 메모리 제한: /etc/default/jenkins에 JAVA_ARGS="-Xmx512m" 추가
sudo systemctl restart jenkins
# Job 설정 → Discard old builds → 최대 빌드 수: 10
```
### 8.4 Webhook 미동작
```bash
# 수동 트리거 테스트
curl -X POST "http://114.203.209.83:8080/generic-webhook-trigger/invoke?token=sam-api"
# Gitea: Webhooks → Recent Deliveries → 응답 코드 확인 (200=정상, 403=Token 불일치)
```
### 8.5 React 빌드 OOM
```bash
# Jenkinsfile에서 메모리 증가
sh 'export NODE_OPTIONS="--max-old-space-size=2048" && npm run build'
# 실패 시 로컬(WSL)에서 react/deploy.sh 사용
```
> **경고: 개발 서버에서 React 빌드 실패 시 로컬에서 `deploy.sh`를 사용한다.**
---
## 관련 문서
- [운영 환경 배포 계획서](../plans/production-deployment-plan.md) - Jenkinsfile 상세, 브랜치 전략
- [.env 동기화 절차](production-env-sync.md) - 환경 변수 분리
- [Docker 환경 스펙](../specs/docker-setup.md) - 현재 개발 환경
---
**최종 업데이트**: 2026-02-22