- Phase 0: INDEX.md 전면 재작성, CLAUDE.md→INDEX.md 통합 삭제 - Phase 0: front/→guides/ 이관(5개 파일), changes/ D7 포맷 통일(3개) - Phase 0: guides/ai-config-설정.md→ai-config-settings.md D3 통일 - Phase 2: architecture/+specs/→system/ 이관(6개 이동, 4개 폐기) - Phase 2: 13개 파일 경로 참조 수정 (specs/→system/, architecture/→system/) - Phase 4: 7개 파일 11개 교차참조 깨진 링크 수정 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
7.9 KiB
7.9 KiB
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 추가
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 + 방화벽
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 패키지 설치
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 초기 설정
sudo cat /var/lib/jenkins/secrets/initialAdminPassword # 초기 비밀번호
http://114.203.209.83:8080접속 → 비밀번호 입력- Install suggested plugins 선택 → 설치 대기 (3~5분)
- 관리자 계정 생성 (Username:
admin) - 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 → 운영 서버)
# 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 |
# SSH 비밀키 확인 (Jenkins에 붙여넣기)
sudo cat /var/lib/jenkins/.ssh/id_ed25519
❌ Jenkinsfile에 비밀번호/토큰/키를 하드코딩 금지
✅ 모든 비밀 정보는 Jenkins Credential에 등록 후 credentials('ID')로 참조
6. Gitea Webhook 연동
6.1 Jenkins Pipeline Job 생성
- New Item → 이름:
sam-api-deploy→ Pipeline 선택 - Build Triggers: Generic Webhook Trigger 체크, Token:
sam-api - 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
- URL:
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 기본 구조
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.md4.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)
sudo su - jenkins && ssh deploy@운영서버IP # 수동 테스트
# 운영 서버에서 authorized_keys 등록 확인
chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys
8.3 메모리 부족
# Jenkins 힙 메모리 제한: /etc/default/jenkins에 JAVA_ARGS="-Xmx512m" 추가
sudo systemctl restart jenkins
# Job 설정 → Discard old builds → 최대 빌드 수: 10
8.4 Webhook 미동작
# 수동 트리거 테스트
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
# Jenkinsfile에서 메모리 증가
sh 'export NODE_OPTIONS="--max-old-space-size=2048" && npm run build'
# 실패 시 로컬(WSL)에서 react/deploy.sh 사용
경고: 개발 서버에서 React 빌드 실패 시 로컬에서
deploy.sh를 사용한다.
관련 문서
- 운영 환경 배포 계획서 - Jenkinsfile 상세, 브랜치 전략
- .env 동기화 절차 - 환경 변수 분리
- Docker 환경 스펙 - 현재 개발 환경
최종 업데이트: 2026-02-22