AWS, Nginx, Github Action을 활용한 React CI/CD 구축
이번에 서울특별시에서 주최하는 2024 서울 열린데이터광장 공공데이터 활용 창업 경진대회에 4명의 팀원과 함께 출전하기로 했습니다.
한국노인인력개발원 노인 구인정보를 활용하여, 사람인, 알바몬과 같은 구인구직 사이트를 만들기로 했습니다.
React를 이용한 프론트엔드 개발을 맡게 되어서, AWS, Nginx, Github Action을 사용하여 CI/CD를 우선 구축하였습니다.
React 레퍼지토리를 생성했다는 가정하에 포스팅을 진행하겠습니다.
AWS
인스턴스 생성
우선 AWS에 접속하여 EC2 -> 인스턴스(좌측 메뉴바) -> 인스턴스 시작(우측 상단)
순으로 접속하여 인스턴스를 생성창으로 접속합니다.
인스턴스의 이름을 설정하고 AMI를 Ubuntu Server 22.04
로 지정합니다.
AMI를 설정하였다면 인스턴스 유형과 키페어를 설정합니다. 인스턴스 유형을 t2.small
를 설정하였지만 t2.micro
로 설정하여도 무방합니다.
마지막으로 보안 그룹을 설정합니다. 저희는 nginx를 사용하여 배포를 하기 때문에 HTTP,HTTPS 트래픽을 허용합니다. 우측 하단의 인스턴스 시작
버튼을 클릭하여 인스턴스를 생성합니다.
node js 설치
생성된 인스턴스에서 react를 실행하기 위해 node js를 설치합니다. 저는 아래 사이트를 참고하여 VSCode에서 Remote Development를 사용하여 인스턴스에 접근하였습니다.
VSCode에서 AWS EC2 instance원격 접속하기
위 방법을 사용하시는 분들은 다운로드한 키페어에 읽기 권한을 반드시 부여하셔야 합니다.
접속을 하셨다면 터미널 창을 열고 node js 설치를 진행합니다.
로컬 환경과 같은 버전을 다운 받는 것을 권장합니다.
아래 명령을 입력해 현재 계정에 nvm
스크립트를 설치합니다.
1
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bash
설치한 nvm
스크립트를 사용하기 위해 아래 source
명령어를 입력해 .bashrc
파일에 수정된 값을 적용시킵니다.
1
$ source ~/.bashrc
아래 명령어를 입력해 설치 가능한 버전을 볼 수 있습니다.
1
$ nvm list-remote
저는 로컬 환경과 같은 v20.12.2
를 설치하겠습니다.
1
$ nvm install 20.12.2
GitHub Action
self-hosted runner
GitHub의 React 레퍼지토리로 들어가 setting -> runner -> New self-hosted runner
를 클릭합니다.
self-hosted runner 설치하면 연결된 GitHub의 내용이 업데이트 될 때마다 그 내용을 다운로드합니다.
Runner image는 Linx를 클릭하고 위의 박스 친 부분의 명령어들을 aws 인스턴스 터미널에 입력하여 설치를 진행합니다.
actions-runner
디렉토리로 들어가면 svc.sh
파일이 생성된 것을 확인할 수 있습니다. 아래의 명령어로 설치를 진행합니다
1
$ sudo ./svc.sh start
workflows
이제 workflow를 지정하여 저장소에 이벤트가 발생할 경우 실행할 작업들을 설정합니다.
GitHub 레퍼지토리의 Action
에 들어가 node
를 검색하여 Node.js
를 클릭합니다.
이제 위 창에서 아래 코드를 붙여넣기 하고 commit-changes
를 클릭합니다. node-version
의 경우 이용하는 Node.js 버전에 맞게 수정해야 합니다!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs
name: Node.js CI
on:
push:
branches: [ "main" ]
jobs:
build:
runs-on : self-hosted
strategy :
matrix:
node-version: [20.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps :
- uses: actions/checkout@v3
- name: Use Node.js $
uses: actions/setup-node@v3
with:
node-version: $
cache: 'npm'
- run: npm ci
- run: npm run build --if-present
참고로 저의 경우에는 run: npm ci
에서 계속 에러가 발생하였습니다. 로컬의 package-lock.json
과 GitHub에 package-lock.json
의 충돌이 원인이었고 새로운 레퍼지토리를 생성하여 .gitignore
에 package-lock.json
을 추가하였습니다. 이후 워크플로우의 - run : npm ci
상단에 - run: npm install
을 추가하여 이벤트 발생시 AWS 인스턴스 내에서 package-lock.json
파일이 생성되게 하여 문제를 해결했습니다.
1
2
3
4
# ...
- run: npm install
- run: npm ci
# ...
위 작업을 모두 마치면 Github 레포지토리의 Action에서 CI/CD 워크플로우가 실행됩니다.
잘 실행이 되었다면 Aws 인스턴스의 /actions-runner/_work
에 Github 파일이 로드됩니다.
Nginx
Nginx 설치
이제 Github 레퍼지토리에 commit을 하면 자동으로 Aws 인스턴스에 내용이 적용되고 빌드됩니다. 빌드 된 내용을 Nginx를 사용하여 배포하면 됩니다.
Aws 인스턴스 터미널에 아래 명령어를 사용하여 Nginx 설치를 진행합니다.
1
$ sudo apt install nginx
설치를 완료했다면 우리가 만드는 설정과 겹칠 수 있기 때문에 기본 설정을 삭제합니다.
1
2
$ sudo rm /etc/nginx/sites-available/default
$ sudo rm /etc/nginx/sites-enabled/default
이제 Nginx 설정파일을 생성합니다.
1
2
$ cd /etc/nginx/sites-available/
$ sudo touch myapp.conf
myapp.conf
의 내용은 다음과 같습니다.
1
2
3
4
5
6
7
8
server {
listen 80;
location / {
root /home/user/myapp/build;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
}
listen 80
의 의미는 포트 80번을 통해 접근을 허용한다는 뜻입니다. 저희는 Aws 인스턴스를 생성하면서 방화벽이 http
에 대한 접근을 허용했습니다만 혹시 하시지 않은 분들은 Aws 인스턴스의 인바운드 규칙에 http
통신을 추가해 주시기 바랍니다.
저의 경우에는 root
에 /home/ubuntu/actions-runner/_work/the-nuri-front/the-nuri-front/build;
를 입력하였습니다.
root에 들어가는 경로 모두 읽기 권한이 부여되어야 합니다. 그렇지 않으면 Nginx에서 403 에러를 발생시킵니다.
1
sudo ln -s /etc/nginx/sites-available/myapp.conf /etc/nginx/sites-enabled/myapp.conf
위 명령어를 입력하여 /etc/nginx/sites-available/
에 설정 파일의 심볼릭 링크를 /etc/nginx/sites-enabled/
에 만듭니다.
워크플로우 추가
아쉽게 Aws 인스턴스에 이벤트 내용을 적용시켰다고 하더라도 Nginx가 서비스하는 웹 페이지에는 적용되지 않습니다.
무중단 배포를 하는 법이 있지만 내용이 너무 복잡하여 그냥 Nginx를 껐다가 다시 실행하는 방식을 선택하였습니다.
1
2
3
4
5
6
7
8
9
10
11
...
- run : npm install
- run: npm ci
- run: npm run build --if-present
# 아래 내용 추가
- name: Stop Nginx
run: sudo service nginx stop
- name: Start Nginx
run: sudo service nginx start
이 방법은 실제 서비스에 적용되기에는 많은 무리가 있다고 생각되니 참고해 주시기 바랍니다.
이제 커밋한 내용이 퍼블릭 주소의 웹사이트에도 잘 적용된 것을 확인할 수 있습니다.