DevOps/Deploy

S3 + CloudFront + Github-Actions으로 리액트 배포하기

닝닝깅 2024. 1. 22. 21:41

개발을 수차례 해봤지만 대용량 트래픽을 마주할 일이 없다는 이유로 배포는 항상 netlify나 github pages를 통하여 간단하게 해결했다.. 과거 딱 한번 AWS를 사용해본 적이 있으나 개발도 제대로 할 줄 모르던 시절에 겪어본 경험이라서 이번 기회에 AWS로 배포를 해보고자 마음 먹었다. + 자동화!

 

🧐 고민 : AWS의 어떤 방법을 통해 배포해야 하나

aws에서 제공하는 서비스가 너무 많아 어떤 방식으로 배포를 해야 할 지 선택해야 했다.

EC2를 사용하는 방법과 CloudFront + S3를 사용하는 방법 중에서 고민을 했다.

 

일단 각 용어의 개념을 정리해보았다.

✨ AWS?

  • 아마존닷컴에서 운영하는 클라우드 컴퓨팅 플랫폼이다.
  • 퍼블릭 클라우드 컴퓨팅 서비스를 제공한다.
  • IaaS ( Infra as a Service ) 형식을 갖추고 있다.
클라우드 컴퓨팅 
직접 서버 장비를 구매하거나 임대 계약을 하지 않고도, 요청하는 즉시 컴퓨팅 자원을 제공해주는 서비스로 원하는 시간 동안 원하는 만큼 컴퓨팅 자원을 이용할 수 있다.
퍼블릭 클라우드
특정 기업이나 사용자를 위한 서비스가 아닌 인터넷에 접속 가능한 모든 사용자를 위한 클라우드 서비스 모델
IaaS ( Infra as a Service )
- 인프라 수준의 클라우드 컴퓨팅을 제공한다
- 사용자가 서버 OS부터 미들웨어, 런타임, 그리고 데이터와 어플리케이션까지 직접 구성하고 관리할 수 있다.
- 클라우드 제공 업체는 데이터센터를 구축하여 서버 운영에 필요한 모든 것을 책임지고 관리한다.

 

EC2?

  • AWS의 컴퓨팅 서비스이다.
  • 컴퓨팅 리소스를 제공하므로 한대의 독립적인 컴퓨터라고 생각할 수 있다.
  • 필요에 따라 성능, 용량을 자유롭게 조절할 수 있다.
  • 리소스를 사용한만큼의 비용을 지불한다.

 

 CloudFront?

  • AWS의 네트워킹 서비스이다.
  • 데이터, 동영상, 애플리케이션 및 API를 전 고객에게 빠르고 안전하게 전송한다.
  • 사용자와 가까운 곳에 위치한 캐시서버에 해당 컨텐츠를 캐싱하고 컨텐츠 요청 시에 캐시서버에서 응답한다.
    •  => 지리적 물리적으로 떨어져 있는 사용자에게 콘텐츠 제공자의 콘텐츠를 더 빠르게 제공할 수 있다.

 

 S3?

  • AWS의 정적 파일 스토리지 서비스이다.
  • 사진, 비디오, 문서, frontend 코드 등을 저장한다.
  • 사용자는 URL을 통해 접근하고 다른 사용자들의 접근은 제한할 수 있다.
  • HTTP 프로토콜과 연동하여 정적 웹 사이트를 호스팅 하는데 사용할 수도 있다.
    •  => 스토리지에 html 파일을 올리고 브라우저에서 버킷 url로 파일에 접근하는 흐름으로 이해

 

💡 S3 + CloudFront 방식을 선택한 이유

S3 + CloudFront 방식을 선택한 이유는 ec2를 사용한 배포는 서버를 따로 구축한 뒤 배포를 해야했기에 러닝 커브가 높아보였다. aws의 기초를 경험해보기 위한 취지였기 때문에 비교적 간단해보이는 s3 + cloudFront 방식을 선택했다.

 

자 이제 배포를 시작해보자 ➰➰

 

✅ IAM 권한 설정 : 접근 권한을 위하여

⭐ AWS 계정이 없다면 지금 당장 만들고 오세요!! ⭐

 

IAM은 AWS 계정 내 사용자, 그룹 및 역할에 대한 권한을 관리하는 서비스이다. 

권한 설정하면 access-key-id와 secret-access-key를 발급해주는데 이걸 통해 S3 버킷에 접근할 자격을 얻게 되는 것이다.

 

1. 상단 검색창에 IAM 검색 => 왼쪽 사이드바에서 '사용자' 메뉴 => 오른쪽 상단 사용자 생성 버튼 클릭

 

