SW-Hub 인프라 모노레포. 역할 분리로 운영한다.
- Terraform: 네트워크 / EC2 / RDS / S3 / Cloudflare DNS·Tunnel 등 인프라 프로비저닝
- Ansible: 생성된 서버의 OS·런타임 구성 관리 (Docker, zram, Redis, cloudflared, pgvector 등)
현재 dev 환경은 EC2 앱 서버 + RDS PostgreSQL + EC2 로컬 Redis + Cloudflare Tunnel 진입 구조다. EC2의 앱 포트는 직접 공개하지 않고, 공개 HTTPS 트래픽은 Cloudflare Tunnel을 통해 들어온다.
인프라 변경은 GitOps로 적용한다. terraform/** 를 수정해 PR을 올리면 CI가 자동으로 plan 을 돌려 PR 코멘트로 보여주고, dev 브랜치에 머지하면 수동 승인 게이트를 거쳐 apply 된다. 인증은 GitHub OIDC라 로컬에 Terraform/AWS 키를 깔지 않아도 된다.
설계 원칙·아키텍처 배경은 CLAUDE.md, CI/CD·인증 흐름 상세는 docs/cicd-and-auth.md 참고.
.
├── .github/workflows/
│ └── terraform.yml # GitOps 파이프라인: PR→plan, dev 머지→apply(승인 게이트)
├── terraform/
│ ├── environments/dev/ # dev 엔트리포인트
│ │ ├── backend.tf # S3 원격 state 백엔드 (락파일)
│ │ ├── *.tf # AWS/Cloudflare provider, vars, ansible 연동
│ └── modules/
│ ├── network/ # VPC, public/private subnet × 2, IGW, route table
│ ├── ec2/ # AMI, key pair (자동 생성), SG, 인스턴스, IMDSv2 강제
│ ├── rds/ # subnet group, SG (EC2 SG만 허용), PostgreSQL
│ └── s3/ # dev용 S3 bucket
├── ansible/
│ ├── ansible.cfg # inventory/roles 경로 등 — 이 디렉토리에서 실행
│ ├── inventories/dev/ # hosts.yml, secrets.yml은 terraform apply 시 자동 생성
│ ├── playbooks/site.yml
│ └── roles/ # common, ram_optimization, docker, redis, cloudflared, postgres
├── docs/ # architecture.md, cicd-and-auth.md
└── tools/
└── install-dependencies.sh # (로컬 운영 시) AWS CLI, Terraform, Ansible 일괄 설치
- AWS: VPC / EC2 app node / RDS PostgreSQL / S3
- Terraform state: S3 원격 백엔드
sw-hub-dev-tfstate-<account_id>(버전관리·암호화·퍼블릭 차단, S3 네이티브 락파일). 로컬 state 아님. - Redis: 비용 절감을 위해 ElastiCache 대신 EC2 내부 Docker Compose Redis 사용
- 기본 바인딩:
127.0.0.1:6379, 외부 공개 금지
- 기본 바인딩:
- Cloudflare: DNS record + Zero Trust Tunnel을 Terraform으로 관리
- cloudflared: Ansible role이 EC2에서 Docker Compose 서비스로 실행
인프라 변경은 로컬에서 apply 하지 않는다. GitHub에 올리면 CI가 OIDC로 AWS에 인증해 처리한다.
terraform/** 수정 → PR
→ GitHub Actions가 OIDC로 임시 AWS 자격증명 발급
→ terraform plan → 결과를 PR 코멘트로 게시
│
▼ (리뷰 후)
dev 브랜치 머지(push)
→ terraform apply 시도
→ GitHub Environment 'dev-apply' 수동 승인 게이트
→ 승인하면 apply 실행
- 인증: GitHub OIDC → IAM role
sw-hub-dev-gha-terraform(저장된 액세스 키 없음) - 트리거 경로:
terraform/**,.github/workflows/terraform.yml변경 시 - 승인 게이트:
dev-apply환경 (reviewer 승인 + dev 브랜치 제한) - 필요한 Repository Secrets:
CLOUDFLARE_API_TOKEN,TF_VAR_CLOUDFLARE_ACCOUNT_ID,TF_VAR_CLOUDFLARE_ZONE_NAME,TF_VAR_CLOUDFLARE_HOSTNAME ⚠️ PR에 머지 충돌이 있으면 GitHub가 merge ref를 못 만들어 워크플로가 트리거되지 않는다. 충돌부터 해소할 것.
일상 작업은 PR 올리고 → plan 확인 → 머지 → 승인 이게 전부다. 로컬에 도구를 깔 필요 없다. 흐름 전체와 자격증명 위치는 docs/cicd-and-auth.md.
대부분 GitOps로 충분하지만, 로컬 plan·state import·Ansible 실행에는 도구가 필요하다.
./tools/install-dependencies.sh # Ubuntu/WSL: AWS CLI v2, Terraform, Ansible(+collections)
# macOS: brew install awscli terraform ansible && ansible-galaxy collection install community.general community.postgresqlaws configure # state가 S3에 있으므로 해당 버킷 접근 권한 필요export CLOUDFLARE_API_TOKEN=...
export TF_VAR_cloudflare_account_id=...
export TF_VAR_cloudflare_zone_name=...
export TF_VAR_cloudflare_hostname=...cd terraform/environments/dev
terraform init # S3 원격 백엔드에 연결 (로컬 state 생성 X)
terraform plan- 기존(수동/외부 생성) 리소스를 state로 편입할 때는
terraform import. - Cloudflare 터널/DNS import 절차와 드리프트(
ignore_changes) 처리는 docs/cicd-and-auth.md 의 "드리프트 처리" 참고.
terraform output # EC2 IP, RDS endpoint 등
terraform output -raw rds_password # RDS 비밀번호
terraform output -raw rds_tunnel_command # 노트북→RDS SSH 포트포워딩 명령CI의
apply는 일회용 러너에서 돌기 때문에, SSH private key(sw-hub-dev.pem)·Ansible 인벤토리 같은 로컬 파일 산출물은 로컬에 남지 않는다. 로컬에서 필요하면 위terraform output으로 조회하거나, 로컬에서terraform apply(또는 refresh)를 한 번 돌려 파일을 생성한다.
Ansible은 아직 Terraform CI 파이프라인에 포함되지 않는다(로컬/수동 실행). ansible/ 디렉토리에서 실행해야 ansible.cfg 가 자동 인식된다.
cd ansible
ansible -m ping all
export MOA_PUBLIC_HOSTNAME=...
export CLOUDFLARED_TUNNEL_TOKEN=...
ansible-playbook playbooks/site.yml각 role 요약:
- common — 기본 패키지, timezone (Asia/Seoul)
- ram_optimization — zram-tools + vm.swappiness 튜닝 (작은 인스턴스용)
- docker — Docker CE + Compose plugin, 로그 회전 제한
- redis — EC2 내부 Redis Compose 서비스 (
127.0.0.1:6379) - cloudflared — Cloudflare Tunnel connector Compose 서비스
- postgres — RDS에 pgvector 확장 설치 (psql client +
community.postgresql)
필요한 role만 실행할 수도 있다.
ansible-playbook playbooks/site.yml --tags redis
ansible-playbook playbooks/site.yml --tags cloudflareddestroy 는 GitOps 파이프라인에 없다. 의도적으로 로컬에서만 수행한다(주의).
cd terraform/environments/dev
terraform destroyEC2/RDS/S3/네트워크/Cloudflare 리소스/SSH 키 파일/Ansible 자동 생성 파일이 제거된다.