react 프로젝트를 gitlab ci 를 이용하여 s3에 저장 후 cloudfront에 배포한 경험을 정리한다.
깃허브액션, 도커를 이용하여 자동배포는 설정해본적이 있지만 서비스가 중단되지 않는 무중단 배포는 아니었다.
이번엔 서비스가 중단되지 않는 무중단 배포를 설정해보려고 한다.
react를 무중단 배포 하는 방법은 여러가지가 있다.
Cloudfront로 ec2를 따로 관리 안해줘도 된다는 점과 protect 정책, cdn 등 많은 걸 지원해줘서 cloudfront로 결정했다.
배포 과정은 다음과 같다.
1. gitlab
github와는 다르게 gitlab은 runner를 따로 설치해서 사용해야 한다.
그래서 먼저 gitlab runner를 등록해야 한다.
처음 이부분을 모르고 계속 실패했다가 나중에 알게되었다.
gitlab runner는 https://docs.gitlab.com/runner/register/ 여기서 확인할 수 있다.
아니면 각 레퍼지토리 설정의 CI/CD란에서 gitlab runner를 확인할 수 있다.
gitlab runner 설치 명령어
# Download the binary for your system
sudo curl -L --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-linux-amd64
# Give it permission to execute
sudo chmod +x /usr/local/bin/gitlab-runner
# Create a GitLab Runner user
sudo useradd --comment 'GitLab Runner' --create-home gitlab-runner --shell /bin/bash
# Install and run as a service
sudo gitlab-runner install --user=gitlab-runner --working-directory=/home/gitlab-runner
sudo gitlab-runner start
gitlab runner 레퍼지토리에 등록 명령어
sudo gitlab-runner register --url [등록 url] --registration-token [등록 토큰]
토큰과 url은 ci/cd 설정 gitlab runner에서 확인 가능하다.
등록하고 새로고침해보면 등록을 확인할 수 있다.
나는 gitlab runner를 aws ec2인스턴스에 설치하여 어디서든 사용할 수 있게 설정하였다.
이제 gitlab ci를 작성한다.
.gitlab-ci.yml
파일이름은 위와 같이 해야 한다.
깃허브 액션은 특정 폴더에 넣으면 명명에 대한 규칙이 없었지만 깃랩은 .gitlab-ci.yml 이라는 파일이 필수로 존재해야 한다.
이 안에서 include를 활용하여 여러 파일로 나눌 수 있다.
.gitlab-ci.yml
stages:
- build-prod
- deploy-prod
build-prod:
stage: build
image: node:18.16.0
before_script:
- cp $PRODUCTION_ENV_FILE ./front/.env.production
- cd front
- npm install
script:
- npm run build
artifacts:
expire_in: 1 hour
paths:
- front/build
only:
- main
deploy-prod:
stage: deploy
image: python:3.9
before_script:
- pip install awscli
script:
- aws s3 sync front/build s3://$S3_BUCKET
- aws cloudfront create-invalidation --distribution-id $CLOUDFRONT_DISTRIBUTION_ID --paths "/*"
only:
- main
$로 표시한 부분은 ci/cd variable 에서 등록하여 사용 할 수 있다.
여기서 protected를 설정할 수 있는데 main브런치에서만 사용할 경우 체크를 해주고
dev브런치나 기타 브런치에서 설정할 경우 체크를 해제해야 변수를 불러온다.
내가 설정해준 variable들은 위와 같다.
AWS_ACCESS_KEY_ID, AWS_DEFAULT_REGION, AWS_SECRET_ACCESS_KEY를 설정해주면
awscli에서 자동으로 불러와 사용한다.
나머지는 dev서버용, prod서버용을 나누기 위해 사용했다.
추후 s3와 cloudfront를 만들고 변수값들을 넣어주면 된다.
yml파일 작성시 깃허브 액션과 다른점은 모든 작업을 일일히 해줘야 한다는 것이다.
예를 들면 깃허브 액션은 오픈소스로 다른 사람이 만들어 놓은 작업을 가져와 변수값만 넣으면 s3에 쉽게 저장할 수 있다.
하지만 깃랩은 awscli를 직접 설치하여 사용해야 한다는 점이다.
artifacts:
expire_in: 1 hour
paths:
- front/build
artifacts로 path에 있는 파일들을 유지시켜 다른 stage에서도 파일을 쓸 수 있게 한다.
- aws s3 sync front/build s3://$S3_BUCKET
s3에 내 파일들을 저장한다.
- aws cloudfront create-invalidation --distribution-id $CLOUDFRONT_DISTRIBUTION_ID --paths "/*"
cloudfront는 캐시 기능을 이용하여 s3에 있는 파일들을 불러온다.
이 캐시를 제거하여 내가 방금 s3에 올린 파일들을 불러올 수 있도록 하는 것이다.
2. S3
IAM계정을 만들고 S3에 접근할 수 있는 권한을 설정했다.
설정 후 S3를 만들때 public 접근을 막은 후 cloudfront에만 권한을 설정해 줄것이다.
해당 부분을 구현할 때 많은 블로그들을 봤지만 대부분 public설정을 해주고 cloudfront를 연결했다.
실제 운영서버에 public권한을 열어놓으면 다른 사람도 내 s3를 접근할 수 있다는 위험한 점이 있다.
실제 gitlab ci 가 작동되면 s3에는 보통 이런식으로 올라간다.
여기서 index.html을 cloudfront가 배포할 수 있도록 설정해주면 된다.
3. cloudfront
cloudfront 생성시 OAI 옵션으로 배포하려는 s3를 설정해주고 권한을 자동으로 추가해주면
해당 cloudfront에서만 s3에 접근할 수 있도록 설정이 된다.
s3에서도 정적 호스팅이 지원이 되지만 ssl까지 지원은 안된다.
cloudfront에서 ssl 통신을 하고 s3와는 http통신을 하도록 하기 위해 cloudfront를 사용한 큰 이유기는 하다.
그리고 매달 얼마를 내면 protect정책으로 디도스 공격을 막아주기도 한다.
CDN
cloudfront는 cdn기능도 제공한다.
cdn이란 content delivery network로 직역하면 컨텐츠를 제공하는 네트워크이다.
내가 한국에서 접속하면 한국에 있는 서버에서, 미국에서 접속하면 미국서버에서 페이지를 보여주는것이 이에 해당한다.
따라서 사용자는 어디에서 접속하든 가까운 서버에서 페이지를 제공받아 빠르게 이용할 수 있게 된다.
새로고침 오류
react는 SPA(single page application)이다.
react를 배포후 따로 설정을 안해준다면 새로고침시 404 에러를 뱉을 수도 있다.
어플리케이션 입장시 index.html을 보여준다.
/test 라는 uri로 이동후 새로고침을 하면 404 에러를 뱉는다.
왜냐하면 실제 리액트는 uri가 바뀌는것이 아니라 바뀌는 척을 하는 것이기 때문이다.
자세히 들여다 보면 리액트 라우터는 브라우저의 히스토리를 조작하여 uri가 바뀐것처럼 보이게 한다.
결국 그 uri에 대한 요청을 처리하는게 아니라 이미 가지고 있는 페이지를 uri가 바뀐것처럼하여 보여주는 것이다.
그렇기 때문에 브라우저에서 해당 uri에 대해 바로 요청한다면 이 요청은 처리할 수 없는것이다.
이를 해결하기 위해 다른 uri로 접근시 에러페이지 대신 200코드를 뱉어주고 index.html을 보여준다면
해당 uri를 자기가 가지고 있는 페이지에서 찾아 보여준다.
원래 ec2로 배포했을때에는 nginx를 이용하여 location 처리를 해줬지만 cloudfront에서는 에러 처리만 해주면 된다.
위와 같이 403, 404를 뱉는 대신에 200코드를 뱉고 index.html을 보여준다.
s3, cloudfront 만드는 법은 다른 블로그에서 자세한 설명들이 나와있다.
이러한 설정들을 해주고 마지막으로 route53으로 cloudfront를 잡아줬다.
결론
해당 파이프라인을 설정하면서 웹에 대한 흐름을 공부할 수 있었던 시간이다.
단순히 페이지를 제공하는게 아니라 좀 더 빠르게 제공하기 위한 방법을 고민했던 시간이다.
'개발 > Devops' 카테고리의 다른 글
[Devops] ELK 디스크 부족 이슈 S3로 해결하기 - ubuntu 22.04 (0) | 2023.11.23 |
---|---|
[Devops] ELK Stack 8.x 설치 - ubuntu 22.04 (0) | 2023.11.13 |
[Devops] spring boot 블루/그린 무중단 배포 (gitlab ci, docker, nginx) (0) | 2023.06.19 |
[Devops] github actions로 자동 배포 설정하기 (react docker 배포) (1) | 2023.02.16 |
[Devops] github actions로 자동 배포 설정하기 (nodejs 배포) (0) | 2023.02.16 |