프로젝트의 중심을 FE보단 BE에 맞추고 있다 보니, React의 배포를 최대한 간단하게 해보려한다.
구상한 계획은
- Nginx를 통해 메인 도메인으로 들어오는 경우 React 빌드 파일을 통해 정적 배포
- BE배포 처럼 배포 전략은 Blue/Green으로
- 두 빌드 파일을 서로 최신화하고 바꾸는 방식
- workflow 작성 및 deploy용 쉘 스크립트 작성
이렇게 된다.
Nginx로 React 프로젝트 배포하기
간단하게 메인 페이지와 /health 경로로 들어갔을 때 나오는 인사 화면 정도만 구성한 React 프로젝트를 빌드하고
scp -i ***.pem -r 빌드폴더경로/build 인스턴스사용자명@Ipv4:/인스턴스 내 저장할 경로
위 명령어를 통해 빌드 파일 통채로 인스턴스로 옮겨준다
이제 아래처럼 nginx에서 root위치를 build 폴더로 변경하고 index.html을 배포해주면 끝인데..
server {
# root /var/www/html;
# index index.html index.htm index.nginx-debian.html;
server_name xx.com www.xx.com; # managed by Certbot
root /home/ubuntu/fe/build;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/xx.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/xx.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
403 오류가 발생했다.
/var/log/nginx/error.log 를 확인해보면 파일들을 읽을 권한이 없다고 뜬다.
즉, 경로 설정과 읽으려는 시도는 정상적으로 이루어지지만 해당 경로의 파일들로 nginx가 접근하지 못하는 것이다.
/etc/nginx/nginx.conf 를 확인해보면 그 이유를 알 수 있다.
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
# multi_accept on;
}
...
user가 ubuntu가 아닌 www-data로 되어 있는 것을 확인할 수 있다.
즉, 빌드 폴더에 www-data가 접근할 수 있게 만들거나 nginx의 user를 ubuntu 로 변경해야 이를 해결할 수 있다.
나같은 경우 ubuntu나 Root로 변경하기엔 다른 파일들에 대한 접근이 모두 가능해지는 것이니 조금 꺼려져서 기존 /home/ubuntu 아래에 있던 빌드 폴더를 /www/html 밑으로 옮겨 접근을 가능하게 만들었다.
이제 배포한 도메인에 접속하면 정상적으로 리액트 페이지가 노출된다.
Nginx 설정 변경으로 빌드 파일 스왑하기
BE 배포 때 nginx 변수를 blue,green에 따라 변경한 후 reload하는 것 처럼 이번에는 root 경로를 변수로 설정하고 이를 blue, green 배포에 따라 변수를 덮어 씌운 후 reload해서 빌드 파일을 스왑해보려 한다.
/etc/nginx/conf.d/fe-route.inc 에
set $fe_route /var/www/fe_green/build;
변수를 설정해주고
fe-route-green엔 set $fe_route /var/www/fe_green/build;
fe-route-blue엔 set $fe_route /var/www/fe_blue/build;
이렇게 적어준 후
server {
include /etc/nginx/conf.d/fe-route.inc;
server_name xx.shop www.xx.shop; # managed by Certbot
root $fe_route;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/xx.shop/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/xx.shop/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}
이렇게 fe_route 변수를 root를 하고 그 아래의 index.html을 배포하는 방식으로 Nginx 설정을 변경한다.
Github action으로 FE 무중단 배포 완성시키기
이제, blue,green에 따라 다른 빌드 파일을 배포할 수 있는 설정을 마쳤으니
github action workflow를 만들고 실행시킬 쉘 스크립트만 작성하면 완료된다.
workflow는 BE때 작성했던 것을 바탕으로 작성했고 아래와 같다
name: Build and Deploy
on:
push:
branches:
- master
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: '18'
- name: Install dependencies
run: npm install
- name: Build React app
run: npm run build
- name: Copy build files to EC2 instance
uses: appleboy/scp-action@master
with:
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USERNAME }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
source: "build"
target: "/home/ubuntu/fe/"
- name: Send fe_deploy.sh
uses: appleboy/scp-action@master
with:
key: ${{ secrets.SSH_PRIVATE_KEY }}
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USERNAME }}
port: 22
source: "./fe_deploy.sh"
target: "/home/ubuntu/"
## deploy fe simply (without docker container)
- name: change fe
uses: appleboy/ssh-action@master
with:
key: ${{ secrets.SSH_PRIVATE_KEY }}
host: ${{ secrets.EC2_HOST }}
username: ${{ secrets.EC2_USERNAME }}
port: 22
script: |
chmod 777 ./fe_deploy.sh
./fe_deploy.sh
단순하지만 순서를 설명하자면
matser 브랜치를 감지 → push 발생 → workflow 실행 → node 환경 설정 → 패키지 설치 → React 빌드 → EC2 인스턴스에 build 폴더 전송 → 실행할 쉘 스크립트 전송 → ssh 연결로 쉘 스크립트 실행
의 순서로 실행된다.
쉘 스크립트는 아래와 같이 작성했다.
#!/bin/bash
IS_GREEN=$(cat /etc/nginx/conf.d/fe-route.inc | grep green)
if [ -z "$IS_GREEN" ]; then
echo "### BLUE => GREEN ###"
sudo rm -rf /var/www/fe_green
sudo cp -r /home/ubuntu/fe /var/www/fe_green
sudo cp /etc/nginx/conf.d/fe-route-green /etc/nginx/conf.d/fe-route.inc
sudo nginx -s reload
else
echo "### GREEN => BLUE ###"
sudo rm -rf /var/www/fe_blue
sudo cp -r /home/ubuntu/fe /var/www/fe_blue
sudo cp /etc/nginx/conf.d/fe-route-blue /etc/nginx/conf.d/fe-route.inc
sudo nginx -s reload
fi
마찬가지로 BE때 작성했던 것에서 많이 단순화 시킨 버전이다.
blue일 경우 기존 green 폴더를 지우고 전송된 신규 빌드 폴더를 green으로 옮긴 후, fe-route.inc 를 green 설정으로 변경한 후 nginx를 reload 시키는 방식이다.
BE 때 했던 방식과 많이 유사해서 구축하기 상당히 편했고, 또 의외로 폴더 권한과 명령어 권한 때문에 고생을 조금 했었다 .. !
끝 !
참고
https://projectlog.tistory.com/22
https://dejavuqa.tistory.com/358
http://miconblog.com/archives/1608
'Gyunpang' 카테고리의 다른 글
(번외) docker container scale 조정 시 github action에서만 recreate된다.. (0) | 2024.04.13 |
---|---|
6. 여러대의 인스턴스에 무중단 배포하기 (0) | 2024.04.06 |
4. Docker + Github Action + nginx로 CI/CD 파이프라인 구축하기 (1) | 2024.03.24 |
3. 도메인 연결 및 nginx 설정하기 (0) | 2024.03.24 |
2. Docker를 통해 Sonarqube를 프로젝트와 연동시켜보자 (0) | 2024.03.24 |