React 웹사이트 무중단배포: S3 CloudFront

동동주·2024년 11월 9일
1

⭐배포를 하게 된 배경

이번 학기에 SK Lookie라는 동아리에 들어가게 되었다. 여러 프로젝트를 진행해보고 싶었고, SK Lookie 동아리는 이미 1학기 때부터 기획을 진행하고 있었고 나는 개발자로써 하반기 팀원으로 중간 합류하게 되었다.

SK Lookie는 SK 행복나눔재단에 운영하는 청년 소셜 이노베이터 양성 대외활동으로, 사회문제를 해결할 비즈니스 모델을 만들고 사회를 긍정적으로 변화시키는 것을 목표로 한다. 전국 14개의 대학과 장애 전문 동아리가 SK 행복나눔재단의 지원을 받아 'Lookie'로서 활약하고 있다.

나는 SK Lookie의 MnM이라는 팀에 들어갔고 리필 문화 확산을 위한 '캠퍼스 기반 리필 스테이션'을 기획 및 운영하고 있었고 팀이 운영하는 캠코더 프로젝트의 웹사이트 구현을 위해 개발자를 모집하게 되었다고 한다.

사실 처음 동아리에 지원했을 때에는 백엔드 업무를 많이 맡고 싶었는데 생각보다 기존 팀원분들이 원하는 기능들이 프론트에 치중되어있다는 것을 알았고 React 코드를 제대로 짜본 적이 없던 나는 처음에는 주춤하였지만 프론트 경험이 있던 다른 분의 코드를 보고 뜯어보며 내 담당 파트의 코드를 짤 수 있게 되었다.

왜 S3와 CloudFront?

S3 CloudFront Github-Action로 배포를 하고자 한 이유는 먼저 백엔드와 프론트엔드를 따로 배포하기로 했다. 백엔드 서버 따로, 프론트엔드 서버 따로 배포하는 방법이 있었지만 서버를 두 개나 돌리는 것은 부담스럽다는 의견이 나왔다. 그래서 백엔드는 Nginx를 사용해 EC2에 무중단 배포하게 되었고 프론트엔드는 S3 CloudFront를 사용해 무중단 배포를 하기로 결정하였다.

무중단 배포가 필요했던 이유

같은 팀의 기획자분들이나 디자이너분들에게 어느 정도의 결과물들을 보냈어야했고, 기본 기능은 구현했지만 수정되어야할 사항들이 남아있었기 때문에, 배포 후 작업을 진행하면 자동으로 업데이트가 되는 무중단 배포가 필요했다.

💻 S3와 CloudFront를 이용한 배포

1. 가비아에서 도메인 구매

가비아에서 도메인을 구입한다. (Route53에서 구입하는 방법도 있다고 한다.)
나는 가장 저렴한 .shop을 샀다. 내 기억으론 1년에 500원이었던 것 같다.
도메인을 구입하고 한 5분 정도 기다리면 등록이 완료된다. 해당 도메인은 이용 중인 서비스 탬에서 확인할 수 있다.

2. 계정 설정

IAM 사용자 생성

  • IAM 사용자 페이지에 들어가 사용자를 추가한다. 사용자 이름과 사용자 지정 암호를 입력한 뒤 권한을 설정한다.
  • 권한 정책에서 AdministratorAccess를 체크해 사용자 그룹을 생성한다. 이는 어떤 리소스에 어떤 액세스를 가능하게 할지 권한을 정하는 것이고 AdministratorAccess는 모든 리소스에 액세스가 가능하게 설정하는 것이다.

IAM 액세스 키 발급

  • 사용자가 정상적으로 생성되었다면 AWS CLI를 사용하기 위해 IAM 액세스 키를 발급받는다. 발급받은 액세스 키는 csv파일로 저장되며 추후에 필요할 일이 있으며 파일을 따로 정리해두는 걸 권장한다.

해당 사이트 에 더 자세히 설명되어있다.

CloudWatch, S3 권한 추가

  • 생성된 IAM에서 권한추가 -> 직접 정책 연결 후 이미지에 있는 두 권한을 추가해준다.

S3 버킷 설정

배포용 S3 버킷을 생성

  • S3 버킷을 생성하면서 ACL을 활성화한다.
  • 객체 퍼블릭 차단을 해제한 후, 버킷 만들기를 클릭한다.

