[FE] 기술 요구사항 2 ‐ 프론트엔드 CI CD 파이프라인 및 인프라 아키텍처 가이드 - woowacourse-teams/2026-gachi-gacha GitHub Wiki

[가치가챠] 프론트엔드 CI/CD 및 인프라 아키텍처 가이드

  • 본 문서는 가치가챠 프로젝트의 프론트엔드 애플리케이션 배포 과정을 팀원에게 공유하고, 인프라 IP 변경이나 구조 수정 시 대응할 수 있도록 작성한 문서입니다.

1. 아키텍처 개요 및 목표

프론트엔드 인프라를 구축하며 다음 핵심 문제들을 생각했습니다.

개발 / 운영 배포 환경의 물리적 분리

검증되지 않은 기능이 사용자에게 노출되는 것을 막기 위해 서버(EC2) 4대(FE-DEV, FE-PROD, BE-DEV, BE-PROD) 체제로 환경을 분리했습니다.

Webpack 환경 설정을 분리하여, DEV 환경에서는 디버깅과 임시 UI 확인이 가능하게 구성했습니다.

배포 자동화 (CI/CD) 및 최신 화면 즉시 반영

GitHub Actions 기반의 자동 배포를 구축했습니다.

Webpack의 contenthash를 활용한 Cache Busting을 적용하여, 배포 즉시 브라우저 캐시를 무시하고 최신 버전이 사용자 화면에 반영되도록 설정했습니다.

2. 전체 배포 아키텍처 (Self-hosted Runner 방식)

보안상 S3와 CloudFront IAM 역할 생성이나 키 생성은 어려워 AWS IAM Access Key 없이 구동되는 Self-hosted Runner 구조를 채택했습니다. GitHub가 우리 EC2로 들어오는 것이 아니라, 우리 EC2 내부의 Runner가 깃허브로 나가서 코드를 가져와 배포하는 구조입니다.

흐름도 요약: PR 및 Merge -> GitHub에서 프로덕션 빌드 -> EC2 내부의 Runner가 파일 다운로드 -> 심볼릭 링크(current) 스위칭으로 무중단 배포 -> Nginx가 서빙

3. 서버 접속 가이드 (.pem 키 파일 관리)

인프라 설정을 수정하려면 EC2 서버에 접속해야 합니다. 처음 세팅하는 팀원도 아래 순서대로 진행하면 서버에 안전하게 접속할 수 있습니다.

Step 1. 안전 금고 폴더 만들고 키 파일 보관하기

발급받은 .pem 키 파일을 안전한 곳(~/.ssh/)으로 옮기고 권한을 설정합니다.

# 1. 안전 금고 폴더 만들기
mkdir -p ~/.ssh

# 2. 다운로드 받은 키 파일을 이동시키기 (키 파일이 있는 경로에서 실행)
mv key-gachi-gacha-front-dev.pem ~/.ssh/
mv key-gachi-gacha-front-prod.pem ~/.ssh/

# 3. 소유자만 읽을 수 있도록 파일 권한 잠그기
chmod 400 ~/.ssh/key-gachi-gacha-front-dev.pem
chmod 400 ~/.ssh/key-gachi-gacha-front-prod.pem

Step 2. 서버 접속 명령어 (SSH)

터미널 왼쪽 프롬프트가 ubuntu@... 로 바뀌면 접속 성공 (최초 접속 시 나오는 메시지에는 yes를 입력)

프론트엔드 DEV 서버 접속:

Bash
ssh -i ~/.ssh/key-gachi-gacha-front-dev.pem [email protected]

프론트엔드 PROD 서버 접속:

Bash
ssh -i ~/.ssh/key-gachi-gacha-front-prod.pem [email protected]

4. 백엔드 IP 변경 시 Nginx 설정 수정 방법

