Skip to main content

AI 코드 리뷰어 개발 및 배포 여정 [1]

작성일: 2025.12.09


Intro

1. 프로젝트 개요: LLM과 배포 여정의 교차로에서

💡 프로젝트 탄생 배경 및 동기

이번 프로젝트는 단순히 코드를 짜는 것을 넘어, 제가 경험했던 기술적 아쉬움과 새로운 기술에 대한 호기심이 결합된 결과물입니다.

  1. LLM 실전 경험 : 최근 가장 핫한 기술인 LLM을 가지고 '진짜 작동하는' 토이 프로젝트를 만들어보고 싶었습니다.

  2. 미완의 서비스에 대한 아쉬움 : 과거 GitHub API를 써서 포트폴리오 서비스를 만들다가 중단했던 아쉬움이 남아 이번에 다시 MVP라도 GitHub API를 활용해 그 경험을 완성하고자 했습니다.

  3. 클라우드 배포 최적화 학습 : 단순 코딩을 넘어, Vercel, NCP, SSL/ALB 구성을 결합해서 배포 환경을 구축하는 것을 핵심 목표로 삼았습니다.

🤖 Why Gemini? (Ollama -> Gemini)

Ollama Self-Hosted ModelGemini API Model


과거에 저는 한 기술 블로그에서 Ollama를 접하고 흥미를 느꼈었고 언젠가 꼭 사용해보겠다고 생각했었습니다.

그래서 이번에 저비용으로 경량 LLM 모델을 직접 호스팅 해보자는 생각에 Ollama 기반의 온프레미스 구성을 첫 번째 선택지로 고려했습니다.

항목Ollama (Self-Hosted)Gemini 2.5 Flash API
Resource 의존도매우 높음 (GPU 필수)낮음 (API 서버에서 처리)
운영 비용VM(GPU) 시간당 과금 (매우 비쌈)토큰 사용량 기반 과금 (저렴하고 명확함)
속도느림 (VM 성능에 의존)빠름 (API 응답 속도 우수)

하지만 테스트 결과, Ollama는 GPU 의존도가 너무 높고 무거워서 제가 비용상 사용할 NCP VM 인스턴스(저코스트)에서 안정적인 서비스 속도를 보장할 수 없었습니다. GPU 옵션을 추가하면 VM 비용이 시간당 몇 천 원으로 급증하는 문제도 있었습니다.

결국, 속도가 빠르고 GPU 의존도가 없으며, 비용 구조가 토큰 기반으로 명확한 Gemini 2.5 Flash API를 사용하는 것이 최적의 선택이라 판단하고 변경했습니다.

☁️ Why NCP?

NCP

지금까지의 배포 경험은 AWS에만 집중되어 있었기 때문에 이번 기회에 타 클라우드 환경을 경험해보고 싶다는 생각이 컸습니다.

  1. AWS 프리티어 만료 : 기존에 사용하던 AWS 프리티어가 만료되면서 적지 않을 서버 유지 비용에 대한 부담이 생겼습니다.

  2. NCP 크레딧 활용 : 마침 NCP에서 신규 가입 시 제공하는 10만 원 상당의 크레딧이 있었고 유효기간 내에 새로운 클라우드 환경을 경험하기 위해서 선택했습니다.

💻 주요 기술 스택

이 프로젝트는 아래 기술 스택을 기반으로 성능과 개발 효율성을 모두 고려하여 구축되었습니다.

구분기술 스택설명
FrontendReact, Vite빠른 UI 및 GitHub OAuth 2.0 흐름 제어
BackendJDK 21, Spring Boot 4.0, Spring SecurityGitHub OAuth 처리, Gemini API 호출 및 비즈니스 로직
AI ServiceGoogle Gemini 2.5 Flash API코드 리뷰, 채팅 및 분석 리포트 생성
Hosting 비용VM 시간당 약 330원, ALB 월 약 2.5만원, Domain 550원비용을 최소화하며 인프라를 구축

🏗️ 아키텍쳐

NCP

🚀 왜 Vercel과 NCP를 함께 썼을까?

저의 백엔드 서버가 NCP에 있음에도 프론트엔드를 Vercel에 배포한데는 몇가지 이유가 있습니다. 바로 개발 경험과 사용자 경험 극대화입니다.

NCP
  1. 극대화된 개발 생산성: Vercel은 GitHub와 연동만 해두면 코드를 푸시할 때마다 자동 빌드 및 배포를 해줍니다(자동사냥 CI/CD).
  2. 글로벌 CDN 성능: Vercel의 글로벌 CDN 덕분에 UI 파일 로딩 속도가 빠릅니다.
  3. 자동 SSL: Vercel이 프론트엔드 도메인에 대해 자동으로 HTTPS 인증서를 발급해 주어 보안의 기본을 잡아주었습니다.

2. 실습 배포 과정: NCP와 도메인 연결하기

