(24.08.05)[17주차] Nginx 404 Not Found 오류 고찰과 해결
정상적으로 Java SpringBoot 기반의 BE 프로젝트와 React를 활용한 FE 가 CI/CD를 통해서 컨테이너 형식으로 웹 서버 인스턴스에서 최신화되면서 배포 파이프 라인이 일단은 완료가 되었었다.
publicclassdev.com 도메인을 구입하여, 영역을 지정해 해당 웹서버 인스턴스로 접근할 수 있도록 설정을 했다.
하지만, 브라우저에서 도메인으로 진입 후, 새로고침을 하거나, 특정 주소에 직접적으로 접속을 하는 경우(ex. 브라우저 주소창에 publicclassdev.com/board/2 처럼 Path를 전부 지정해서 한번에 요청) 에 위와같은 nginx단에서 404 Not Found 에러가 발생했다.
이에 대해 고찰해보고 해결까지를 정리하면서 주의할 점을 다시 한번 상기 하도록 한다.
오류발생 : 기존 CD 배포 파이프라인 상황
이러한 파이프 라인상에서 Nginx 컨테이너에 직접적으로 네트워크 설정인 nginx.conf 파일의 내용을 수정을 하고자 하면서 404 에러를 고치고자 했다.
인스턴스 내 모든 컨테이너는 같은 브릿지 네트워크로 연결된 상태임에도 작동이 안되고 있었다.
conf 설정 : FAIL
events {}
http {
server {
listen 80;
server_name publicclassdev.com www.publicclassdev.com;
...
location / {
try_files $uri $uri/ /index.html;
}
...
관련한 FE 및 배포에 관련해서 지식이 없었기 때문에 거의 3일이상을 찾아보면서 nginx.conf 파일의 설정에 대해서 학습하면서 알아보면서 점검
- try_files 문으로 React에 파일이 없을 경우 이미지가 빌드가 될 때 생성된 index.html 을 참고하라는 conf 문을 입력
- 그럼에도 404 오류가 발생했기 때문에, 이는 참고해야할 index.html이 없거나 문제가 있다고 판단
- 기타 관련 설정들을 추가해도 똑같은 문제 발생
React container 의 /usr/share/nginx/html 와 일치 시키는 작업 : FAIL
# React 컨테이너에서 해당 경로를(내부 파일까지) 복사해서 /tmp 지정
docker cp publicclassdev-front:/usr/share/nginx/html /tmp/html
# 임시 경로 /tmp 복사한 내용을 nginx container 경로에 붙여넣기
docker cp /tmp/html nginx-container:/usr/share/nginx/
# 임시 경로의 파일 삭제
rm -rf /tmp/html
- 인스턴스 SSH 로 직접 React Container에서 참고해야하는 index.html과 static 요소들(파일들) 을 전부 복사해서 nginx container 안의 경로에 붙여넣어 참고할 수 있게 시도
- 404 오류는 발생하고 있지는 않지만, 오히려 index.html 에 지정되어있는 CSS 및 JS 요소들을 React 쪽으로 참조를 하고 있지 못한 상태
이 상황에서 2~3일 밤을 새가면서 찾아보면서 했지만, 모든 해결 방법들이 적용이 되지 않은 상태였다가, 깃헙액션의 처음부터 점검을 해보자라는 마인드로 전체 점검을 한 후, Dockerfile에서 그 문제의 원인을 알아 낼 수 있었다.
React Image를 위한 Dockerfile 점검 : SUCCESS
# Stage 1: Build
FROM node:18 AS build
# 작업 디렉토리 설정
WORKDIR /app
# 종속성 파일 복사
COPY package.json package-lock.json ./
# 종속성 설치
RUN npm install
# 애플리케이션 소스 복사
COPY . .
# 애플리케이션 빌드
RUN npm run build
# Stage 2: Production Image
FROM nginx:latest
# Nginx 설정 파일을 Docker 이미지에 포함
COPY nginx.conf /etc/nginx/nginx.conf
# 빌드 단계에서 생성된 파일을 Nginx로 복사
COPY --from=build /app/build /usr/share/nginx/html
# Nginx 포트 공개
EXPOSE 80
# Nginx 실행
CMD ["nginx", "-g", "daemon off;"]
위는 React 단의 Image를 만들어 낼 수 있는 Dockerfile
- Stage 2 부분에서 nginx.conf 를 통해서 Nginx를 빌드하는 단계를 발견
- 즉, 이미 React Container안에서는 서로를 참조할 수 있는 Nginx가 이미 존재를 하고 있었던 것
위처럼 80 포트로 외부에서 요청이 들어오게 될 때, nginx가 두개를 거쳐서 react로 들어가기 때문에 nginx 2개와 React의 빌드 파일이 조금이라도 통일되지 않거나, conf가 문법이 꼬일 경우,
- React의 어떠한 파일로도 참조할 수 없음
- 서로 다른 conf 로 참조해야할 파일이 있어도 다른 index.html에서 참조
등 서로가 서로를 참조를 하지 못하는 상황이 발생했던 것
파이프라인 재구성으로 해결
- 새로 만든 Nginx Container를 삭제
- React Container의 외부 노출 포트를 80 포트 = 인스턴스로 요청이 들어오는 포트로 설정
- 어차피 React Container안의 Nginx도 80:80 으로 받고 있기 때문에 정상적으로 작동이 됨
# 적용된 nginx.conf
user nginx;
worker_processes auto;
...
http {
...
server {
listen 80;
server_name publicclassdev.com www.publicclassdev.com;
root /usr/share/nginx/html;
index index.html;
# React 애플리케이션 요청 처리
location / {
try_files $uri $uri/ /index.html;
}
# Spring Boot API 요청 프록시
location /api/ {
proxy_pass http://publicclassdev:8080; # Spring Boot 컨테이너 이름을 확인하여 수정
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
..
- 이미 존재하는 React Container안의 위의 정상적으로 index.html을 참조할 수 있도록 nginx.conf 에 적용
# React Dockerfile에서 Nginx 설정 파일을 Docker 이미지에 포함하는 스텝
COPY nginx.conf /etc/nginx/nginx.conf
- 해당파일은 Dockerfile이 참조할 수 있도록 같은 경로에 저장을 해서 nginx.conf를 React 빌드할 때 포함시킬 수 있도했음
결국 일주일 내내 nginx와 React 컨테이너를 분리한다는 독립된 환경을 구축하려는 욕심으로 인해서, Dockerfile도 확인을 안하는 실수를 했던 것.
어차피 Nginx는 React와 서로를 참조해야지만 작동되는 웹어플리케이션이기 때문에 FE BE 를 분리한다는 명목하에 굳이 나눌 필요도 없는 nginx를 React와 분리시킨다는 이상한 Ideation에서 구상을 진행한 것이라고 생각한다.
앞으로 이러한 FE BE 분리 한 환경을 인스턴스 내에 Docker Container로 구축을 하고자 할 때 위에 같은 패턴을 가지고 구성을 하는 것도 참조해야할 필요가 있다고 생각한다.
'Today I Learned' 카테고리의 다른 글
(24.08.07)[17주차] Spring Batch와 스케쥴링 - 활용 및 정리 (0) | 2024.08.07 |
---|---|
(24.08.06)[17주차] Spring Batch와 스케쥴링 (0) | 2024.08.06 |
(24.08.02)[16주차] CD Pipeline 중 GitHubs자동화 배포에 대한 정리 (0) | 2024.08.02 |
(24.07.24)[15주차] Sprint Data JPA Tuple 객체의 사용 (2) | 2024.07.24 |
(24.07.23)[15주차] MinIO 활용 정리 - 코드 분석 (0) | 2024.07.23 |