vite + nginx를 도커 이미지로 만들어 배포하기 - local 편

haerim·2024년 3월 19일
2

배포 배경

드디어 작게 모여서 하던 사이드 프로젝트의 클라이언트를 웹서버로 올릴 준비가 되었습니다. (박수박수!)
이미 백엔드 서버는 NAS 서버에 배포되어 있는 상황인지라 프론트엔드만 NAS 서버에 배포하면 되는 상황...

약간의 이슈

백엔드 분과 몇 번 대화 후 프론트엔드가 결정해줘야 하는 사항들이 몇가지 생겼었습니다.
가장 중요 골자는 프론트엔드를 어떤 식으로 배포할 것이냐, 였는데 기존에는 백엔드 분께서 일단 NAS 서버에서 npm run start라는 커맨드를 이용해서 돌려보셨던 상황...!
그러나 npm run start라는 커맨드는 dev 모드에서 사용하는 커맨드였고 실제 배포와는 무관한 것이었기 때문에 올바른 배포 방법이 아니었습니다. (그래서 그랬는지 자꾸 죽어버리는 프론트엔드 서버... 당연한 거였을까)

배포 방향 결정

결론적으로 프론트엔드는 NAS 서버 내에 nginx를 설치하고, 빌드한 파일을 nginx로 배포하는 방향으로 결정했습니다. (이게 맞는 듯?)
그리고 그냥 배포하는 게 아니라 Docker 이미지로 만들어서 배포하고는 것이 최종 방향이었습니다.

즉! 프론트엔드 클라이언트 + Nginx를 도커 이미지로 만들어서 NAS 서버에 배포를 하자! (꿈도 야무짐)

참고 자료

프론트엔드 팀원 전부 nginx 문외한이었으므로...
React + NginX를 도커 이미지로 만들어 배포하기 를 참고했습니다.

배포 과정

아무튼... NAS 서버는 함부로 건드리고 싶지 않은 부분이라... 일단 로컬 환경에서 Docker 이미지를 만들어서 배포해보기로 해서 프론트엔드 같이 하시는 분과 디스코드에서 만나서 화면 공유를 하고, 저의 PC로 시도를 했습니다... (뭐 잘 안 되면 다 날리면 되지! 하는 나이브한 생각으로 ㅎㅎ)

다행히 이미 docker는 설치한 상태이기 때문에 (설치 자체는 정말 어렵지 않음!) 클라이언트 디렉토리에서 설정을 진행하기 시작했습니다.

1. 배포할 디렉토리 선정

  • 배포를 시도할 프로젝트로 이미 vite 기반 프로젝트가 있어서 그 디렉토리를 선정했습니다.
  • (아예 처음부터 nginx로 배포하면 cra나 vite로 앱을 만들어서 진행하면 될 것 같습니다.)

2. nginx.conf 생성

  • 배포할 디렉토리를 루트로 하여 nginx 폴더를 만듭니다.
  • 그리고 nginx 폴더 밑에 nginx.conf 파일을 생성해 줍니다.
    • 이렇게 src 폴더와 형제 레벨로 생성하면 됩니다!

nginx.conf 파일

# ./nginx/nginx.conf

server {
    listen 80;
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;
    location / {
        # root를 /usr/share/nginx/html 을 바라보게 했으므로(Dockerfile 참고)
        # 해당 경로 아래에 배포해주면 됩니다.
        root   /usr/share/nginx/html;
        index  index.html index.htm;
        try_files $uri $uri/ /index.html;
    }
}
  • server 안에 들어오는 내용은 이하와 같습니다.
    • 80번 포트에서 클라이언트 요청을 수신합니다.
    • access 로그와 error 로그를 남길 장소를 지정합니다.
      • 도커에서 해당 경로를 찾아 쪼로로 따라 들어가 보면 여기에 이렇게 로그를 남기도록 설정하는 것입니다.
      • access_log는 클라이언트 요청에 대한 로그를 기록하는 로그 파일입니다.
      • error_log는 서버 오류에 대한 로그를 기록하는 로그 파일입니다.
    • URL 경로에 따라 서버가 어떻게 동작해야 하는지를 설정합니다.
      • 정적 파일들이 위치하는 디렉토리를 지정합니다. 클라이언트가 요청한 파일을 찾기 위해 여기서부터 검색합니다.
        • 만약 요청한 경로에 디렉토리가 포함되어 있고, 그 디렉토리에 해당 파일이 없으면, 이 인덱스 파일들 중에서 먼저 발견된 것을 클라이언트에게 반환합니다.
    • Nginx가 요청된 파일을 찾을 때 사용할 전략을 정의해둡니다.
      • 먼저 $uri에 해당하는 파일이 있는지 확인하고, 없으면 $uri/로 시도하고, 그래도 없으면 /index.html을 반환하도록 합니다. (이 부분이 세팅되어 있지 않으면 요청된 URL에 해당하는 파일이 없을 경우, 라우팅을 프론트엔드에서 처리할 수 없게 되어 에러가 발생합니다.)

