본문 바로가기
  • ANALOG CODE
  • AnalogCode
개발

Nuxt.js SSR 모드 PM2 배포시 빌드 문제

by 아날로그코더 2023. 4. 13.
반응형

Nuxt를 사용하여 SSR 모드로 어플리케이션을 만들어서 PM2를 사용하여 서버로 배포한다. 그러면 서버에서 nuxt build 작업을 하게 되는데, 이때 빌드 작업이 CPU와 메모리에 상당한 부하를 일으킨다. 그래서 AWS EC2 micro 이하급으로 하면 빌드 중간에 리소스 부족으로 멈추는 현상이 발생한다.

 

 

 

문제가 발생하는 현재 상황은 이렇다.

Nuxt SSR + PM2 Deploy

Nuxt SSR 모드로 개발을 하고 PM2를 이용하여 서버에서 인스턴스 관리를 하고 PM2 deploy 를 이용하여 배포 작업을 한다.

Nuxt SSR 모드로 production server에서 동작하려면 빌드 과정이 필요하다. 이 빌드 작업은 Remote Server에서 실행한다.

 

Nuxt SSR 모드 명령어

Nuxt가 SSR 모드로 동작하게 하기 위해 필요한 과정이다.

  • 빌드: nuxt build
  • 실행: nuxt start
// package.json

{
  "scripts": {
    "dev": "nuxt",
    "build": "nuxt build",
    "start": "nuxt start"
  },
  ...
 }

빌드를 하면 .nuxt 라는 폴더가 생기는데 여기에 빌드 결과물들이 생성된다. 이 폴더는 SSR 모드로 실행하는데 필요한 폴더이다.

 

PM2 Configuration

PM2를 이용하여 test-app을 실행시켜주고 인스턴스 관리를 하게 한다.

// ecosystem.config.js

module.exports = {
  apps : [{
    name: 'test-app',
    script: 'npm run start',
    watch: '.',
    instances: 1,
    autorestart: true,
    env: {
      NODE_ENV: 'development'
    },
    env_production: {
      NODE_ENV: 'production'
    }
  }]
}

 

PM2 Deploy Configuration

PM2 deploy 를 사용하여 서버에 배포작업을 진행한다. post-deploy에서 다음 작업을 순서대로 진행한다.

  • npm install : 의존성 패키지 설치
  • npm run build : nuxt 빌드 
  • pm2 reload : 프로세스 재시작

문제점이 여기에 있다.

배포시에 remote server 에서 빌드 작업을 한다. 이 때 빌드 작업 부하가 remote server에서 너무 심하게 걸려서 빌드가 실패하고 배포가 실패하는 상황이 생긴다.

// deploy.config.js

module.exports = {
  deploy : {
    production : {
      key: 'key.pem',
      user : 'username',
      host : ['xxx.xxx.xxx.xxx']
      ref  : 'origin/main',
      repo : 'gitrepo.git',
      path : 'path',
      'post-deploy' : 'npm install && npm run build && pm2 reload ecosystem.config.js --env production',
    }
  }
}

 

아래는 Nuxt SSR 빌드 작업시에 얼마나 부하가 걸리는 지를 측정한 결과이다.

 

 

nuxt build 작업 부하

보통 프로젝트 초창기에 micro 급과 같은 저렴한 서버를 사용을 하여 서비스를 하게 되는데, 여기서 배포를 하면 중간에 빌드 시간이 너무 오래 걸리고 서버에 부하가 심하다. 그리고 빌드시간동안 페이지가 정상적으로 보이지 않게 된다. 아래는 빌드 테스트를 한 결과이다.

 

테스트 서버: AWS / EC2 / t2.micro

vCPU 1
메모리 1 GiB

 

빌드시간4분 28초

nuxt build time

 

Cpu 사용량 : 최대 99% 까지 올라감

메모리 사용량 : 50% 이상

EC2 모니터링 (CPU 사용률)

top 명령어 모니터링

TOP 명령어

이처럼 nuxt build 작업은 cpu와 메모리를 너무 많이 사용하고 있어서 서버 배포시에 시간이 오래 걸리고 잘못하다 빌드 작업이 멈추는 상황까지 발생한다. 그러면 배포작업이 실패하게 되어 생각만해도 피곤한 상황이 발생한다.ㅠㅠ

 

 

 

 

왜 빌드를 서버에서? 

부하가 많이 걸리는 빌드 작업을 꼭 Remote Server에서 해야될까란 의문이 들었다. 서버가 여러개라면 모든 서버에서 이 빌드 작업을 해야하는 엄청난 낭비가 있는데도 불구하고 말이다.

 

내가 이렇게 했던 이유는 하나이다. Nuxt 문서에 .nuxt 폴더는 .gitignore 에 추가해서 git에 커밋되지 않도록 하라고 가이드를 해주었기 때문이었다.

Nuxt build directory

 

맞는말이고 나도 수긍한 부분이다. 빌드 서버가 따로 있고 빌드 결과물만 Production 서버로 배포하면 되기 때문이다. 아니면 빌드후에 Docker 이미지를 만들어서 배포하면 되기 때문이다. 그래서 굳이 build 결과물까지 git 저장소에 커밋될 필요는 없다.

 

그런데 PM2 deploy 시스템은 git 저장소를 배포할 서버에 복제하고 업데이트하는 방식이다. 그래서 git 저장소에는 빌드된 결과물이 없기 때문에 git 저장소를 복제하거나 최신버전으로 업데이트를 하면 빌드 작업을 해야만 한다. PM2 deploy를 사용하려면 어쩔 수가 없다.

추후에는 컨테이너 기반으로 개선된 CI/CD를 도입하겠지만, 현재는 최소한의 인프라만 이용해서 서비스를 구축하고 싶어서 이렇게 하였다.

 

 

 

 

해결책

결국 Remote Server에서의 빌드 작업을 없애기로 하였다. 내 로컬에서 Production용 빌드를 만들어서 git 저장소에 커밋을 하게 바꾸었다. Nuxt 문서의 가이드를 무시하고 .nuxt 폴더를 git 저장소에 추가하였다. 그러면 빌드된 결과가 이미 git 저장소에 들어있기 때문에 배포대상 서버에서는 빌드 작업을 할 필요가 없이 그냥 start만 시키면 끝이다.

 

1. build directory(.nuxt) git commit

Nuxt SSR 빌드 결과물인 .nuxt 폴더를 저장소에 커밋한다.

 

2. PM2 Deploy 설정 변경

PM2 Deploy 설정에서 npm run build 스크립트를 제거하였다.

// deploy.config.js

module.exports = {
  deploy : {
    production : {
      key: 'key.pem',
      user : 'username',
      host : ['xxx.xxx.xxx.xxx']
      ref  : 'origin/main',
      repo : 'gitrepo.git',
      path : 'path',
      'post-deploy' : 'npm install && pm2 reload ecosystem.config.js --env production',
    }
  }
}

 

이때 Nuxt의 env 환경변수 사용에 주의해야한다.

nuxt build 과정에서 env 환경변수가 사용되므로 로컬에서 빌드할때 production용 env 환경변수가 사용되도록 설정을 해주어야 한다.

이것은 각자 환경변수를 사용하는 방법에 따라서 세팅을 해주도록 한다.

 

NodeJS 환경에서 사용이 간단한 PM2를 이용하여 최소한의 인프라로 서버 배포 및 운영을 하기 위한 전략이다. 혹시나 문제가 될 수 있는 점이 있거나, 더 좋은 방법이 있다면 꼭 댓글로 알려주시면 감사하겠다.

 

 

반응형

댓글