[2주차] 팀원과 함께 고민한 기술 스택-2

코헤·2026년 1월 6일

cohiChat

목록 보기
3/10

커피챗 프로젝트 2주차 회고 (2/2) - 혼자 삽질한 기록

2주차 2부는 진짜... 길을 잃으며 나아가는 과정을 생중계한다고 보면 된다.


3. 내가 다 한 것들

모노레포 vs 멀티레포, 그리고 서버비의 공포

처음엔 단순했다. "CI/CD를 진행하려면 디렉토리 구조를 어떻게 해야 하지?"

고민했던 구조:

  • A안: 모노레포 (apps/backend/, apps/frontend/)
  • B안: 쉽게쉽게 가는 법 (레포를 두 개 만들고 FE, BE 따로 관리)

모노레포가 도전적이고 배울 게 많긴 한데... 팀원한테 제대로 설명할 수 있을까? (나약함 이슈)

그리고 더 큰 문제는...

현실:

  • QA 서버: FE 1대 + BE 1대
  • 운영 서버: FE 1대 + BE 1대
  • = 돈 졸라 나감 💸💸💸

💡 그래서 낸 아이디어

서버비를 줄이는 방법을 고민했다:

  1. QA 서버를 로컬에서 테스트하자

    • 기존: 로컬 작업 → QA 서버 배포해서 확인 → main 머지
    • 변경: 로컬 작업 → 로컬에서 확인 → main 머지
    • EC2 4대 → 2대로 절반으로 줄임
  2. QA 서버는 필요할 때만 켜자

    • 스팟 인스턴스 or 작업 시간만 ON
    • 24시간 돌릴 필요 없음

근데 솔직히...

팀원이랑 대화하면서 "로컬 QA로 괜찮을까...?" 고민했는데, 실무 경험 없어서 확신이 안 섰다. 그래도 우리 서비스 복잡도 생각하면 로컬로도 충분할 것 같았음.

📝 팀원과의 대화 요약 (길어서 접음)

타르트: 만약 로컬로 QA 할 경우 서버비 괜찮을 것 같아요?

: EC2 4대 vs EC2 2대... 후자가 압도적으로 싸겠지?

타르트: 확실히 줄긴 하겠네. 근데 QA를 로컬로 돌려도 무리 없을까요?

: 아니면 QA 서버는 필요할 때만 켜는 건 어떨까...?

타르트: 24시간 안 돌리고 필요할 때만 돌린다? 이게 더 맞는 방향 같긴 함.

: 엉엉ㅇ어어렁놔ㅓㅠㅠ러ㅣ머ㅗㅇ라ㅓ뉴퓨ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ (멘붕)

그래서 JVM 튜닝해서 GraalVM으로 돌리고, Docker 이미지 최소화해야겠네...

타르트: 들키지만 않으면 돈도 아끼고... 스크립트도 나중에 써도 되고...

: 솔깃하네요 (솔깃)


🐳 Docker 이미지 전달 방식 고민

3가지 옵션:

  • A안: GitHub Actions 빌드 → SSH로 EC2 전달
  • B안: GitHub Actions 빌드 → ECR → EC2 pull
  • C안: EC2에서 git clone → 내부 빌드

결국 B안(Docker Hub) 채택했다. ECR은 유료고, Docker Hub는 무료 플랜이 있어서.


###환경변수 관리

3가지 옵션:

  • A안: application.yml 하드코딩 (로컬 테스팅용)
  • B안: GitHub Secrets
  • C안: AWS Secrets Manager

B안(GitHub Secrets) 채택. AWS Secrets Manager는 유료고, GitHub Secrets면 충분함.


🏗️ Graviton(ARM64) vs x86

2가지 옵션:

  • A안: x86 (t3.micro)
  • B안: ARM64 (t4g.micro)

솔직히 이건 내가 잘 몰라서... 일단 x86으로 시작하기로 했다.


무중단 배포 고민

3가지 옵션:

  • A안: 그냥 재시작 (다운타임 5초)
  • B안: 컨테이너 블루-그린
  • C안: 노드 블루-그린

