인프라 아키텍처¶
👋 이 문서는 d-edu 인프라의 "전체 지도"입니다. 처음 합류하셨다면 여기서 "어디서 뭐가 돌고, 코드가 어떻게 서버까지 가는지"를 한눈에 파악할 수 있습니다.
한 줄 요약 — 하이브리드 구성: - Dev 백엔드 = 🏠 온프레미스(우리 사무실 서버) ·
apidev.d-edu.site- Dev 프론트 = ▲ Vercel ·dev.d-edu.site- Prod(운영) = ☁️ AWS Lightsail ·d-edu.site/api.d-edu.site- 코드 = 📦 모노레포idealstudy/mvp-mono(백+프+wiki 한 트리)⚠️ 비밀번호·키·IP 같은 시크릿 값은 이 문서에 없습니다 — GitHub Secrets와
raw/(REDACTED)에만. 여긴 "구조"만.
0. 한눈에 (TL;DR)¶
| 구분 | Dev (개발) | Prod (운영) |
|---|---|---|
| 백엔드 | 🏠 온프레미스 서버 (Docker) | ☁️ AWS Lightsail |
| 프론트 | ▲ Vercel | ☁️ AWS Lightsail (nginx) |
| DB | 온프레 mysql_dev (MySQL 8.4) |
Lightsail MySQL |
| 백엔드 도메인 | apidev.d-edu.site |
api.d-edu.site |
| 프론트 도메인 | dev.d-edu.site |
d-edu.site |
| 배포 트리거 | develop 브랜치 머지 |
main 브랜치 머지 |
2026-05~06에 Dev를 AWS에서 온프레미스로 이전했습니다. 그 이유·과정은 ADR-0017, 옛 AWS Dev 구성은 아래 §7 이전 이력에 보존돼 있습니다.
1. 토폴로지 (그림)¶
flowchart TB
subgraph REPO["📦 idealstudy/mvp-mono (private 모노레포)"]
BE["mvp-back/ · Spring Boot"]
FE["mvp-front/ · Next.js"]
end
BE -- "develop 머지<br/>(back-deploy-onprem)" --> APP
BE -. "main 머지<br/>(back-deploy-aws)" .-> PROD
FE -- "develop 머지<br/>front-sync-mirror<br/>(subtree split→push)" --> TEP["the-edu-project<br/>(public 미러)"]
TEP -- "Vercel 자동 빌드" --> VER
subgraph ONP["🏠 온프레미스 서버 — cloudflared 터널 · docker net: theedu_backend"]
APP["the-edu-staging<br/>(Spring · GHCR 이미지)"]
DB[("mysql_dev")]
RD[("theedu_redis")]
APP --- DB
APP --- RD
end
VER["▲ Vercel · dev.d-edu.site"] -- "API 요청 (BFF 프록시)" --> APIDEV(["apidev.d-edu.site<br/>= Cloudflare 터널"])
APIDEV --> APP
APP -- "미디어 presigned URL" --> S3[("☁️ AWS S3 · theedu")]
PROD["☁️ AWS Lightsail · api.d-edu.site (운영)"]
읽는 법: 개발자는 mvp-mono에 PR → develop 머지. 그 순간 백엔드는 온프레 서버로, 프론트는 the-edu-project 미러를 거쳐 Vercel로 자동 배포됩니다. 사용자가 dev.d-edu.site에서 보는 화면(Vercel)은 API를 apidev.d-edu.site(온프레 백엔드)로 보냅니다. (운영은 main 머지 → AWS.)
2. 구성 자원¶
2-1. Dev — 온프레미스 (Docker)¶
사무실 서버 1대 위에 Docker 컨테이너로 구성. 외부 접속은 Cloudflare 터널로 뚫습니다(서버에 공인 IP/포트 개방 없이 안전하게).
| 컨테이너 / 자원 | 역할 | 비고 |
|---|---|---|
the-edu-staging |
백엔드 Spring 앱 | GHCR 이미지, staging 프로파일, 포트 8080 |
mysql_dev |
MySQL 8.4 (DB명 dedu) |
~/mysql_dev의 docker-compose, 데이터=도커 볼륨 |
theedu_redis |
Redis (세션·인증코드) | ~/redis_dev의 docker-compose |
docker network theedu_backend |
세 컨테이너 내부 통신망 | external 네트워크 (⚠️ §6 참고) |
| self-hosted GitHub Actions runner | 온프레 배포 실행기 | ~/actions-runner |
| cloudflared 터널 | 외부→서버 접속 통로 | apidev.d-edu.site, ssh.d-edu.site |
용어: cloudflared 터널 = 서버가 Cloudflare로 바깥 연결을 걸어두고, 외부 요청을 그 연결로 받아오는 방식. 방화벽에 포트를 안 열어도 돼 안전합니다.
2-2. Dev 프론트 — Vercel¶
- Vercel 프로젝트 "the-edu-front-dev"(Production 환경)가
dev.d-edu.site로 서비스. - Vercel이 보는 소스 =
idealstudy/the-edu-project(public). 모노레포가 이 레포로 동기화해주면 Vercel이 자동 빌드/배포.
2-3. Prod — AWS Lightsail (이전과 무관, 유지)¶
- Lightsail 인스턴스 + Lightsail/RDS MySQL. nginx + certbot(HTTPS).
api.d-edu.site/d-edu.site.
2-4. 공용 — AWS S3 theedu¶
- 미디어(과제·QnA·게시판 썸네일) 저장. Dev(온프레)도 운영도 이 S3를 씁니다 → presigned URL 발급에 AWS 키 필요. 삭제 금지.
3. 배포 파이프라인 (코드가 서버로 가는 길)¶
| 대상 | 워크플로 | 트리거 | 흐름 |
|---|---|---|---|
| Dev 백엔드 | back-deploy-onprem.yml |
develop 머지 + mvp-back/** 변경 |
self-hosted runner가 빌드 → GHCR push → 온프레서 docker run the-edu-staging → 헬스 게이트(응답 확인, 실패 시 롤백) |
| Prod 백엔드 | back-deploy-aws.yml (deploy-prod) |
main 머지 |
AWS Lightsail 배포 (ECR 경유) |
| Dev 프론트 | front-sync-mirror.yml |
develop 머지 + mvp-front/** 변경 |
git subtree split로 mvp-front/만 떼어내 → SSH(deploy key)로 the-edu-project에 force push → Vercel 자동 배포 |
용어: subtree split = 모노레포에서
mvp-front/폴더만 깨끗한 별도 히스토리로 뽑아내는 git 기능. 그걸 public 미러(the-edu-project)에 올려 Vercel이 빌드하게 합니다(private 모노레포를 Vercel에 직접 안 붙여도 됨).
4. 도메인 · 네트워크 (요청이 어디로 가나)¶
| 도메인 | 가리키는 곳 | 경유 |
|---|---|---|
dev.d-edu.site |
Dev 프론트 (Vercel) | — |
apidev.d-edu.site |
Dev 백엔드 (온프레) | Cloudflare 터널 → 온프레 서버 |
api.d-edu.site |
Prod 백엔드 | AWS |
d-edu.site |
Prod 프론트 | AWS |
- 쿠키/CORS: 프론트(
dev.d-edu.site) ↔ API(apidev.d-edu.site)가 형제 서브도메인이라, 로그인 쿠키 도메인은.d-edu.site(둘 다 커버) +SameSite=None; Secure. CORS 허용 origin에dev.d-edu.site포함. - 프론트는
dev.d-edu.site로 접속해야 로그인 쿠키가 붙습니다(raw*.vercel.app직접 접속 시 안 걸림).
5. 환경 · 프로파일 · 시크릿¶
- Spring 프로파일:
dev(구 AWS, 폐기 예정) ·staging(온프레 Dev) ·prod(AWS 운영). 온프레 백엔드는staging프로파일로 기동. - GitHub Environments:
dev/staging/prod별로 시크릿 분리. 온프레 배포는staging환경 시크릿(DB_URL=mysql_dev,REDIS_*,KAKAO/NAVER_REDIRECT_URI=apidev…등) + repo 공통 시크릿(AWS_*,KAKAO_CLIENT_*등) 사용. - 자세한 환경 매트릭스·변수명 → teams/engineering/infra/environments. 값은 Secrets/raw에만.
6. 알려진 리스크 · TODO¶
온프레 이전 과정에서 드러난, 앞으로 챙겨야 할 것들 (ADR-0017 §Consequences):
theedu_backend네트워크 단일 소유자 부재 — 앱은docker run, mysql/redis는 compose라 네트워크 주인이 없음. 재생성 시 컨테이너 간 통신이 끊긴 적 있음(장애 1회). → 최상위 compose로 일원화 권장.- 온프레 MySQL 자동 백업 없음 — 데이터가 도커 볼륨 1곳에만. → 정기
mysqldump+ off-box(S3) 백업 필요. - 모니터링·알림 부재 — apidev 다운 시 인지 불가. → Prometheus/Loki/Grafana 재구축 (teams/engineering/infra/observability).
- deploy 롤백 로직 — 인프라 문제 시 이전 이미지 롤백도 무의미. 헬스 실패 시 알림+중단이 나음.
- AWS
back-deploy-aws.yml의 deploy-dev job 잔존 — dev EC2 삭제로 develop 머지 시 실패. 비활성화 필요.
7. 이전 이력 — 구 AWS Dev (~2026-05, 보존)¶
📌 아래는 이전 전(AWS) Dev 구성입니다. 2026-05~06 온프레미스로 이전하며 EC2/RDS는 삭제(스냅샷
dev-onpremise-260531보관)했지만, 기록 보존을 위해 남깁니다. 의사결정 맥락은 ADR-0017.
| 항목 | 구 AWS Dev (삭제됨) |
|---|---|
| 컴퓨팅 | EC2 프리티어 인스턴스 |
| DB | RDS MySQL the_edu |
| 이미지 레지스트리 | ECR (theedu/back) |
| 백엔드 도메인 | api.dev.d-edu.site (nginx + certbot HTTPS) |
| 배포 | deploy.yml deploy-dev → SSH로 EC2 docker 교체 |
- React 빌드물을 nginx 정적 서빙, certbot(Let's Encrypt)으로 HTTPS — 이 방식은 운영(Lightsail)엔 그대로 유효.
- 데이터는 RDS
the_edu→ 온프레mysql_dev로mysqldump마이그레이션 완료(member 266·study_room 416).
8. 관련¶
- teams/engineering/infra/environments — Dev/Prod 환경 매트릭스 + 변수명
- teams/engineering/infra/observability — 모니터링·로깅
- teams/engineering/infra/db-ddl — DB 스키마 ↔ 도메인
- ADR-0017 — dev 온프레미스 이전 결정·교훈
- ADR-0003 — 대칭 모노레포 구조
- teams/engineering/guides/cicd, teams/engineering/guides/docker