From 86ea901de09a60fefda2494fd079ac862f930850 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=B3=B4=EA=B3=A4?= Date: Sun, 22 Feb 2026 20:51:33 +0900 Subject: [PATCH] =?UTF-8?q?docs:=20[guides]=20Jenkins=20=EC=85=8B=EC=97=85?= =?UTF-8?q?=20=EA=B0=80=EC=9D=B4=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Jenkins 이해하기 (용어, CI/CD 개념) - 사전 준비 (Swap, Java, 방화벽) - 설치 및 초기 설정 - 필수 플러그인 설치 - Credential 설정 (SSH, Gitea, Slack) - Gitea Webhook 연동 - Jenkinsfile 작성 가이드 - 트러블슈팅 & FAQ --- INDEX.md | 4 + guides/jenkins-setup-guide.md | 274 ++++++++++++++++++++++++++++++++++ 2 files changed, 278 insertions(+) create mode 100644 guides/jenkins-setup-guide.md diff --git a/INDEX.md b/INDEX.md index a3d9121..384016e 100644 --- a/INDEX.md +++ b/INDEX.md @@ -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/ - 프로젝트별 문서 diff --git a/guides/jenkins-setup-guide.md b/guides/jenkins-setup-guide.md new file mode 100644 index 0000000..d40ac35 --- /dev/null +++ b/guides/jenkins-setup-guide.md @@ -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