Dev/Deployment

[Deployment] React App 배포하기

隣のプログラマー君 2024. 9. 23. 15:34
반응형

 

이거 두개만 가지고 아주 쉽게 React를 배포할 수 있다.

 

 

얼마 전에 회사에서 MonoRepo로 구현한 React App 배포 파이프라인 구축을 완료했다.
애초에 내가 만든 앱은 Next를 사용하지 않은 CSR 기반의 React App이고, 때문에 오직 정적 리소스 배포만으로도 동작이 가능하기 때문에 상당히 심플하고 뭐 난해할게 없다.
그래서 별로 어렵지 않은 작업에 속하는데 하지만 우리 신입 개발자들은 이런 기초적인 정보 하나하나가 소중한 사람들이기 때문에, 한번 이야기 해보도록 하자.

1. React 어플리케이션은 어떻게 배포되는가?

배포를 한번 해보자! 하고 구글을 잔뜩 검색해보다보면 이제 만나게 되는 혼란스러움이 있는데, 그게 뭐냐면 어디선 S3로 배포한다고 그러고 어디선 EC2로 배포한다고 그런다는거다.
AWS 조금이라도 만져본 사람은 알겠지만 S3의 경우엔 정적리소스 배포를 위한 것이고, EC2 같은 경우엔 PC라고 볼 수 있는 가상 인스턴스를 띄워서 컨테이너 배포를 하는데 쓴다 뭐 이정도로 알고 있을 것임.
아예 모르는 경우엔 S3는 웹서버를 띄우기 위한 컴퓨터 같은 너낌이고, EC2는 WAS를 띄우기 위한 컴퓨터 느낌이라고 생각해주면 되겠다.
근데 이제 두가지가 용도가 다른데 어디선 이거 쓴다 그러고 어디선 이거쓴다 그러는게 이제 혼란스럽다는거다.

React로 개발하는 어플리케이션은 상당히 특이한 점이 있다. React는 화면을 그리는 방식을 여러가지로 쓸 수 있는데 그게 이제 흔히 알고 있는 CSR, SSR, ISR 이런거임.
이게 React App 배포에 특이점을 발생시키는거다. 당연히 우리가 CSR 기반으로 개발을 한다면 서버측에서 동적으로 화면을 생성할 이유가 없기 때문에 빌드 결과물을 S3에 넣어두기만 해도 배포처리가 끝이난다.
하지만 동적으로 화면을 생성하게끔 개발해뒀다면 WAS같은 환경이 필요해진다. DB에서 데이터도 꺼내와야하고 요청마다 화면을 다르게 그려야하기때문이다. 뭐 디테일하게 화면을 그리는 방식은
다른 게시물에서 알아보도록 하고, 어쨌든 이런 특성이 있기 때문에 React App은 배포방식에 다양성을 가진다.

2. CI/CD는 뭘까?

뭐 말로는 유창하게 지속적 통합/배포 라고 부른다. 근데 대단한거 아니고, 원래 개발자가 수동으로 빌드도 하고, 그거 복사해다가 배포 가능한 서버에 붙여넣기 하고 실행하고 이러던걸 GitLab이나 GitHub 같은 Repository에 push만 하면
자동으로 알아서 배포까지 하게끔 만들어 놨다는 뜻임.
그래서 CI/CD 하기전에 배포가 어떻게 이뤄지는지에 대한 이해부터 필요하다는게 그 얘기다. 수동으로도 할줄 모르는 놈이 자동으로 한다고 설치는 꼴이 되기 때문이다.
이걸 두단계로 쪼개서 CI(통합단계)를 원활하게 할 수 있도록 도와주는게 gitlab-ci, jenkins 그런거고, CD(배포단계) 를 자동으로 개발자가 신경쓰지 않게끔 도와주는게 kubernetis, docker-compose 이런 툴들이라고 생각하면 되겠다.
근데 이제 React CSR 프로젝트를 배포하는 경우엔, Nginx 서버 실행시켜놓고 파일만 바꿔치기 해주면 재실행할 필요가 없기 때문에, CD단계의 툴은 생략하고도 진행할 수 있어서 초급개발자들에게 배포 파이프라인을 공부하는데 아주 좋아보일 수 밖에 없다.

3. CSR App을 배포해보자.