프론트엔드 Nginx는 화면 렌더링뿐만 아니라, CORS 에러와 Mixed Content(HTTPS/HTTP 통신) 차단 문제를 피하기 위해 백엔드로 /api 요청을 토스하는 리버스 프록시(Reverse Proxy) 역할을 합니다. 백엔드 서버의 프라이빗 IP가 변경되었을 경우, 아래 순서대로 프론트 EC2의 Nginx 설정을 수정해야 합니다.

Step 1. DEV 서버 Nginx 설정 파일 열기

DEV 서버에 접속한 상태에서 아래 명령어를 쳐서 설정 파일을 엽니다.

Bash
sudo nano /etc/nginx/sites-available/gachi-gacha-frontend
(참고: PROD 서버의 경우 sudo nano /etc/nginx/sites-available/gachi-gacha-frontend-prod 입력)

Step 2. proxy_pass 아이피 주소 변경

location /api/ { ... } 블록 안의 proxy_pass 주소를 변경된 백엔드 서버의 프라이빗 IP(현재 BE-DEV: 10.0.0.184)로 수정합니다.

Nginx
    location /api/ {
        # 백엔드 서버 Private IP로 토스 (CORS 해결)
        proxy_pass http://10.0.0.184:8080; 

        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    # SPA 새로고침 404 에러 방지 규칙
    location / {
        try_files $uri $uri/ /index.html;
    }

수정이 끝났으면 Ctrl + O -> Enter -> Ctrl + X 를 차례로 눌러 저장하고 빠져나옵니다.

Step 3. Nginx 재시작 및 적용

Bash
sudo nginx -t  # 문법 에러가 없는지 검사 (syntax is ok 응답 확인)
sudo systemctl reload nginx  # 변경된 설정으로 재시작

5. 프론트엔드 CI/CD 환경 구축 상세 내역

초기 구축 시 아래와 같은 과정으로 인프라가 세팅

5.1. Nginx 및 배포 전용 계정 세팅

  • 패키지 설치: sudo apt-get install -y nginx curl ca-certificates tar gzip

  • 보안 계정 생성: sudo useradd --create-home --shell /bin/bash github-runner (보안을 위해 root가 아닌 이 계정이 배포를 담당함)

  • 배포 디렉터리 생성: /srv/gachi-gacha/frontend-dev/releases 폴더를 생성하여 빌드 산출물을 저장

5.2. GitHub Self-hosted Runner 설치 (ARM64)

/opt/actions-runner 디렉터리를 만들고, GitHub Settings에서 제공하는 ARM64 리눅스용 Runner 패키지를 다운로드 및 압축 해제

폴더 권한을 runner 계정으로 넘김: sudo chown -R github-runner:github-runner /opt/actions-runner

깃허브 연동: sudo -u github-runner ./config.sh --url ... --token ...

서비스 등록: sudo ./svc.sh install github-runner -> sudo ./svc.sh start 로 가동

5.3. 무중단 배포 전략

현재 CI/CD YAML 스크립트(frontend-deploy.yml)는 배포 도중 화면이 깨지는 현상을 막기 위해 심볼릭 링크(Symbolic Link) 교체 방식을 사용

새 코드가 빌드되면 releases/커밋해시 이름의 새 폴더에 저장

Nginx가 바라보는 current라는 바로가기가 이전 폴더에서 새로 만들어진 폴더로 빠르게 교체(ln -sfn)

이를 통해 배포 중에도 지연 없이 서비스를 이용할 수 있으며, 롤백 시에도 이전 릴리스 폴더로 링크만 다시 연결해주면 즉시 복구됨


5.4. 사용 기술 및 역할

기술 스택 역할 및 설명
GitHub Actions (CI/CD 자동화) 코드 푸시 및 PR 시 자동으로 빌드(Build)하고, 완성된 정적 파일을 AWS EC2로 전송(Deploy)하는 파이프라인을 구동합니다.
AWS EC2 (Ubuntu) (호스팅 서버) 프론트엔드 애플리케이션이 실제로 띄워져 사용자에게 제공되는 클라우드 가상 서버입니다. DEV와 PROD 두 대를 운영합니다.
Nginx (웹 서버 & 리버스 프록시) 빌드된 프론트엔드 정적 파일을 사용자에게 제공, /api로 들어오는 요청을 백엔드 서버로 넘겨주는 역할을 합니다.
Let's Encrypt (Certbot) (HTTPS 보안) Nginx에 무료 SSL/TLS 인증서를 발급하고 자동 적용하여, 사용자 통신을 암호화합니다.

내도메인.한국 을 통해 AWS EC2의 Elastic IP 대신 사용자가 쉽게 접속할 수 있는 .kro.kr 도메인을 제공 및 매핑합니다.


5.5. 구축 흐름 및 의사결정 과정

Step 1. 인프라 환경 분리 (DEV / PROD)

  • 작업 내용: AWS EC2 인스턴스를 2대 생성하고 각각 고정 IP(Elastic IP)를 할당. 이후 dev.gachigacha.kro.kr (개발용)과 gachigacha.kro.kr (운영용) 도메인을 각각의 IP에 A 레코드로 연결
    • 실제 사용자에게 서비스되는 운영 환경을 건드리기 전, 개발 환경에서 신규 기능과 HTTPS 인증서 발급 리허설을 진행하기 위해 환경을 분리
    • 서브도메인(dev.) 방식을 채택하여 하나의 메인 도메인 계정에서 관리하도록 구성

Step 2. Nginx 웹 서버 및 리버스 프록시 세팅

  • 작업 내용: EC2 내부에 Nginx를 설치하고, 프론트엔드 정적 파일 경로 지정 및 /api 경로에 대한 리버스 프록시(proxy_pass)를 설정
    • 프론트엔드(HTTPS)에서 백엔드(HTTP)로 API 요청을 보낼 때 발생하는 혼합 콘텐츠 차단 에러와 CORS 에러를 방지하기 위함.
    • 프론트엔드는 상대 경로(/api/v1/...)로만 요청을 보내고, Nginx가 백엔드로 안전하게 전달.

Step 3. HTTPS (SSL 인증서) 적용

  • 작업 내용: certbot과 python3-certbot-nginx 패키지를 활용하여 각 도메인에 대한 SSL 인증서를 발급받고 443 포트(HTTPS)를 개방
    • 추후 추가 예정인 사용자의 현재 위치(GPS) 기반 기능, Secure cookie 처리, 그리고 카카오 로그인 등 외부 API 연동 시 HTTPS 환경이 필수적으로 요구되기 때문.

Step 4. GitHub Actions CI/CD 파이프라인 연동

  • 작업 내용: GitHub 저장소의 Secrets and variables에 접근 정보를 저장하고, 코드가 main(prod) fronend-dev(dev) 브랜치에 푸시될 때 자동으로 실행되는 Workflow(.yml)를 작성
    • 개발자가 매번 로컬에서 빌드하고 서버에 접속해 파일을 옮기는 수동 작업을 없애고, 휴먼 에러를 방지하기 위함.
    • 소스 코드 내부에 API URL이나 접속 키가 하드코딩되는 것을 막기 위해, GitHub Variables에 DEV_FRONTEND_URL (https://dev.gachigacha.kro.kr) 등을 등록하여 환경별로 안전하게 주입되도록 구성.

6. 파이프라인 작동 흐름 요약

  1. [개발자] 코드를 작성하고 GitHub dev 브랜치에 Push/PR.
  2. [CI: GitHub Actions]
    • 의존성 설치 (pnpm install)
    • 코드 검증 (ESLint, Prettier, TypeScript type check)
    • 프로덕션 빌드 (pnpm run build -> 정적 파일 생성)
  3. [CD: GitHub Actions]
    • 빌드된 결과물(디렉터리)을 AWS EC2(DEV) 서버로 안전하게 전송.
  4. [Hosting: Nginx]
    • https://dev.gachigacha.kro.kr 로 접속하는 사용자에게 전송된 최신 정적 파일을 렌더링.