정적 호스팅 설정

  • 생성된 버킷의 속성 탭을 클릭한 후, 제일 하단으로 내려가면 해당 부분처럼 등록한다.
  • 권한 탭에서 버킷 정책을 수정할 차례이다.
  • 정책 생성기를 클릭하면 해당 창을 확인할 수 있다.
    • Select Type of Policy
      • S3 선택
    • Principal
        • 입력
    • Actions
      • GetObject 선택
    • Amazon Resource Name
      • 해당 버킷의 ARN/ (뒤에 / 붙여야함)
      • 예시: arn:aws:s3:::my_bucket_name/*

빌드 파일 업로드

$ yarn build 

해당 명령어를 통해 빌드 파일을 업로드할 수 있다. 사실 저 명령어는 패키지 매니저로 yarn을 사용하고 있을 때, 적용되는 명령어라고 하는데 해당 배포를 진행했을 때는 나는 패키지 매니저의 개념을 잘 몰랐어서 내 패키지 매니저가 npm인지 몰랐던 상황이었다. 하지만 해당 명령어를 사용하여도 문제 없이 잘 돌아갔다. (다음에는 npm을 기반으로 업로드 해야겠다😅)

빌드가 완료되면 build라는 디렉토리가 생성된다. 생성된 걸 확인했다면 빌드가 성공적으로 된 것이다! 이후에는 build 내부의 파일들을 S3 버킷에 담아야한다. 디렉토리 자체가 아닌 build 디렉토리 하위에 있는 파일들을 올려야한다.

정적 배포 확인


해당 사진처럼 창을 확인할 수 있다면 배포가 정상적으로 완료된 것이다!

4. Route53 설정

호스팅 영역 등록 및 가비아 네임서버 설정

  • Route53에 접속하여 호스팅 영역 생성을 클릭하고 도메인 이름에는 가비아에서 구매한 이름을 작성하면 된다.

  • 가비아에서 구매한 나의 도메인과 Route53에 등록한 도메인을 매핑해준다.

    가비아 > My가비아 > 도메인 > 매핑할도메인의 관리버튼 > 네임서버 설정 버튼

  • Route53에 있는 값을 순서대로 입력해준다.

SSL 인증서 설정

  • AWS Certificate Manager(ACM) 콘솔에 접속하여 SSL 인증서를 발급받는다.
  • 도메인에는 Route53에 등록한 도메인 이름을 등록한다.
  • 인증서 발급 상태 창에서 Route53에서 레코드 생성하기 버튼을 클릭한다.
  • 해당 창에서 CNAME이 추가된 것을 확인한다. (A 유형은 없어서 당황했는데 해당 사이트를 보고 괜찮다는 것을 알게 되었다.)
  • 레코드 이름과 값/트래픽 라우팅 대상 값이 이전 인증서의 값과 같은지 확인한다.

인증서 발급

  • 인증서 발급이 시간이 꽤 오래 걸리는 편인데, 검증 대기중상태에서 5분이 지나도 변화가 없다면 Route53에서 레코드 생성을 적용하면 된다.
  • 해당 사이트를 참고하면 된다.

5. CloudFront 설정

  • CloudFront에 접속하여, 배포 생성 버튼을 클릭한다.
  • 원본 도메인에는 정적 호스팅이 완료된 S3 버킷의 엔드포인트 주소를 등록한다. (원본 경로와 이름은 선택사항이다.)

  • 대체 도메인에는 Route53에 등록한 도메인, 사용자 정의 SSL 인증서에는 ACM에서 발급받은 인증서를 등록한다.
  • 기본 경로는 index.html로 설정한다.

캐시 무효화

  • 엣지 로케이션의 캐시 무효화(Cache Invalidation)을 통해 나의 캐시 정책을 무효화하고, 새롭게 캐시할 수 있다.
  • 무효화 생성 버튼 클릭
  • 무효화 생성 완료!

오류 페이지 설정

  • 잘못된 페이지에 접근했을 때에 대한 설정을 따로 해줄 수 있다.

A 레코드 추가

  • 아까 확인하지 못했던 A 레코드를 추가해줄 차례이다.

    A 레코드(A Record)는 DNS에 저장되는 정보의 타입으로 도메인 주소와 서버의 IP 주소가 직접 매핑시키는 방법이다

Route53 페이지에서 레코드 생성 버튼을 누른다.

  • 레코드 유형 A > 별칭 > CloudFront > 레코드 생성

여기까지 하면 배포가 완료된 것이다! 이제 Github-Action으로 CICD 파이프라인을 구성해주면 된다. (거의 다 왔다!!)

6. Github-Action (CICD) 생성

github-secret 설정

  • AWS_ACCESS_KEY_ID / AWS_SCRET_ACCESS_KEY
    - IAM 생성할 때 다운 받은 csv에 있는 값
  • AWS_DEFAULT_REGION
    - 예시) ap-northeast-2
  • AWS_STAGING_BUCKET_NAME
    - S3 버킷 이름
    오타 안 나게 조심하기! 이름에서 오타 한번 나서 다시 코드를 확인했던 기억이 있다😅

yaml 생성

프로젝트 루트 디렉토리에
.github > workflows > deploy.yaml 를 생성한다.

name: Build
on:
  push:
    branches:
      - main #빌드하고싶은 브랜치
jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [16.x]

    steps:
      - uses: actions/checkout@v1
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v1
        with:
          node-version: ${{ matrix.node-version }}
      - name: Yarn Install
        run: |
          yarn install
      - name: Yarn Build
        run: |
          yarn build
      - name: Deploy to S3
        uses: jakejarvis/s3-sync-action@master
        with:
          args: --delete
        env:
          AWS_S3_BUCKET: ${{ secrets.AWS_STAGING_BUCKET_NAME }}
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          AWS_REGION: ${{ secrets.AWS_DEFAULT_REGION }}
          SOURCE_DIR: "build" #빌드 파일 업로드 단계에서 생성된 파일 이름 쓰기
  • 주석을 단 곳은 프로젝트 설정에 따라 써야하는 코드가 다르니 한번씩 체크하고 넘어가길 바란다.
  • 해당 프로젝트에서는 다른 환경변수가 필요하지 않아 삽입하지 않았지만 GOOGLE_CLIENT_ID와 같은 환경변수 추가 설정이 필요하다면 step 칸에 아래와 같이 추가하면 된다.
- name: Create env file
        run: |
          touch .env
          echo VITE_GOOGLE_CLIENT_ID=${{ secrets.VITE_GOOGLE_CLIENT_ID }} >> .env
          # ...이런 식으로 환경 변수 삽입
          cat .env

빌드 잘 되는지 확인!


해당 과정이 끝나면 리포지토리의 Action 창에서 잘 build가 되는지 확인할 수 있다. build되는 데에는 약 1분에서 1분 30초 정도가 걸린다. 초록 불이 뜨면 build 성공이다!

  • 나는 첫 build에 바로 에러가 떴지만 에러 코드를 자세히 보면 어디서 오류가 났는지 알 수 있기 때문에 에러 창을 확인해보면 될 것 같다..
    😲 TIPS
    배포 후, 코드를 올릴 때 Github Action이 잘 돌아가는지 한번씩 확인하는 습관을 들이자! 로컬에서는 오류가 없어도 Action에서 오류나는 경우가 종종 있다.

느낀 점

배포를 처음 해 봐서 두려움이 많았는데 차근차근 해보니 크게 막히는 곳 없이 성공적으로 하게 되어 뿌듯하다. 시간은 한 넉넉잡아 (생소한 부분들이 많아 찾아보느라) 5시간 정도 걸린 것 같다. 다음 번에 하면 훨씬 시간이 단축될 것 같다!

개선해야할 점

  • 배포된 사이트에 처음 접속하면 사진을 로딩하는 시간이 몇 초 걸리데 이 부분에 대해 좀 더 알아볼 예정이다. 원래 로딩이 오래 걸리는 건지, 아니면 더 개선할 수 있는 방법이 있는지!
  • Github에 추가로 개선/구현된 사항을 PR로 올리고 머지하면 이 코드가 반영되는데 한 시간 정도가 걸렸다. 이 시간을 단축할 방법이 있는지 추가로 알아볼 예정이다.

✳️ 출처
https://velog.io/@igun0423/S3-CloudFront-Github-Action%EC%9C%BC%EB%A1%9C-ReactVite-App-%EB%B0%B0%ED%8F%AC-%EC%9E%90%EB%8F%99%ED%99%94%ED%95%98%EA%B8%B0

0개의 댓글