앞에서도 말했지만 CSR Application의 경우 단순히 빌드하고 빌드결과물만 배포서버에 옮겨 넣어주면 배포가 가능하다고 얘기했다. 때문에 단순해서 여러분이 이해하기에도 좋고,
내가 만든 시스템도 CSR이기 때문에 한번 예시를 들어 배포과정을 한번 살펴보자.
일단 내가 이번에 개발한 프로그램은 MonoRepository 구조를 채택했다. 때문에 패키지별로 별도 배포하는 방식을 필요로 하고, 그러기 위해선 커밋 내역에서 변경된 파일이 어떤 패키지에 존재하는지 감지하는 것이 필요하다.
그래서 GitLab-CI 스크립트에서 trigger라는 녀석을 활용했다.

// common .gitlab-ci.yml

stages:
  - triggers
  - build
  - deploy

# A_PIPELINE_TRIGGER
trigger-a:
  stage: triggers
  trigger:
    include: packages/apps/a/.gitlab-ci.yml
  rules:
    - if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME =~ /^(master)$/ || $CI_COMMIT_BRANCH =~ /^(master)$/'
      changes:
        - packages/apps/a/**/*
        - packages/modules/a-module/**/*
        - packages/modules/shared/**/*

# B_PIPELINE_TRIGGER
trigger-b:
  stage: triggers
  trigger:
    include: packages/apps/b/.gitlab-ci.yml
  rules:
    - if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME =~ /^(master)$/ || $CI_COMMIT_BRANCH =~ /^(master)$/'
      changes:
        - packages/apps/b/**/*

# C_PIPELINE_TRIGGER
trigger-c:
  stage: triggers
  trigger:
    include: /packages/apps/c/.gitlab-ci.yml
  rules:
    - if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME =~ /^(master)$/ || $CI_COMMIT_BRANCH =~ /^(master)$/'
      changes:
        - packages/apps/c/**/*
        - packages/modules/c-module/**/*
        - packages/modules/shared/**/*

# D_PIPELINE_TRIGGER
trigger-d:
  stage: triggers
  trigger:    
    include: packages/d/.gitlab-ci.yml
  rules:
    - if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME =~ /^(master)$/ || $CI_COMMIT_BRANCH =~ /^(master)$/'
      changes:
        - packages/apps/d/**/*

이렇게 메인 스크립트를 작성해주고, 배포할 각 패키지마다 별도의 .gitlab-ci.yml 파일을 작성해줘야함.
대충 살펴보면 a,b,c,d 라는 패키지가 존재하고 각 패키지에 속하는 경로의 파일이 변경되고, master 브랜치일 경우에만 배포 파이프라인을 동작시킨다고 보면 되겠다.

그 다음으로 실질적으로 배포과정을 처리하게 될 스크립트를 작성해주도록 하자.다 동일하니 a 패키지만 살펴보도록 하자.

stages:
  - build
  - deploy

# create build env
image: node:latest
cache:
  paths:
    - .yarn
before_script:
  - apt update && apt-get install

# build process
build_a:
  stage: build
  image: node:latest
  before_script:
    - yarn set version 4.1.1
    - yarn install
  script:
    - yarn a-build
  only:
    - master
  artifacts:
    paths:
      - packages/apps/a/dist/
  cache:
    paths:
      - packages/apps/a/dist/

# transfer bundle package
deploy_a:
  needs: [ build_a ]
  stage: deploy
  script:
    - apt update
    - apt-get install openssh-client
    - apt-get install sshpass
    - >
      sshpass -p 'password' scp -r -o StrictHostKeyChecking=no packages/apps/a/dist/* [계정]@[서버]:/home/docker/services/nginx/html/a
  only:
    - master

대충 또 설명하면 배포과정을 두가지 stage로 쪼갠다. build를 하고 배포 서버에 전송하기. CSR 프로젝트기 때문에 이런 단순한 방식으로도 자동 배포가 가능한 것이다.
우리가 흔히 알고 있는 yarn build 이런 명령어를 통해서 빌드를 하고, 빌드한 결과물을 cache에 저장한 뒤에 배포하는 서버로 SSH를 사용해서 전송해주면 된다고 보면 된다.

LIST

'Dev > Deployment' 카테고리의 다른 글

[Deployment] NGINX  (0) 2024.06.08
[Deployment] React App을 배포하기 전에  (2) 2024.06.06
[Docker] Docker  (0) 2023.08.02
[Deployment] 배포 (Deployment)를 시작하기 전에  (0) 2023.08.02