2. 사용자 생성

사용자 이름을 입력한다. 

나는 임의로 test-dev라고 하였다.

다음 버튼을 눌러 권한설정으로 넘어간다.

 

<권한 옵션>에서 직접 정책 연결을 선택한다

<권한 정책>에서 S3, CloudFront 접근 권한을 얻기 위해 AmazonS3FullAccess, CloudFrontFullAcess 권한을 추가한다.

 

권한 추가를 완료하면 아래와 같은 화면이 뜬다.

 

사용자 생성 버튼을 눌러 사용자를 생성한다.

 

3. 생성한 사용자의 액세스 키 획득

생성된 사용자를 클릭하고 보안자격증명 탭으로 들어간다.

 

스크롤을 내려 액세스 키 만들기 버튼을 클릭한다.

 

 

사용 사례로는 CLI를 선택한다.

 

액세스 키 만들기 버튼을 클릭한다.

액세스 키와 비밀 엑세스 키가 생성된다.

상단 문구에 나온 것 처럼 비밀 엑세스 키는 다시 확인할 수 없으니 별도로 잘 보관해두도록 한다.

 

 

 S3 버킷 생성

1. 상단 검색창에 S3 검색 => 버킷 만들기 버튼 클릭

 

2. 버킷 만들기

버킷의 이름을 입력하고 aws 리전을 선택한다.

이때 버킷의 이름은 전세계적으로 고유한 이름이어야 한다.

 

버킷의 접근 권한을 내 계정에만 주기 위해서 ACL을 비활성화한다.

 

모든 퍼블릭 액세스 차단을 선택한다.

만약 퍼블릭 엑세스를 허용하게 되면 S3를 통해 정적 호스팅이 가능해진다. 나는 CloudFront를 통해 캐시된 CDN 서버에 데이터를 요청할 것이기 때문에 차단하였다.

 

 

나머지 설정은 기본 설정 그대로 두었다.

 

<버킷 버전 관리> : 업로드한 파일들의 versioning이 필요할 때 활성화한다.

<태그> : 결제 대시보드에서 비용 추적을 할 수 있는 이름을 작성해줄 수 있다.

<기본 암호화> : 업로드한 파일들을 암호화하여 저장할 때 활성화한다.

 

버킷 만들기 버튼을 눌러 버킷을 생성한다.

 

3. 생성한 버킷에 build 파일 업로드

버킷을 클릭하면 객체 탭에 아래와 같은 화면이 뜬다.

 

프로젝트를 build 한 후 생성된 build 폴더 속 파일들을 업로드 하면 된다.

 

4. 생성한 버킷을 사용한 웹 사이트 호스팅 설정

버킷의 속성 탭으로 이동하고 속성의 <정적 웹사이트 호스팅>을 활성화 시킨다.

인덱스 문서, 오류 문서가 모두 index.html인 이유는 리액트는 SPA프레임워크이기 때문이다.

 

 

 CloudFront 생성 및 연동

버킷에 업로드 한 정적파일을 CDN을 생성해 배포하기 위해 CloudFront를 생성할 차례이다.

 

1. 상단 검색창에 CloudFront 검색 => 배포 생성 버튼 클릭

2. 배포 생성

생성한 버킷 이름의 원본 도메인을 선택한다.

 

 

CloudFront로만 배포할 수 있도록 S3에서 모든 퍼블릭 액세스 차단을 차단했기 때문에 S3 버킷 액세스의 OAI 사용을 체크한다.

새 OAI 생성을 눌러 원본 액세스 ID를 만든다.

버킷정책 업데이트에도 동의한다.

OAI
CloudFront가 S3에 접근하는데 사용되는 접근 객체

 

배포 도메인이 S3의 버킷에 접근할 때 OAI를 통해 접근 권한을 확인하고 컨텐츠를 줄지 말지 결정한다.

 

 

 

Origin Shield를 활성화하고 리전을 선택한다.

Origin Shield
CDN과 origin 서버 사이에 추가적인 캐싱 레이어를 두고 컨텐츠를 캐싱한다. origin 서버에 대한 모든 요청이 거쳐지므로 캐시 적중률이 높아지고 동일 객체에 대한 동시 요청 수를 줄일 수 있다.

 

 

 

컨텐츠 파일의 크기를 줄이기 위해 자동으로 객체 압축 Yes를 선택한다.

 

<뷰어 프로토콜 정책> : HTTP를 HTTPS로 리다이렉트 시켜준다.