블루그린 해야지...

근데 솔직히 DAU 10명 서비스에 블루그린까지...? 오버엔지니어링 아닌가 싶긴 했음ㅋㅋ 그래서 이 내용은 추후 다시 고민하기로 했음


로깅은 어떻게?

3가지 옵션:

  • A안: docker logs
  • B안: Vector + Elasticsearch
  • C안: CloudWatch

제일 싼 게 EC2라는데... (후르츠츠츠) 일단 A안으로 시작하고 나중에 B안을 진행하기로 잡았다.
이 또한도 다음으로 미루는 것으로 했다.

📝 마이그레이션을 정당화하는 논리

팀원이랑 대화하다가 핵심 질문이 나왔다.

"자바로 마이그레이션하면 서버비만 더 나가는데, 왜 마이그레이션을 하는 거지?"

이게 진짜 치명타였다. 나도 순간 멘탈이 흔들렸음ㅋㅋㅋ

그래서 정리한 Python → Java 마이그레이션 이유:

타입 안정성

  • Python은 런타임 에러가 많음 → 배포 후 터짐
  • Java는 컴파일 타임에 잡아냄 → 운영 리스크 감소

성능 & 동시성

  • Python GIL 때문에 멀티스레딩 제약
  • Java는 JVM 기반 멀티스레드 최적화
  • 동일 로직 처리 시 Java가 Python보다 2~5배 빠름 (TechEmpower 벤치마크)

엔터프라이즈 생태계

  • Spring Boot는 보안, 트랜잭션, 모니터링 검증됨
  • Python Flask/FastAPI는 직접 구현해야 할 게 많음

팀 역량 & 채용

  • 내가 Java/Spring Boot 1년+ 실무 경험 있음
  • 나중에 백엔드 개발자 채용할 때도 Java 개발자 풀이 더 넓음

로깅 & 모니터링

  • Logback, Micrometer, APM 같은 도구들이 Java 생태계에서 더 성숙
  • Docker/K8s 환경에서 Java 애플리케이션 운영 노하우 많음

근데 난 왜 아직도 부족하다고 느껴질까 고민고민중


🚀 CI/CD 파이프라인 구축 (12/30)

드디어 실전. EC2 세팅부터 GitHub Actions까지 싹 다 했다.

1. EC2 인스턴스 생성

인스턴스 정보:

  • 퍼블릭 IP:
  • 리전: 서울 (ap-northeast-2)
  • 인스턴스 타입: t2.micro
  • OS: Ubuntu Server
  • 키 페어: cohi-chat-key.pem

보안 그룹 설정:
| 타입 | 포트 | 소스 | 설명 |
|------|------|------|------|
| SSH | 22 | 0.0.0.0/0 | SSH 접속용 |
| HTTP | 80 | 0.0.0.0/0 | HTTP 웹 접속용 |
| Custom TCP | 8080 | 0.0.0.0/0 | Spring Boot |


2. EC2에 Docker 설치

문제 발생: 로컬에서 SSH 접속이 안 됨ㅠㅠ

ssh -i "cohi-chat-key.pem" ubuntu@3.34.99.110
# 결과: Connection timed out

시도한 것들:

  • ✅ 보안 그룹 확인 → 포트 22 열려있음
  • ✅ 인스턴스 상태 확인 → 실행 중
  • ✅ .pem 파일 권한 설정
    icacls "cohi-chat-key.pem" /inheritance:r
    icacls "cohi-chat-key.pem" /grant:r "$($env:USERNAME):(R)"

원인: 로컬 네트워크/방화벽에서 SSH 포트 차단된 듯

  • 찾아보니 skt 와이파이를 쓸 경우 아웃바운드로 22번포트를 차단해놓아서 문제였다
    => 때문에 집에서 하니까 잘 되었다 ㅠㅠ!

해결: 집에서 진행...

  1. EC2 Console → 인스턴스 선택
  2. 연결(Connect) 버튼 클릭
  3. EC2 Instance Connect 탭 → 연결

브라우저에서 터미널이 뜸! 여기서 Docker 설치 진행.

