CHANBEEN.COM
React 정적 서빙에서 동적 서빙으로 전환기 (ft. 404 & API 이슈)
2024-09-30#React#Nginx#Docker#Troubleshooting

React 정적 서빙에서 동적 서빙으로 전환기 (ft. 404 & API 이슈)

들어가며

안녕하세요 🫰
최근 React 프로젝트를 Docker와 Nginx 환경에서 배포하던 중,
로컬에서는 멀쩡하던 앱이 Docker에 올라가면 죽는 기이한 현상들을 마주했습니다.

단순한 설정 오류인 줄 알았으나, 파고보니 정적 빌드 환경과 실시간 데이터 처리 간의 불일치 문제였고...
삽질 끝에 배포 방식을 전환하며 해결한 내용을 공유합니다.


1. 마주한 문제

새로고침하면 나타나는 404 Error

React-Router로 서브 페이지를 잘 만들어두었는데,
사용자가 특정 페이지에서 새로고침만 하면 404 페이지로 날아가 버렸습니다.

외부 API 라이브러리 작동 불능

로컬(npm start)에서는 그래프(Chart.js)가 예쁘게 잘 그려지는데,
Docker + Nginx로 배포한 서버에서는 Line Element 에러를 뿜으며 화면이 멈췄습니다.
라이브러리 등록(register) 코드도 문제없는데 말이죠.

에러 캡처본


2. 원인 분석

정적 파일은 이미 굳어버린 시멘트

원인은 React를 정적 빌드 파일(npm run build) 상태로 옮기다 문제가 발생하는,
SPA(Single Page Application) 문제일 가능성이 크다 판단했고, WAS가 없음에도 이런 문제가 발생하는 건
React 프로젝트 내에서 루트 URL을 지정한 부분이 있기 때문이라 판단했습니다.

이 경우, 실제 WAS를 사용하고 있었다면 단순히 404로 리다이렉트 될 때,
React의 루트 URL로 이동되도록 설정하면 정상적으로 동작하겠지만, 현재는 프록시나 WAS를 사용하지 않기에 솔루션이 되지 못했습니다.

API를 못 읽는건?

콘솔을 보기 전 까진 CORS 문제인가.. 했습니다.
다만 콘솔 로그를 보면, Line Element에 대한 오류만 표시되고 있습니다.

  ChartJS.register(verticalLinePlugin, CategoryScale, LinearScale, PointElement, LineElement, BarElement, Title, Tooltip, Legend, Filler, zoomPlugin);

여러가지 요소가 들어있지만, Chart.js의 Register 부분에도 정상적으로 LineELement가 등록이 되어있습니다.
그럼에도 이 문제가 나오는 건, 정적 빌드 환경에서 실시간 동적 데이터를 처리하는 데 문제가 있다는 결론에 이르렀습니다.

정적 파일의 경우 동적으로 움직이는 게 아닌, 사전에 정의된 환경을 가시화하는 데 특화되어 있습니다.
하지만 본 프로젝트의 페이지는 실시간으로 데이터가 바뀌는 모니터링 페이지이기 떄문에, Chart.js의 동적 업데이트를
정적 환경에서 읽지 못하는 것이라 판단했고, 이 가설을 기반으로 정적 렌더링에서 동적 렌더링으로 전환 해 보기로 했습니다.


3. 해결 방법

정적 서빙에서 동적 서빙으로 전환

우선, 현재 구축 된 CI/CD 파이프라인은 다음과 같습니다.

현재 아키텍쳐

Nginx 두 개가 실행이 되고 있던 구조였고, 외부 API와 각종 API를 사용하는 대시보드 특성상
동적 렌더링으로 전환해야 하는 상황입니다.

Nginx로 빌드 파일을 보여주는 대신, Docker 내부에서 직접 Node.js 서버를 띄워 동적으로 렌더링하도록 하면 될 것 같더군요.

목표 아키텍쳐

Dockerfile 수정

기존 Nginx 베이스 이미지를 버리고, 실제 개발 환경과 동일한 Node 버전으로 이미지를 재구축했습니다.

🥹 과거의 선택에 대한 회고...
당시에는 컨테이너 내부에서 여러 앱을 실행해보고자 Nginx를 사용했었습니다.
하지만 돌이켜보면, 동적 데이터 서빙이 핵심인 환경에서 'Before' 아키텍처는 잘못된 설계였습니다.
이번 기회에 불필요한 레이어를 제거했습니다.

## 변경 전
FROM nginx:alpine
COPY ./build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

## 변경 후 [Node 서버 기반 동적 배포]
FROM node:20.16.0
WORKDIR /app
# 캐싱 효율
COPY package*.json ./
RUN npm install --production
COPY . .
EXPOSE 80
CMD ["npm", "start"]

4. 결과 및 결론

배포 방식을 전환한 후, 모든 문제가 해결되었습니다.
404도 나오지 않고, 외부 API를 읽고 차트 그리기까지 깔끔하게 되더군요...

정상_대시보드

  • Node 서버가 라우팅을 직접 핸들링하며 404 오류가 사라졌습니다.
  • Chart.js 등 외부 라이브러리가 동적 환경에서 정상 동작하며 그래프가 실시간으로 업데이트됩니다.

마무리하며

이번 삽질을 통해 프로젝트의 특성(정적 대시보드 vs 실시간 데이터 앱)에 맞는 배포 전략을 선택하는 것이 얼마나 중요한지 다시금 깨달았습니다.
대시보드처럼 변화가 잦은 앱은 동적 서빙이나 SSR 환경을 고려하는 것이 정신 건강에 이로운 것 같네요!

빠른 수정과 적용을 위해 우선은 npm start로 처리 해 놨지만,
현재 방식보다 메모리 최적화를 위해 serve 패키지를 도입해서 사용 해 보는것도 괜찮을 것 같네요.
tomcat과 정적 배포 압박을 받아 시야가 잠시 좁아졌던 것 같습니다. 다시 이렇게 넓힐 수 있는 계기가 되었네요 :D

더 나은 구성을 구현할 때까지,
감사합니다. 😊