AWS 아키텍처
⚠︎ 지난 판 — 2026-07-26. 현재 판은 여기다. 이 문서는 그때의 기록이고 고치지 않는다.
갱신일 2026-07-26 · 기준:
infra@0c6f7b0(main) ·server@bf192cc·ai@60ee59a·web@87e0834Terraform이 만드는 것과 사람이 손으로 하는 것을 갈라 적는다. 앞 절만 코드로 확인된 것이고, 뒤 절은 저장소에 없다.
확인한 사실 — Terraform이 만드는 것
heymoa-infra의 terraform/environments/prod가 소유하는 범위다. 계정 110080810555, 리전 ap-northeast-2.
| 리소스 | 값 | 근거 |
|---|---|---|
| VPC · subnet | 10.30.0.0/16, public 1 + private data 2(AZ 2개). NAT Gateway 없음 | network.tf |
| EC2 | t4g.small ARM64 1대, EIP 고정, lifecycle.ignore_changes = [ami, user_data] | application.tf |
| 인바운드 | 80·443만. SSH 22도 8080도 열지 않는다 — 접속은 SSM | 같은 파일 |
user_data | SSM Agent 설치·기동뿐. Docker·Git·Nginx·Certbot은 접속 후 사람이 설치 | 같은 파일 |
| RDS | heymoa-prod-postgres, db_name = "heymoa", 마스터 유저 heymoa_admin, manage_master_user_password = true | database.tf |
| RDS 접근 | EC2 보안그룹에서 오는 5432만. IP CIDR 허용 없음 | 같은 파일 |
| IAM | EC2 Role에 AmazonSSMManagedInstanceCore + 그 Secret 하나의 GetSecretValue만 | application.tf · database.tf |
| state | S3 heymoa-prod-terraform-state-110080810555, use_lockfile = true, bootstrap이 prevent_destroy | versions.tf · bootstrap/main.tf |
쓰지 않는 것도 코드가 말한다 — ALB·ACM·NAT Gateway·SSH key·애플리케이션용 S3가 없고, module/tfvars 분리도 하지 않았다.
RDS는 삭제가 쉽게 열려 있다. deletion_protection = false, skip_final_snapshot = true다. infra README가 "실제 사용자 데이터가 생기면 둘 다 반대로 바꾼다"고 조건을 적어 뒀다.
설계 전제
- 한 대를 손으로 굴린다. EC2 안의 Git·Docker·Nginx·Certbot은 Terraform 밖이고,
ignore_changes가 AMI 갱신으로 인스턴스가 교체되는 것을 막는다. CI/CD와 immutable deployment를 도입할 때 이 예외를 걷는다. - DB 비밀번호를 코드가 갖지 않는다. RDS가 Secret을 만들고 회전하며, EC2는 IAM Role로 읽는다. 회전 뒤에도
.env에 복사해 쓴다면 값 갱신과 컨테이너 재기동이 필요하다. - 공개 진입은 Cloudflare A 레코드 → EIP → EC2의 Nginx 하나뿐이다. 앱 컨테이너는
127.0.0.1에만 바인딩한다(server 포트 8080·actuator 8081이 그렇게 설정돼 있다). - MVP 비용 상한을 의도적으로 낮게 잡았다. infra README 기준 월 약 $62이고, Docker 빌드 중 메모리가 부족할 때만
t4g.medium으로 올린다.
미확인 — 저장소에 없는 배포 경로
추정을 사실로 적지 않는다. 아래는 코드로 확인되지 않았고, 값이 확인되면 위 절로 올린다.
| 무엇 | 지금 아는 것 | 확인 못 한 것 | 어디를 봐야 하나 |
|---|---|---|---|
| heymoa-ai가 어디에 뜨나 | ai 레포에는 로컬 docker-compose.yml만 있고 운영 배포는 "heymoa-infra 소유"라고만 적혀 있다. Terraform에는 ai를 가리키는 리소스가 없다 | 같은 EC2에 함께 올리는지, 인스턴스 수, 이미지가 ARM64로 빌드되는지 | EC2의 compose 파일 |
heymoa_ai database | RDS가 만드는 database는 heymoa 하나다 | heymoa_ai database를 누가 언제 만드는지, CREATE EXTENSION vector를 어디서 도는지 | RDS 안의 실제 database 목록 |
| checkpoint 테이블 생성 시점 | ai가 기동 때 saver.setup()을 부르고, 실패하면 채팅만 죽는다 | 배포 스텝으로 분리했는지 | 배포 절차 문서 |
| 마이그레이션 직렬화 | Alembic이 앱과 분리된 일회성 스텝인 것까지 | 인스턴스가 여럿일 때 동시 실행을 막는 장치 | 배포 스크립트 |
| heymoa-web 호스팅 | @vercel/analytics·@vercel/speed-insights 의존과 heymoa.app 도메인 | vercel.json도 .github/workflows/도 없다 — 빌드·배포 주체와 환경변수 주입 지점 | Vercel 프로젝트 설정 |
| 관측 스택 | infra 레포에 Prometheus·Loki·Tempo·Grafana compose가 있으나 커밋 메시지가 "이전 서버의 모니터링 템플릿(legacy)"이다 | 지금 운영에 붙어 있는지 | EC2 실행 중인 컨테이너 |
| Langfuse | ai는 키가 있을 때만 트레이싱을 붙인다 | 운영에서 키를 넣었는지 (넣으면 전사 원문이 외부로 나간다) | .env.prod |