nodejs express 서버 docker에서 pm2로 기동하기

nawnoes·2021년 1월 29일
4

nodejs express 서버 docker에서 pm2로 기동하기

기존에 개발한 서버를 pm2와 도커를 이용해 기동하려고 하니 수많은 에러를 뿜어 내면서 기동 되지 않았습니다. pm2를 사용하지 않고, 단일 서버에 대해 빌드하여 기동했을 때는 정상적으로 서버를 사용할 수 있었고, 기본적으로 제공하는 pm2 기동 방법에서 최신 자바스크립트 문법을 지원해 주지 않아, 다른 방법을 찾아 보았습니다.

ecosystem.config.js
pm2로 기동하기 위해서는 ecosystem.config.js를 필요로 합니다. npm run build가 완료되면 src 아래에 있던 소스파일들이 변환되어 dist 파일 아래에 생성되고, 빌드된 서버를 실행하기 위해 dist/index.js를 실행합니다.

module.exports = [{
    script: 'dist/index.js',
    name: 'my-server',
    exec_mode: 'cluster',
    instances: 2
}]

위와 같은 pm2 ecosystem.config.js을 실행하는 경우 에러가 나는 이유는 제가 서버를 es6로 작성하고 실행하였기 때문입니다. 따라서 es6로 작성한 노드 서버 소스를 pm2에서 실행시키기 위해서는 트랜스파일이 필요하였습니다.

트랜스파일이란?
트랜스파일은 컴파일의 일종으로 한언어로 작성된 소스 코드를 비슷한 수준으로 추상화된 다른 언어로 변환하는 것을 말합니다.

  • js es6를 es5로 변환
  • C++ 언어를 C로 변환

1. 노드 서버 빌드

개발에서 사용하는 babel-node의 경우 운영환경에서는 사용하지 않아야합니다. 그 이유로는 불필요하게 무겁고, 캐시를 사용하기 위해 많은 메모리를 사용하기 때문입니다. 따라서 노드 서버를 빌드하여 바벨을 사용하지 않고 서버를 동작시킬수 있도록 합니다.

노드 서버를 바벨과 함께 사용하기 위해서는 이 깃헙을 참고하시기 바랍니다.

(1) 빌드 스크립트 추가

빌드를 진행하면 src 디렉토리 아래에 모든 소스파일들을 dist 경로 아래로 빌드해주게 됩니다.
package.json에 추가

  "scripts": {
+   "build": "babel src -d dist"
  }

(2) 노드 서버 빌드

위와 같이 빌드 스크립트를 추가하고, 서버 디렉토리 경로 아래 dist/index.js를 생성해 pm2로 기동하고자 합니다.

아래 명령어로 빌드를 진행합니다.

npm run build

설치해보니 계속 에러 메세지가 나와서 아래의 패키지를 npm install --save-dev <패키지명>으로 설치하였습니다.

    "@babel/plugin-proposal-numeric-separator": "^7.12.7",
    "@babel/plugin-syntax-numeric-separator": "^7.10.4",
    "@babel/preset-env": "^7.8.6",
    "@babel/preset-modules": "^0.1.4",
    "@babel/runtime": "^7.12.5",

위 패키지들을 모두 설치후에 아래와 같이 빌드가 되고 dist경로에 index.js가 생성된걸 확인 할 수 있습니다.

npm run build               

> my-server@1.0.0 build
> babel src/index.js -d dist

Browserslist: caniuse-lite is outdated. Please run the following command: `npx browserslist --update-db`
Successfully compiled 1 file with Babel (528ms).

다 된줄 알고 시원하게 도커에서 빌드 후 실행시켜보니 아래와 같은 에러를 계속 뿜어냈습니다

2021-02-01T13:23:27: PM2 log: App [my-server:1] exited with code [0] via signal [SIGINT]
2021-02-01T13:23:27: PM2 log: App [my-server:1] starting in -cluster mode-
ReferenceError: regeneratorRuntime is not defined

스택오버플로에서 Babel 6 regeneratorRuntime is not defined 글을 통해 조치해봅니다.

① 패키지 추가 설치

npm install --save-dev @babel/plugin-transform-runtime

② .babelrc수정

{
    "presets": ["@babel/preset-env"],
    "plugins": [
        ["@babel/transform-runtime"]
    ]
}

③ 다시 빌드

npm run build 명령 수행

정상 빌드 완료

2. docker에서 pm2로 nodejs 서버 띄우기

Dockerfile 작성

FROM node:10

# 앱 디렉터리 생성
WORKDIR /usr/src/app

COPY package*.json ./
RUN npm install

# pm2 설치
RUN npm install -g pm2 

# 프로덕션을 위한 코드를 빌드하는 경우
# RUN npm ci --only=production
# ENV NODE_ENV production

# dockerfile을 실행하는 경로에서 소스 복사
COPY . .

# 아래 포트로 매핑
EXPOSE [원하는 포트]

RUN npm run build

# pm2-runtime으로 실행 
CMD ["pm2-runtime", "start", "ecosystem.config.js", "--env", "production"]

도커 이미지 빌드, docker build

위에 작성한 dockerfile을 이용해 서버 이미지를 빌드한다.

docker build -t [닉네임]/[이미지 이름] .  

도커 이미지 실행, docker run

정상적으로 빌드가 완료되면 이미지가 동작되는지 확인한다.

docker run -p 2222:2222 [닉네임]/[이미지 이름]

docker hub에 업로드, docker push

docker push  [닉네임]/[이미지 이름]

마무리

위 과정을 통해 node 서버를 빌드하고 빌드한 서버를 docker에서 pm2를 이용해 여러개의 코어에서 동작하도록 살펴보았습니다.

다음으로는 docker hub에 업로드한 이미지를 바탕으로 ec2인스턴스에서 이미지를 실행시켜보도록 하겠습니다.

References

0개의 댓글