3. DockerFile 생성

이 부분이 가장 곤란했던 부분... 아마도 docker와 yml을 잘 몰라서 몇 번의 에러를 경험했었던 것 같습니다.

Dockerfile

# ./Dockerfile

# nginx
FROM nginx

# 작업 디렉토리는 default로 지정했습니다.
WORKDIR /

# 로컬에서 빌드한 결과물을 /usr/share/nginx/html 으로 복사합니다.
COPY ./dist /usr/share/nginx/html

# 기본 nginx 설정 파일을 삭제합니다. (custom 설정과 충돌 방지)
RUN rm /etc/nginx/conf.d/default.conf

# custom 설정파일을 컨테이너 내부로 복사합니다.
COPY nginx/nginx.conf /etc/nginx/conf.d

# 컨테이너의 80번 포트를 열어줍니다.
EXPOSE 80

# nginx 서버를 실행하고 백그라운드로 동작하도록 합니다.
CMD ["nginx", "-g", "daemon off;"]

트러블 슈팅

  1. 먼저 tsconfig.json의 "types" 부분에 "vitest/globals" 를 추가해주었습니다. build 시 해당 부분이 추가되어 있지 않아 build가 실패했었습니다. (확실히 vite가 cra보다 build 속도가 빨랐습니다.)

  2. 기존 참고한 자료에서는 /build 로 지정이 되어 있었는데, vite로 만든 프로젝트는 build 시 이름이 dist로 지정이 됩니다. 따라서 DockerFile에서 빌드 폴더를 dist로 바라볼 수 있도록 수정했습니다.

  3. 경로 이슈가 계속 생겨 몇 번의 시도 후 npm install 하는 부분과 npm run build를 하는 부분을 제거하고, 수동 빌드를 진행했습니다. (이건 완벽한 트러블 슈팅이라고 볼 수 없어 점진적으로 YML 파일을 수정할 예정입니다.)

4. Dockerfile Image 생성

docker build --no-cache --tag nginxtest:test .
  • 도커 이미지를 빌드하는 데에 사용하는 커맨드입니다.
  • --no cache 옵션을 사용했습니다. (빌드 프로세스에서 캐시를 사용하지 않도록 지정하기 위해)
  • 빌드된 이미지에 태그를 지정했습니다. nginxtest 라는 이름을 붙이고, 태그 명으로 test 를 사용했습니다. (로컬에서 테스트용으로 만든 거라!)

수많은 역경을 해결한 끝에 만난 이 화면... 진짜 울 뻔...

도커 이미지에서 생성된 걸 확인할 수 있었습니다.

5. Nginx 웹서버 실행

  • 생성된 이미지 옆에 작은 세모꼴 버튼을 클릭하면 해당하는 화면이 나옵니다.
  • Optional settings를 클릭하면 좀 더 옵셔널한 설정을 부여할 수 있습니다.
  • container 이름, 호스팅할 port 등을 선택할 수 있습니다.
    container 이름을 설정하지 않을 경우 docker에서 임의로 지정해줍니다.
    호스팅할 port 또한 마찬가지이나 웬만하면 지정해 줍시다. (어디 포트인지 찾기 어려우니까...)
  • 다 설정했으면 run 버튼을 클릭해 줍니다.

그러면 컨테이너가 만들어져서 동작하는 걸 확인할 수 있습니다. 저는 3001 포트로 웹서버를 열었기 때문에 localhost:3001로 접속해보았습니다.

6. 접속

큰 문제가 없다면 3001 포트로 접속했을 때 웹 브라우저로 잘 뜨는 걸 확인할 수 있었습니다! 와!

느낀점

  • 사실 처음에는 아예 시도해보지 않은 영역이었어서 docker로 이미지를 만들고, nginx 웹 서버를 올리고 하는 것 자체가 약간 주저 됐었는데, 막상 몇 번의 트러블 슈팅을 경험하고 실제로 올려보고 나니 다음 번에는 더 잘 할 수 있을 거 같다는 생각이 들었습니다.
  • docker와 nginx를 좀 더 공부해야겠습니다. 아직까지는 명확히 어떤 의미인지 와닿지는 않아서...
  • YML으로 script를 짜는 것을 좀 더 공부해야겠다는 생각이 듭니다. 아직까진 외계어처럼 보이네요...

차후 목표

  • local에서 성공했으니 이번에는 NAS 서버에도 올려보기로 다음 목표를 잡았습니다!
profile
멋진 프론트엔드 개발자가 되고 싶은

0개의 댓글