# Docker 설치
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker ubuntu

# Docker Compose 설치
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

# 설치 확인
docker --version
docker-compose --version

✅ 설치 완료!


3. GitHub Secrets 설정

GitHub Actions가 자동 배포하려면 민감한 정보들이 필요하다.

설정한 Secrets (총 5개):
1. DOCKER_USERNAME: Docker Hub 사용자명
2. DOCKER_TOKEN: Docker Hub Access Token
3. EC2_HOST: 3.34.99.110
4. EC2_USER: ubuntu
5. EC2_SSH_KEY: .pem 파일 전체 내용

EC2_SSH_KEY 값 준비 (PowerShell):

Get-Content C:\Users\hyeonyeong\Desktop\cohi-chat-key.pem | Out-String

이거 복사해서 GitHub Secrets에 붙여넣기.


4. CI/CD 파이프라인 완성

QA 브랜치 Push 시:

QA 브랜치 Push
    ↓
[docker-build-push.yml 실행]
    → Gradle로 Spring Boot 빌드
    → Docker 이미지 생성
    → Docker Hub에 푸시
    ↓
[deploy.yml 실행]
    → EC2에 SSH 접속
    → Docker Hub에서 최신 이미지 Pull
    → docker-compose down (기존 컨테이너 중지)
    → docker-compose up -d (새 컨테이너 시작)
    → 헬스체크 확인
    ↓
배포 완료!

main 브랜치 Push 시:

  • CI만 돌림 (빌드 + 테스트)
  • 배포는 안 함 (나중에 추가 예정)

💡 배운 점

1. EC2 Instance Connect의 유용성

로컬 SSH가 안 될 때 브라우저 기반 터미널로 대체 가능. 일시적인 네트워크 문제 우회 가능.

2. 보안 그룹의 중요성

인바운드 규칙 제대로 안 설정하면 아무것도 작동 안 함. 필요한 포트: 22 (SSH), 80 (HTTP), 8080 (애플리케이션)

3. GitHub Secrets 활용

CI/CD에서 민감한 정보를 안전하게 관리. Docker Hub credentials, SSH keys 등을 코드에 노출하지 않음.

4. Multi-stage Docker Build

builder stage에서 빌드, runtime stage에서 실행. 최종 이미지 크기 최소화.

5. Docker Hub의 역할

GitHub Actions → Docker Hub → EC2 흐름. 어디서든 같은 이미지를 pull 가능.


🎯 다음주 할 것들

  • Account 쪽 개발 매니징하면서 팀원이 TDD를 어떻게 진행하는지 확인해보기
  • CI/CD 파이프라인 실제 배포 테스트
  • 헬스체크 엔드포인트 확인: http://3.34.99.110:8080/actuator/health

마무리

2주차는 진짜 정신없었다.

서버비 고민하면서 "왜 자바로 마이그레이션 했지?" 자기 회의도 들었고, EC2 SSH 접속 안 돼서 삽질도 했고... 그래도 결국 CI/CD 파이프라인까지 구축하는 데 성공했다.

현재 상태:
| 항목 | 상태 | 비고 |
|------|------|------|
| EC2 인스턴스 생성 | ✅ 완료 | IP: 3.34.99.110 |
| 보안 그룹 설정 | ✅ 완료 | 포트 22, 80, 8080 오픈 |
| Docker 설치 | ✅ 완료 | EC2 Instance Connect 사용 |
| GitHub Secrets | ✅ 완료 | 5개 모두 설정 |
| 로컬 SSH 접속 | ✅ 완료 | 네트워크 이슈 (우회 가능) |
| CI/CD 파이프라인 | ⏳ 대기 중 | 다음주 테스트 예정 |

준비 완료! 다음주에 워크플로우 실행만 하면 자동 배포가 시작된다. 🚀

길을 잃으며 나아가는 과정이 부끄럽긴 한데, 이게 진짜 개발 아닐까? ㅎㅎ

궁금한 거 있으면 댓글로 남겨주세요~ 👋

profile
하이하이

0개의 댓글