📄 Frontend CI/CD 가이드
이 문서에서는 Frontend CI/CD 전체 과정과 발생한 문제들의 해결 방법을 다룹니다.
🧩 배경 및 필요성
CI/CD 도입 목적
지속적인 통합(Continuous Integration)과 지속적인 배포(Continuous Deployment)를 위해 Frontend 배포 과정에 CI/CD 파이프라인을 도입했습니다.
인프라 구성
- 배포 환경: 할당받은 EC2 서버에서 동작
- CI/CD 도구: Private GitLab과 Jenkins 사용
- 서버 구성: 별도의 Runner 서버 대신 배포 서버에 Jenkins를 설치하여 파이프라인 구축
- 웹 서버: OpenVidu v3에 내장된 Caddy 웹서버 활용
- Caddy 설정 파일을 수정하여 Reverse Proxy 기능 구현
배포 전략: CSR(Client-Side Rendering) 선택
- SSR 대신 CSR을 선택한 이유:
- SSR은 서버에서 렌더링하여 완성된 페이지를 제공하므로 CPU 사용량이 높음
- 현재 서버에 다양한 프로세스가 실행 중이므로 CPU 사용량 최소화 필요
- 정적 파일 배포 방식인 CSR로 서버 부하 감소
🛠️ 문제 해결 과정
1. Jenkins에서 Node.js 환경 구성
문제: Jenkins가 React 프로젝트를 빌드하기 위해 Node.js가 필요
해결 방법:
# EC2에 전역으로 사용 가능한 Node.js 설치
sudo yum install -y nodejs npm
# 또는 NodeSource repository 사용
curl -fsSL https://rpm.nodesource.com/setup_18.x | sudo bash -
sudo yum install -y nodejs
Jenkins의 역할:
- GitLab에서 소스코드 가져오기
- React 프로젝트 빌드 실행
- 빌드 결과물을 서빙 경로로 이동
2. Caddy Container 볼륨 마운트 문제
문제:
- CSR 배포를 위해 Caddy의
file_server로 정적 파일 제공 필요 - Docker로 실행되는 Caddy 컨테이너에서 빌드된 파일에 접근 불가
- Docker-compose.yml에서 프론트엔드 정적 파일 볼륨이 누락됨
해결 방법:
Docker-compose.yml 파일 수정하여 볼륨 마운트 추가
caddy:
image: docker.io/openvidu/openvidu-caddy:3.3.0
restart: unless-stopped
container_name: caddy
network_mode: host
command: run --config /config/caddy.yaml --adapter yaml
volumes:
- ./custom-layout:/var/www/custom-layout
- ./data/runtime/config/caddy:/config
- ./data/caddy_data:/data
- ./owncert:/owncert
- /var/www/html/build:/var/www/html/build # 프론트엔드 빌드 파일 볼륨 추가
depends_on:
openvidu-init:
condition: service_completed_successfully
logging:
options:
max-size: "${DOCKER_LOGS_MAX_SIZE:-200M}"
3. 빌드된 파일의 경로 참조 문제
문제:
- 브라우저에서 JS/CSS 파일을 찾지 못해 렌더링 실패
index.html에서 에셋 파일들이 절대 경로로 참조됨
문제가 된 경로:
<script type="module" crossorigin src="/assets/index-CFmP2VCM.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-CuDOF3jD.css">
해결 방법:
Vite 설정에서 base 경로를 상대 경로로 변경
// vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [react(), tailwindcss()],
base: './', // 상대 경로로 설정 (핵심!)
build: {
outDir: 'dist' // 또는 'build'
}
})
결과:
<!-- 수정된 경로 -->
<script type="module" crossorigin src="./assets/index-CFmP2VCM.js"></script>
<link rel="stylesheet" crossorigin href="./assets/index-CuDOF3jD.css">
📈 결과 및 성과
달성된 목표
- 자동화된 배포: Jenkins에서 "Build Now" 클릭만으로 자동 배포 가능
- 안정적인 서빙: Caddy를 통한 정적 파일 안정적 제공
- 효율적인 리소스 사용: CSR 방식으로 서버 CPU 사용량 최적화
CI/CD 파이프라인 흐름
- GitLab: 코드 커밋 및 푸시
- Jenkins:
- GitLab에서 소스코드 가져오기
npm install→npm run build실행- 빌드 결과물을
/var/www/html/build로 복사
- Caddy: 정적 파일을 브라우저에 서빙
향후 개선 사항
- GitLab Webhook을 통한 자동 트리거 설정
- 배포 롤백 기능 추가
- 빌드 상태 알림 시스템 구축