개요
프로젝트 당시 서비스의 기능 구현을 우선했기 때문에 인프라 작업은 정상적인 서비스 배포가 가능한 수준으로만 진행했다.
배포 작업은 크게 문제가 없지만, 최근 클라우드 서버를 NCloud에서 OCI로 이전하면서 배포 시간이 기하급수적으로 증가하면서, 배포 작업 최적화에 대한 필요가 대두되었다.
현재 상황
문제 인식
- NCloud에서 OCI로 클라우드 서버를 이전하면서 인스턴스 성능이 저하
- NCloud c2-g2-h50 : vCPU 2개, 메모리 4GB
- OCI VM.Standard.E2.1.Micro : vCPU 1/4개, 메모리 1GB
- 짤막 CS 지식
- 그 결과 배포 시간이 약 2분 30초에서 약 12분 50초(Docker 빌드 캐시 사용 시 약 7분 40초)로 증가



현재 배포 과정
- Github Actions 워크플로 동작
- 트리거
- push 이벤트(브랜치
main)
- 수동 실행(
workflow_dispatch)
- 실행 환경
- 레이블
[self-hosted, boost-was]가 붙은 Runner
- 주요 스텝
- Checkout
- [actions/checkout@v4]를 통해 레포지토리 소스 클론
- Build and Deploy
- 환경변수 설정 (
NODE_ENV=production, DB/토큰/AI API 관련)
docker-compose up -d --build 명령 실행→ Compose 파일(docker-compose.yml)을 기반으로 서비스별 이미지를 빌드하고, 컨테이너를 백그라운드에서 기동
- Clean up
- 사용되지 않는 dangling 이미지를
docker image prune -f로 제거
- Docker 빌드 및 배포
- frontend 컨테이너: 빌드(Stage 없이 바로 빌드 스크립트 실행)
- 빌드 컨텍스트: 모노레포 루트(
.)
- 볼륨:
./client/dist:/app/client/dist (빌드 산출물을 호스트에 동기화)
- 커맨드:
pnpm --filter client run build→ 클라이언트 애플리케이션을 빌드하고 dist 폴더에 결과물 생성
- backend 컨테이너: TypeScript 빌드 후 프로덕션 서버 실행
- 포트 매핑:
3000:3000
- 환경변수: MongoDB URI, JWT 시크릿, AI API 정보 등
- CMD:
pnpm --filter server run start:prod→ NestJS 프로덕션 서버 실행
- nginx 컨테이너: 빌드된 정적 파일 제공 및 리버스 프록시 역할
- 포트:
80, 443 오픈
- 볼륨
- 정적 파일:
./client/dist:/usr/share/nginx/html
- Let’s Encrypt 인증서 및 certbot 경로 마운트
depends_on: frontend, backend→ 정적 파일과 API 서버가 준비된 후 Nginx 기동
문제점
- 빌드를 한 인스턴스에서 모두 수행
- 도커 컨테이너는 백엔드와 NginX에서만 필요하고, 프론트엔드 컨테이너는 단순히 빌드파일만 생성하고 종료하기 때문에 서버 인스턴스에서는 프론트엔드 빌드파일만 받으면 된다
- 서버 인스턴스 성능이 낮기 때문에 도커 이미지를 다른 곳에서 빌드하고 서버 인스턴스에서 다운로드하는 방법도 있다
- 매 번 모든 이미지 빌드
- 프론트엔드 또는 백엔드 중 일부에만 변경사항이 생겨도 항상 모든 도커 이미지를 빌드한다
- NginX 이미지는 거의 변화가 없음에도 매 번 새로 빌드한다
- 무중단 배포를 도입하려면 NginX 이미지는 배포되는 중에도 계속 존재해야 한다
개선 내용 요약
- Frontend 이미지는 정적 산출물(dist)만 필요하므로 배포 인스턴스보다 성능이 높은 별도 Runner에서 빌드 → Artifact를 사용해 배포 인스턴스로 전달
- Backend 이미지는 self-hosted Runner에서 Docker 이미지로 빌드하며, 캐시를 사용해 빌드 시간 단축
- Nginx 이미지는 빌드 없이 공식 이미지를 재사용하고, dist 마운트만 수행