2.1 NCP 네트워크 환경 구성 (VPC, Subnet, ACG)

NCP에 서버를 띄우기 전 VPC 기반의 네트워크 환경을 먼저 구축했습니다. VPC와 Subnet 생성 자체는 과금이 되지 않기 때문에 부담 없이 설정했습니다.

  1. VPC 생성: git-code-reviewer-vpc 이름으로 가상 네트워크를 정의했습니다.
  2. Subnet 생성: 당연히 외부 통신이 가능한 Public Subnet을 선택했고 public-subnet-1을 생성했습니다.
  3. ACG 설정: code-reviewer-acg를 생성하여 SSH(22) 및 SpringBoot 포트(8080) 접근을 위한 인바운드 규칙을 마련했습니다.

2.2 VM 인스턴스 스펙 및 공인 IP 할당

VPC와 Subnet을 기반으로 Spring Boot 서버를 호스팅할 VM을 생성했습니다.

NCP
항목상세 정보비고
서버 스펙s2-g3a (vCPU 2EA, Memory 8GB)Spring Boot 구동에 안정적인 사양 (시간당 330원)
OSUbuntu 22.04 base익숙한 리눅스 환경 선택
내부 IP10.0.1.6Subnet에 의해 자동 할당되는 사설 주소
공인 IP175.xx.xx.xxVM 생성 시 할당하여 ALB 설정 전까지 직접 접속 및 테스트용으로 사용했습니다.

2.3 백엔드 빌드 및 실행 (NCP)

NCP 인스턴스에 Spring Boot JAR 파일을 올리고 실행하는 과정입니다. 보안을 위해 .env.properties 파일을 생성해 API 키와 프롬프트 같은 민감 정보를 분리했습니다.

  1. 빌드: 로컬에서 Gradle로 JAR 파일을 만듭니다.
    ./gradlew clean build -x test
  2. 파일 전송: scp 명령어로 JAR 파일과 .env.properties를 NCP 서버의 /root 디렉터리로 전송합니다.
    scp git-code-reviewer-0.0.1-SNAPSHOT.jar root@[서버 공인 IP]:/root/
  3. 애플리케이션 실행: .env.properties 파일을 명시적으로 로드하면서 nohup으로 백그라운드 실행합니다.
    # NCP 서버 접속 후 실행:
    nohup java -jar git-code-reviewer-0.0.1-SNAPSHOT.jar --spring.config.location=file:./.env.properties > nohup.out 2>&1 &

2.4 SSL 주입: Mixed Content 해결 여정

Vercel(HTTPS)에서 NCP(HTTP 8080)로 API를 호출하자마자 당연히 Mixed Content Error가 발생했고 저는 필수로 HTTPS 환경을 구축했고 ALB를 생성했습니다.

  1. 도메인 구매: 도메인 비용도 최소로 하기 위하여 이쁘진 않지만 가비아에서 code-reviewer.store 도메인을 구매했습니다 (단돈 550원).

  2. SSL 인증서 발급: NCP Certificate Manager에서 SSL 인증서 발급을 요청하고 확인 후 가비아 DNS 설정에 CNAME 레코드를 입력하여 소유권을 검증했습니다.

  3. Application Load Balancer (ALB) 설정:

    • 리스너 설정: 외부의 HTTPS 443 요청을 받도록 설정하고, SSL 인증서를 연결했습니다.
    • 타겟 그룹 생성: Spring Boot 서버의 내부 IP(10.0.1.6)와 HTTP 8080 포트를 연결하는 타겟 그룹을 생성했습니다.
  4. DNS A 레코드 최종 설정:

    • ALB가 할당된 공인 IP를 확인했습니다.
    • 가비아 DNS로 돌아가, api.code-reviewer.store 도메인의 A 레코드 값을 이 ALB의 공인 IP로 변경했습니다.
NCP

2.5 프론트엔드 수정 및 최종 배포

  1. Frontend API URL 수정: Dashboard.js 파일에서 API 호출 주소를 새로운 HTTPS 도메인으로 변경했습니다.

    // 변경 전: '[http://175.45.204.50:8080/api](http://175.45.204.50:8080/api)'
    // 변경 후: '[https://api.code-reviewer.store/api](https://api.code-reviewer.store/api)'
    const api = axios.create({ baseURL: '[https://api.code-reviewer.store/api](https://api.code-reviewer.store/api)', ... });
  2. 물론 기존 localhost로 되어있던 Github Callback URL도 맞춰서 다시 수정해줬습니다!

NCP

  1. Vercel 배포: 코드를 푸시하여 Vercel을 재배포하는 것으로 마침내 HTTPS 통신 환경이 완성되었습니다.

2.5 NCP 인프라 구축 핵심 과정 요약

1. VPC & Subnet 생성

  • 주요 작업 내용: git-code-reviewer-vpcpublic-subnet-1을 생성합니다.
  • 목적: 외부 인터넷과 격리된 가상 네트워크 공간을 정의하고, 서버를 배치할 구체적인 IP 대역을 마련하는 기초 공사 단계입니다.

