[CL] 1단계: Big Bang 방식 수작업 배포 설계 - 100-hours-a-week/6-nemo-wiki GitHub Wiki
1. 개요
이번 문서는 클라우드 설계 실습 과제의 일환으로, 서비스 초기 단계에서의 수작업 기반 Big Bang 배포를 직접 수행하고, 그 과정에서 배포 방식의 한계와 개선 필요성을 명확히 인식하는 것을 목표로 한다.
이 실습은 단순히 기술적인 구현을 넘어서, 실무 상황에서 어떤 배포 방식이 왜 선택되었는지를 이해하고, 그에 따라 발생할 수 있는 운영 및 확장 이슈를 체감하는 데 의의가 있다.
1.1. 실습 및 평가자 관점
- 원시적인 배포 방식인 빅뱅 배포를 직접 경험한다.
- 자동화나 분산 구조가 없는 상태에서 수작업 배포의 복잡함과 리스크를 실감하고,
- 이후 자동화 기반 배포(CI/CD 등) 설계로 나아가기 위한 기초 학습 단계로 활용한다.
1.2. 실무자 관점
- “왜 지금은 수작업 배포를 선택해야만 했는가?”
- “이 방식이 실제 서비스 운영에 어떤 영향을 주는가?”
- “서비스가 성장하고 복잡해질수록 어떤 문제가 생길 수 있는가?”
- 위 질문을 기반으로, 빅뱅 배포의 실질적 문제를 체험하고 주도적으로 개선 방향을 모색할 수 있도록 유도한다.
1.3. 과제 목표 및 구성
이번 과제는 다음 세 가지 핵심 작업으로 구성된다:
- 현행 배포 방식 분석
- 현재 우리 서비스가 채택하고 있는 배포 구조를 정의하고,
- 빅뱅 배포를 선택한 배경과 한계를 도출한다.
- 수작업 배포 프로세스 설계
- 실제 수작업 배포를 수행하기 위한 단계별 절차와 역할 분담 시나리오를 작성한다.
- 간단한 배포 스크립트와 수동 체크리스트를 포함하여, 반복 가능한 수작업 모델을 설계한다.
- 시스템 구성도 및 기술 명세 작성
- 현재 단일 서버 기반의 시스템 아키텍처를 시각화하고,
- 각 구성 요소의 역할과 주요 기술 스택을 명세한다.
1.4. 제출 항목
- 도입 배경 및 한계 분석 (현행 방식의 필요성과 한계에 대한 분석)
- 배포 절차 설명서 (수작업 배포 시나리오 및 절차, 체크리스트 포함)
- 추가 자료 (스크립트, 로그, 테스트 결과 등)
2. Big Bang 수작업 배포 도입 배경
2.1. 현재 상황
- Big Bang은 아직 서비스 초기 단계로, 최소 기능(MVP) 개발 및 검증에 집중하고 있음
- 빠른 기능 추가 및 테스트가 반복되는 짧은 개발 주기를 가지고 있으며, 아직까지는 프로덕션 수준의 복잡한 인프라가 요구되지 않음
- MVP 단계에서만 사용할 임시 인프라 구성 예정
2.2. 수작업 배포 방식 선택 이유
- 단일 서버 구조
- MVP를 목표로 개발하고 테스트하는 수준의 현재 서비스로는 하나의 EC2 인스턴스에서 구동 가능
- 현재 시점에서 별도의 오토스케일링, 로드밸런서, DB 클러스터 등은 필요하지 않을 뿐더러 오히려 과한 설정 때문에 복잡도가 올라갈 수 있음
- 비용 효율성 극대화
- 현재 사용 가능한 예산이 제한되어 있기 때문에 다른 클라우드 리소스를 도입하는 데 부담이 있음
- 외부 트래픽이 없기 때문에 EC2 하나로 충분히 커버 가능한 범위 내에서 작업하여 리소스 사용 비용을 절감하여 추후 확장성 있는 인프라에 더 큰 투자가 가능함
- 향후 자동화 도입을 위한 이해도 확보
- 수작업 배포를 통해 배포 프로세스를 단계별로 직접 경험하며 학습
- 향후 CI/CD 도입 시 각 단계의 필요성과 동작 원리에 대하 더 명확하고 깊은 이해가 가능함
- 복잡도 최소화로 오류 지점 제거
- 다양한 클라우드 리소스가 추가되면 초기에는 오히려 디버깅 포인트가 많아져 개발 속도가 느려질 수 있음
- 현재는 오류 발생 지점을 최소화하여 빠르게 대응할 수 있도록 하는 것이 필요
2.3. 한계점 및 리스크 분석
- 반복적인 수작업으로 인한 오류 가능성
scp
,ssh
,java -jar
,uvicorn
등 명령어를 직접 입력하기 때문에 오류 발생 가능성이 높음- 변경 사항 반영 시마다 전체 배포 프로세스를 반복해야 하기 때문에 생산성 저하
- 단일 서버 장애 시 전체 서비스 중단
- 모든 서비스(Spring, MySQL, Redis, AI, Next.js)가 하나의 VM에 올라간 구조이므로 단일 실패 지점 (Single Point of Failure)이 존재함
- 환경 불일치로 인한 디버깅 어려움
- 로컬 환경과 서버 환경이 다르면 의존성 충돌 및 실행 오류 발생 가능성이 높음
- 실제 FastAPI 배포 중 uvicorn 버전 충돌로 인해 실행 불가 → 가상환경 도입으로 해결
- 운영 안정성 부족
- 서버가 재시작되면 서비스가 중단되며 재가동 시 다시 수동으로 실행 명령어 입력이 필요함
- 확장성과 유지보수의 어려움
- 서비스가 성장함에 따라 트래픽이 증가할 경우, Scale-out이 불가능하고 부하 분산 불가 등의 구조적 한계가 명확하게 존재함
3. 배포 절차 설명서
3.1. 배포 개요
-
배포 환경: GCP Compute Engine
항목 설정 값 선택 이유 머신 타입 e2-medium
(2 vCPU, 4GB RAM)Spring + Next.js + MySQL + Redis + AI 서버가 동시에 실행 가능한 최소한의 사양 부트 디스크 Ubuntu 20.04 LTS
, 30GBLTS 안정성 + MySQL 데이터/로그 저장 여유 확보 영역 asia-northeast3-a (서울)
지연시간 최소화 및 한국 사용자 테스트 최적화 외부 IP 자동 할당 외부에서 SSH 및 서비스 접속을 위한 필수 조건 방화벽 수동 설정 필요( 3000
,5000
,8080
,3306
,6379
,22
)각 서비스 포트 접근 허용을 위해 필수 -
배포 방식: 수작업 기반 Big Bang 방식
-
대상 컴포넌트
- Spring Boot (8080)
- Next.js (3000)
- FastAPI (5000)
- MySQL (3306)
- Redis (6379)
-
배포 주체: 개발자가 직접 배포 담당
-
배포 목적: MVP 수준의 초기 서비스 구동
3.2. 배포 시나리오
- 배포 시점: 기능 개발 완료 후 로컬에서 빌드 및 테스트 검증이 끝난 시점
- 진행 인원: 각 파트 대표 개발자 1명이 담당 서비스 배포 수행 (FE, BE, AI)
- 배포 흐름
- 로컬에서 빌드 또는 코드 준비
- scp를 통한 서버로 코드 전송
- ssh 접속 후 실행/설치
- 로그 확인 및 테스트
3.3. 서비스별 수작업 배포 절차
다음은 실제 GCP Compute Engine에 수작업으로 모든 서비스를 배포한 상세 과정이다. 수작업 배포의 복잡성과 리스크를 그대로 드러내기 위해 명령어 기준으로 기술하였다.
-
MySQL (3306)
# 1. 시스템 업데이트 및 MySQL 설치 sudo apt update sudo apt install mysql-server -y # 2. MySQL 서비스 시작 및 부팅 시 자동 실행 설정 sudo systemctl start mysql sudo systemctl enable mysql # 3. MySQL 접속 후 DB, 사용자 생성 sudo mysql <<EOF CREATE DATABASE guestbook; CREATE USER 'guest'@'%' IDENTIFIED BY 'guest1234'; GRANT ALL PRIVILEGES ON guestbook.* TO 'guest'@'%'; FLUSH PRIVILEGES; EXIT; EOF # 4. 외부 접속 허용 (bind-address 수정) sudo sed -i 's/^bind-address.*/bind-address = 0.0.0.0/' /etc/mysql/mysql.conf.d/mysqld.cnf # 5. MySQL 재시작 및 확인 sudo systemctl restart mysql sudo systemctl status mysql
-
Redis (6379)
# 1. 시스템 업데이트 및 Redis 설치 sudo apt update sudo apt install redis-server -y # 2. redis.conf 설정 변경 (외부 접속 허용) sudo sed -i 's/^bind .*/bind 0.0.0.0/' /etc/redis/redis.conf sudo sed -i 's/^protected-mode yes/protected-mode no/' /etc/redis/redis.conf # 3. Redis 서비스 재시작 및 확인 sudo systemctl restart redis-server sudo systemctl status redis
-
Spring Boot (8080)
# 1. 로컬에서 JAR 빌드 ./gradlew clean build -x test # 2. 로컬에서 SSH 키 생성 후 GCP Compute Engine에 키 등록 ssh-keygen -t rsa -f ~/.ssh/gcp-key -C glenn -b 2048 # 3. 로컬에서 Compute Engine으로 JAR 업로드 scp -i ~/.ssh/gcp-key ~/final-prep/backend/build/libs/backend-0.0.1-SNAPSHOT.jar [email protected]:/home/glenn/ # 4. Compute Engine에 SSH로 접속 ssh -i ~/.ssh/gcp-key [email protected] # 5. Java 설치 sudo apt update sudo apt install openjdk-21-jdk -y java -version # 5. Compute Engine에서 JAR 실행 (Spring Boot 서버 구동) java -jar backend-0.0.1-SNAPSHOT.jar # 6. DB Connection failed -> why -> Compute Engine 외부 IP 주소가 임시라 바뀜 # 다시 빌드 -> 업로드 -> 전송 -> 실행 과정
-
FastAPI (5000)
# 1. 코드 업로드 scp -i ~/.ssh/gcp-key main.py [email protected]:/home/glenn/sample-app/ai scp -i ~/.ssh/gcp-key requirements.txt [email protected]:/home/glenn/sample-app/ai # 2. 서버 접속 ssh -i ~/.ssh/gcp-key [email protected] cd /home/glenn/sample-app/ai # 3. (처음엔 가상환경 없이 설치 시도) which pip || sudo apt install python3-pip -y pip install -r requirements.txt # 4. 실행 시도 uvicorn main:app --host 0.0.0.0 --port 5000 # ❌ 여기서 문제 발생: # RuntimeError or pkg_resources.VersionConflict: # uvicorn 0.33.0 (apt로 설치됨) vs 필요한 버전 (>= 0.34) 충돌 발생 # → 문제 원인: 시스템 uvicorn이 너무 낮은 버전 (apt 설치된 기본 패키지) # 5. 해결: 가상환경 구성으로 환경 분리 sudo apt install python3.8-venv -y python3 -m venv venv source venv/bin/activate # 6. pip 최신화 및 재설치 pip install --upgrade pip pip install --force-reinstall 'uvicorn[standard]' pip install fastapi pydantic # 7. 버전 확인 (이제 충돌 없음) python3 --version # 3.8.10 uvicorn --version # 0.34.1 (정상) # 8. 실행 성공 uvicorn main:app --host 0.0.0.0 --port 5000 # 9. 외부 테스트 curl -X POST http://34.64.203.5:5000/analyze \ -H "Content-Type: application/json" \ -d '{"content": "오늘 너무 좋아!"}'
-
Next.js (3000)
# 1. 프로젝트 생성 npx create-next-app@latest frontend npm install npm run dev # 2. 기본 앱 빌드 npm run build # 3. GCP 서버에 프로젝트 업로드 cd .. scp -i ~/.ssh/gcp-key -r frontend [email protected]:/home/glenn/sample-app/ # 4. Node.js 설치 curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash - sudo apt install -y nodejs node -v # ex: v18.x.x npm -v # ex: 9.x.x # 5. Next.js 앱 실행 npm run build npm start
3.4. 배포 체크리스트
-
공통 준비사항
- SSH 연결:
ssh -i ~/.ssh/gcp-key glenn@<external-ip>
로 접속
- SSH 연결:
-
Backend
-
로컬 빌드 & 서버 전송
# 1. 로컬에서 JAR 빌드 ./gradlew clean build -x test # 2. JAR 파일 서버로 전송 scp -i $KEY_PATH ./build/libs/backend-0.0.1-SNAPSHOT.jar glenn@$HOST:/home/glenn/
-
서버 접속 & 실행
ssh -i $KEY_PATH glenn@$HOST cd /home/glenn # 3. JAR 실행 (백그라운드) nohup java -jar backend-0.0.1-SNAPSHOT.jar > spring.log 2>&1 &
-
상태 확인
tail -n 30 spring.log # 실행 로그 확인 curl http://localhost:8080 # 응답 확인 sudo systemctl status mysql # MySQL 작동 여부 sudo systemctl status redis-server # Redis 작동 여부
-
-
Frontend
-
서버로 전체 폴더 전송
cd .. scp -i $KEY_PATH -r frontend glenn@$HOST:/home/glenn/sample-app/
-
서버 접속 & 실행
ssh -i $KEY_PATH glenn@$HOST cd /home/glenn/sample-app/frontend # 실행 npm run build nohup npm start > frontend.log 2>&1 &
-
상태 확인
tail -n 30 frontend.log curl http://localhost:3000
-
-
AI
-
로컬 코드 전송
scp -i $KEY_PATH main.py glenn@$HOST:/home/glenn/sample-app/ai scp -i $KEY_PATH requirements.txt glenn@$HOST:/home/glenn/sample-app/ai
-
서버 접속 & 실행
ssh -i $KEY_PATH glenn@$HOST cd /home/glenn/sample-app/ai # 가상환경 활성화 source venv/bin/activate # 실행 nohup uvicorn main:app --host 0.0.0.0 --port 5000 > ai.log 2>&1 &
-
상태 확인
tail -n 30 ai.log # 테스트 요청 curl -X POST http://$HOST:5000/analyze \ -H "Content-Type: application/json" \ -d '{"content": "오늘 너무 좋아!"}'
-
3.5. 예상 소요 시간 및 다운타임
구간 | 소요 시간 (예상) | 다운타임 |
---|---|---|
프론트엔드 | 약 3~4분 | 없음 |
백엔드 | 약 7~9분 | 약 3분 (JAR 재시작 시간) |
AI 서버 | 약 6~8분 | 약 2~3분 (FastAPI 재기동) |
전체 합계 | 약 20~25분 | 전체 중단은 없음(단일 컴포넌트 수준 일시 정지) |
4. 시스템 아키텍처
4.1 구성요소
컴포넌트 | 포트 | 설명 |
---|---|---|
Next.js (Frontend) | 3000 |
사용자 인터페이스 제공. 사용자 요청을 Backend로 전달함 |
Spring Boot (Backend) | 8080 |
핵심 비즈니스 로직 처리. DB/캐시 접근 및 AI 호출 수행 |
MySQL | 3306 |
서비스 데이터 저장소 |
Redis | 6379 |
세션 저장소 혹은 캐시로 사용 |
FastAPI (AI) | 5000 |
AI 기능 처리 (Backend로부터 호출됨) |
4.2 특징
항목 | 긍정적 측면 | 한계 및 문제점 |
---|---|---|
구성 방식 | 단일 서버, 단순 구조, 저비용 | SPOF, 전체 의존, 장애 리스크 |
배포 방식 | 직접 경험, 프로세스 학습 | 무중단 불가, 서비스 중단, 휴먼에러 |
확장성 | 초기 대응 OK | 수평 확장 불가, 병목 위험 |
자동화 수준 | 수동 학습 기회 | 자동화 미흡, 롤백 불가, 유지보수 부담 |
보안 구성 | 빠른 설정, 진입장벽 낮음 | 포트 노출, 인증 부재, 보안 취약 |
모니터링/로깅 | 개발 집중 | 로그 미흡, 장애 진단 어려움 |
운영 안정성 | 빠른 대응 가능 | 운영자 의존, 실수 위험 |
5. 개선 방향 제안
5.1. 개선 필요성
현재 수작업 기반의 빅뱅 배포 방식은 다음과 같은 구조적 한계를 가지고 있다:
- 로컬에서 빌드 후 서버로
scp
로 수동 전송 - 각 서비스 실행은 SSH 접속 후 직접 명령어 입력
- AI 서버는 수동으로 가상환경(
venv
) 생성 및 패키지 설치 - 환경마다 Python, Node, uvicorn 등 버전 불일치로 인한 충돌 발생
- Git과 연동되지 않아 버전 관리 및 재배포 어려움
- 배포 자동화 및 무중단 배포가 불가능하며, 모든 과정이 사람 손에 의존
이러한 배포 구조는 MVP 수준에서는 동작하지만,
서비스가 성장하고 복잡해질수록 속도, 신뢰성, 확장성 모두에서 치명적인 문제가 발생한다.
5.2. 경험 기반 개선 필요 요소
실제 겪은 문제 | 개선 방향 |
---|---|
빌드 후 scp 전송, ssh 접속, 수동 실행 반복 | ➝ GitHub + CI/CD를 통한 자동화 |
AI 서버 패키지 설치 중 uvicorn 버전 충돌 | ➝ Docker 이미지 내 환경 고정으로 해결 |
터미널 닫히면 서비스 종료 | ➝ Docker + restart 정책 또는 systemd로 지속 실행 |
git과 무관한 수동 배포 → 롤백 불가 | ➝ Git 기반 히스토리 관리 + 자동 배포 연결 필요 |
5.3. 다음 단계 예고
다음 버전(v2)부터는 다음과 같은 방향으로 구조를 개선할 예정이다:
- Git 연동 기반 배포 전환
- 커밋 단위로 빌드/배포 기록 추적 가능
- 특정 시점으로 롤백 가능
- 협업자 간 코드/배포 기준 통일 가능
- CI/CD 자동화 파이프라인 구축
- GitHub에 Push하면:
- 자동 빌드 → 테스트 → Docker 이미지 생성 → 서버 배포까지 자동화
- 배포 시간 단축, 실수 방지, 무중단 배포 구조로 진화 가능
- Docker 기반 환경 구성
- 각 서비스(Frontend, Backend, AI)를 컨테이너화
- 서버 간 환경 불일치 제거, 버전 고정, 실행 표준화