<허용된 HTTP 방법> : 정적 웹 사이트이기 때문에 GET, HEAD만 선택한다.

 

AWS의 캐싱 정책은 24시간 동안의 웹 컨텐츠를 캐싱한다.

24시간 이내 배포가 2번 이상 이루어졌을 때 24시간 후 변경사항을 확인해도 괜찮다면 기본 설정 그대로 두고

배포 후 변경사항을 바로 확인하고 싶다면 Caching Disabled로 설정한다.

 

방화벽을 활성화한다.

방화벽은 웹 사이트로 이동하는 악의적인 HTTP/S 트래픽을 필터링, 모니터링 및 차단하여 웹 앱을 보호하고, 승인되지 않은 데이터가 앱에서 나가는 것을 방지한다.

 

<기본값 루트객체>에 index.html을 입력한다.

 

나머지 설정은 그대로 둔 채 cloudFront를 생성한다.

 

3. 오류페이지 설정

SPA 기반의 리액트 배포이기 때문에 Redirect fallback 설정이 필요하다.

SPA는 하나의 index.html을 갖고 JS로 동적 라우팅이 이루어지기 때문에 S3에서 페이지를 찾지 못할 경우 403 Forbidden 를 응답한다. 따라서 403 오류코드에 대한 응답페이지를 직접 설정해줘야 한다.

 

CloudFront의 오류페이지 탭 > 사용자 정의 오류 응답 생성 버튼 클릭

 

403 오류코드를 전송할 경우 응답 페이지를 /index.html로 리다이렉트 시킨 뒤 200 확인 응답코드를 반환한다.

 

 

+ CloudFront의 무효화 탭에서 수동으로 기존의 캐시를 무효화하고 새로 캐싱할 수 있다.

 

 Github Actions Workflow 생성

1. github Secrets 등록

프로젝트 레포지토리의 Settings 탭 > Secrets and Variables > Actions에 들어간다.

New repository secret 버튼을 눌러 아래와 같이 4개의 secrets를 설정한다.

 

AWS_ACCESS_KEY_ID = IAM 설정에서 발급받은 access key

AWS_DISTRIBUTION_ID = cloudFront 아이디 ex) E2DINA3WIXKVKA

AWS_REGION = 버킷 생성 시 설정한 지역  ex) ap-northeast-2

AWS_SECRET_ACCESS_KEY = IAM 설정에서 발급받은 secret access key

 

2. github Actions workflow 생성

레포지토리의 Actions 탭에서 workflow를 생성한다.'set up a workflow yourself' 링크를 통해 템플릿 없이 직접 세팅하였다.

 

아래와 같이 yml 파일을 작성한다.

name: AWS_CICD

on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout source code
        uses: actions/checkout@v2
        
      - name: Install dependencies
        run: yarn install

	# 빌드
      - name: Build
        run: yarn build

	# 배포
      - name: S3 Deploy 
        run: aws s3 sync ./build s3://<생성한 bucket 이름>/ --acl bucket-owner-full-control
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          AWS_REGION: ${{ secrets.AWS_REGION }}

	# 기존 캐시 무효화
      - name: Invalidate CloudFront Cache 
        uses: chetan/invalidate-cloudfront-action@master
        env:
          AWS_DISTRIBUTION: ${{ secrets.AWS_DISTRIBUTION_ID }}
          PATHS: "/index.html"
        continue-on-error: true

 

 

이제 main 브랜치에 push하면 빌드와 배포가 자동으로 이루어진 결과를 확인할 수 있다.

 

 

배포 끝!

다음에는 EC2를 사용해서 AWS 근본 배포 해봐야지


참고

https://inpa.tistory.com/entry/AWS-%F0%9F%93%9A-%EC%95%84%EB%A7%88%EC%A1%B4-%EC%9B%B9-%EC%84%9C%EB%B9%84%EC%8A%A4-%EC%9A%A9%EC%96%B4-%EC%A2%85%EB%A5%98-%EC%A0%95%EB%A6%AC-EC2-EBS-RDB-S3-EBS-SES

https://velog.io/@jeongs/CSR-%EB%B0%B0%ED%8F%AC-%EC%A0%84%EB%9E%B5-with-S3-Cloud-Front-Github-Actions#cloudfront-%EB%B0%B0%ED%8F%AC-%EC%84%A4%EC%A0%95

https://velog.io/@tt8784/Github-Action-S3-CloudFront%EB%A1%9C-CICD-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B0#-cloudfront-%EC%83%9D%EC%84%B1-%EB%B0%8F-%EC%97%B0%EB%8F%99