2. Server (VM) 생성

  • 주요 작업 내용: my-server-reviewer (Ubuntu 22.04, s2-g3a) 인스턴스를 생성합니다.
  • 목적: Spring Boot 애플리케이션을 호스팅할 컴퓨팅 자원을 확보합니다.

3. 초기 접속 경로 확보: Public IP 할당

  • 주요 작업 내용: VM에 공인 IP(175.45.204.50)를 할당합니다.
  • 목적: ALB 설정 전, SSH 접속을 하거나 애플리케이션 테스트를 진행하기 위한 임시 경로를 확보합니다.

4. 방화벽 설정: ACG & UFW 구성

  • 주요 작업 내용: NCP ACG와 서버 내부 UFW에 8080 포트 인바운드 허용 규칙을 설정합니다.
  • 목적: 서버로 들어오는 트래픽에 대한 방화벽을 설정하여 보안을 강화합니다.

5. Certificate Manager

  • 주요 작업 내용: 도메인(code-reviewer.store)을 등록하여 SSL 인증서를 발급받습니다.
  • 목적: HTTPS 접속을 위한 보안 인증서를 확보하여, Mixed Content 에러를 해결할 준비를 합니다.

6. Application Load Balancer 생성

  • 주요 작업 내용: ALB 인스턴스를 생성하고 공인 IP를 할당합니다.
  • 목적: 서버 부하를 분산하고, 가장 중요하게는 SSL/HTTPS 종료를 담당하는 트래픽 관리 계층을 구축합니다.

7. 최종 라우팅 정의: ALB Listener & Target Group 연결

  • 주요 작업 내용: Listener(443/HTTPS)를 Target Group(8080/HTTP)과 연결합니다.
  • 목적: 외부의 HTTPS 요청을 ALB에서 받아 암호 해제 후, 내부 서버의 HTTP로 안전하게 중계하도록 라우팅을 최종 설정합니다.

3. 트러블슈팅

해결

문제 상황해결책교훈
Mixed Content Error도메인 구매 후 NCP ALB에 SSL 인증서를 설정하고, API 호출 주소를 https://[도메인]으로 변경.돈이 들더라도 SSL Termination은 로드 밸런서에게 맡기는 것이 가장 안정적인 실무 공식입니다.
GitHub Callback URL 오류GitHub OAuth App 설정을 최종 주소인 https://api.code-reviewer.store/callback 형태로 업데이트하여 보안 표준을 준수했습니다.OAuth 표준에서는 인증 과정에 IP 주소나 HTTP를 사용하지 않습니다.
Vercel "Not Found"프로젝트 루트에 vercel.json 파일을 생성하여 /auth/callback 같은 클라이언트 라우팅 경로를 index.html로 리다이렉트하는 설정을 추가.React Router 같은 SPA를 정적 호스팅 플랫폼에 배포할 때는 라우팅 폴백 설정이 필수입니다.

임시 방편 및 리팩토링 필요 항목

이 항목은 임시 조치이며, 추후 반드시 보안 표준에 맞게 수정해야 합니다.

문제점일시적 해결책실무적 개선 방향 (필수 리팩토링)
HTTP/8080 포트 공개NCP ACG에서 TCP 8080 포트를 0.0.0.0/0 (전체 외부 접근)에 대해 인바운드 허용.ALB만 허용: ACG 규칙을 수정하여 8080 포트는 ALB의 Private IP 대역에서만 접근 가능하도록 제한해야 서버로의 직접 접근을 막아 보안성을 높입니다.

4. 회고 및 다음 단계

Spring Boot 코드를 짜는 시간보다(어차피 Open API 사용이 대부분이었기에...) NCP 콘솔에서 서버 올리고 ACG와 DNS 레코드를 확인하는 시간이 훨씬 길었던 여정이었지만 꽤 재밌었습니다.

동시에 몇가지 배운것도 많은데

  • SSL Termination의 필요성: Vercel에서 HTTP 백엔드를 호출할 수 없다는 문제 하나가 ALB 도입이라는 월 2.5만 원짜리 결정으로 이어지는 과정을 보면서, 서비스의 안정성과 보안은 곧 비용으로 직결된다는 현실을 배웠습니다.

  • 클라우드 플랫폼의 복잡성: AWS와 달리 NCP의 VPC, Subnet, ALB를 처음부터 설계하고 연결하는 과정은 복잡했지만, 덕분에 클라우드 네트워크에 대한 이해도가 한 단계 깊어졌습니다.

다음 단계에서는 현재 휘발되는 AI 리뷰 결과를 저장하고 관리하기 위해 DB를 도입하여 서비스를 더욱 고도화하고 기능도 몇가지 더 추가할 계획입니다! 계속 확인해주세요 🤗