Computer Science/Setup

[Nginx, React, Docker] 웹서버와 웹 프로젝트 컨테이너 분리하기

_혀니 2025. 4. 12. 13:35
728x90
반응형

우선 분리한 이유

기존에는 react + nginx를 합쳐서 프론트엔드 빌드가 끝나면 nginx를 실행하는 방식을 사용했다.

 

이렇게 하게 되면 불편한 점이: 프론트엔드 빌드가 실패하면 그대로 전체 서버가 죽어버린다.

프론트엔드 빌드는 실패해도 기존의 정적 파일을 서빙하는데

기존 컨테이너 방식으로는 nginx가 프엔 빌드 실패 시 실행을 안 해서 서빙을 못 한다.

게다가 nginx가 리버스 프록싱도 같이 하기 때문에 백엔드 서버 게이트웨이가 죽어버리면.................

 

이런 이유로 분리했다.

 

기존의 docker-compose.yml의 client 부분

services:
  client:
    build: 
      context: ./client
      dockerfile: Dockerfile
    container_name: client
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./client:/client
      - /etc/letsencrypt:/etc/letsencrypt:ro
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
      - ./nginx/default.conf:/etc/nginx/nginx.conf:ro
      - ./media/uploads:/app/uploads

 

Client Dockerfile: /cilent/Dockerfile

FROM node:20.18.1-alpine AS build
WORKDIR /app

# 소스 복사 및 빌드
COPY . .

RUN printf "VITE_PUBLIC_URL=http://localhost\nVITE_PUBLIC_API_URL=http://localhost/api\nVITE_PUBLIC_OAUTH_URL=http://localhost/oauth2\nVITE_PUBLIC_URL=http://localhost\nVITE_PUBLIC_SOCKET_URL=ws://localhost\n" > .env

RUN yarn install
RUN yarn build

FROM nginx:alpine
COPY --from=build /app/dist /opt/app
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

이렇게... 되어있었다.

프엔 빌드가 실패하면 nginx가 통으로 죽어버리는 구조

 

1. docker-compose.yml 수정

services:
  client:
    image: node:20.18.1-alpine
    container_name: client
    working_dir: /client
    environment:
      - VITE_API_SERVER_URL=${VITE_API_SERVER_URL}
      - VITE_LOCAL_SERVER_URL=${VITE_LOCAL_SERVER_URL}
      - VITE_WS_LOCAL_SERVER_URL=${VITE_WS_LOCAL_SERVER_URL}
      - VITE_OPENAI_API_KEY=${OPENAI_API_KEY}
      - VITE_TYPECAST_API_KEY=${VITE_TYPECAST_API_KEY}
    command: >
      sh -c "rm -rf /client/build/* &&
      npm install &&
      npm run build &&
      mkdir -p /app/build &&
      cp -rv /client/dist/* /app/build/"
    volumes:
      - ./client:/client
      - /home/ubuntu/opt/build:/app/build
      - ./media/uploads:/app/uploads
    networks:
      - see_through

  nginx:
    image: nginx:alpine
    container_name: nginx
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /etc/letsencrypt:/etc/letsencrypt:ro
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
      - /home/ubuntu/opt/build:/opt/app
    networks:
      - see_through

 

 

- 생각보다 간단하다.

1) client 컨테이너에서 쓰던 볼륨들을 nginx로 옮겨주고,

2) 빌드한 결과물인 /app/build를 호스트의 /home/ubuntu/opt/build(경로는 자유 설정)와 마운트한 뒤,

3) nginx에서 default.conf가 바라보는 root가 /opt/app으로 설정해두었으므로 nginx에서는 /opt/app과 마운트한다.

그리고 command에 빌드 스크립트들을 추가한다.

2. client/Dockerfile 삭제

빌드시 여러 이미지가 필요한 것이 아니기 때문에 더 이상 필요가 없어서 삭제했다.

728x90
반응형