Jaeseo's Information Security Story

[pm2, Docker] pm2로 babel(ES6) cluster mode 사용하기! (feat. Docker 이미지 구축!) 본문

Coding and Linux Study

[pm2, Docker] pm2로 babel(ES6) cluster mode 사용하기! (feat. Docker 이미지 구축!)

Jaeseokim 2020. 6. 6. 19:13

이전에 제작하던 simple-next-express-boilerplate 에 pm2를 사용하여 dockerfile를 추가하는 것을 예제로 작성했습니다.

원래 기본적으로 pm2로 cluster mode를 사용할 때에는 아래와 같은 형태로 사용을 하면됩니다.

pm2 start ecosystem.config.js

module.exports = {
  apps: [
    {
      name: 'server',
      script: './server/server.js',
      instances: 0,
      exec_mode: 'cluster',
      env: {
        NODE_ENV: 'development'
      },
      env_production: {
        NODE_ENV: 'production'
      }
    }
  ]
}

이 파일을 실행을 하게 되면 오류가 떨어지는 모습을 볼 수 있습니다.

이때 문제점은 babel-node를 사용해야 하기 때문에 interpreter: "babel-node" 를 추가하여 사용 해야 합니다.

또한 pm2 에서는 기본 cluster modenode 에서만 지원을 하기 때문에 다른 방법을 생각 해봐야 합니다.

공식 문서를 찾아보다 보니 using-transpilers-with-pm2 에서 babel-register 를 사용하는 방법을 추천하고 있어서 이방법을 통해 해결 했습니다!

server-register.js

require('@babel/register')
require('./server/server')

ecosystem.config.js

module.exports = {
  apps: [
    {
      name: 'server',
      script: './server-register.js',
      instances: 0,
      exec_mode: 'cluster',
      env: {
        NODE_ENV: 'development'
      },
      env_production: {
        NODE_ENV: 'production'
      }
    }
  ]
}

이렇게 기본틀을 제작하고 Docker에 올리기 위해 좀더 공부를 하던 도중 이런글을 읽게되고 https://engineering.linecorp.com/ko/blog/pm2-nodejs/ 좀더 완성도 있게 하기 위해 코드를 수정 했습니다.

server/server.js 파일에는 아래와 같이 코드를 추가하였습니다.

server.listen(port, err => {
    if (err) throw err
    if (process.env.PM2) process.send('ready') // for pm2
    console.log(`> ✨Ready on http://localhost:${port}`)
  })

  // for pm2
  if (process.env.PM2) {
    process.on('SIGINT', function () {
      isDisableKeepAlive = true
      app.close(function () {
        console.log('> 😢 Server closed')
        process.exit(0)
      })
    })
  }

pm2 환경에서 PM2 환경변수가 전달이 되지 않으면 기본적인 작동을 하고 pm2로 실행이 되었을때에만 위와 같이 작동을 하도록 하였습니다.

ecosystem.config.js 파일도 수정 합니다.

module.exports = {
  apps: [
    {
      name: 'server',
      script: './server-register.js',
      instances: 0,
      exec_mode: 'cluster',
      wait_ready: true,
      listen_timeout: 50000,
      kill_timeout: 5000,
      env: {
        PM2: 'PM2',
        NODE_ENV: 'development'
      },
      env_production: {
        PM2: 'PM2',
        NODE_ENV: 'production'
      }
    }
  ]
}

실행을 하면 실제로 모든 클러스터에서 ready 신호가 올때까지 대기를 하면서 체크를 하는 것을 볼 수 있습니다.

Docker Image 만들기

cicd/Dockerfile 를 생성합니다.

FROM node:14.4.0
MAINTAINER Jaeseo Kim devjaeseo@gmail.com

# Create app directory
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app

# Installing dependencies
COPY package*.json /usr/src/app/
RUN npm install --production
RUN npm install pm2 -g

# Copying source files
COPY . /usr/src/app

# Building app
RUN npm run build

COPY cicd/startup.sh /usr/src/app/
RUN chmod u+x cicd/startup.sh

# Running the app
CMD ["/bin/sh","cicd/startup.sh"]

cicd/startup.sh pm2를 사용하여 서비스를 실행하고 docker가 죽지 않도록 계속 유지되는 pm2 logs 명령어를 실행해주는 스크립트를 작성합니다.

#! /bin/sh

# run pm2
npm run pm2

# show logs
pm2 logs

cicd/build.sh 에는 간단하게 build 하는 스크립트를 작성했습니다.

#! /bin/bash

docker build --tag next-server -f ./cicd/Dockerfile .

이제 build을 하고 실행을 하여 테스트 해봅니다!

정상적으로 docker가 build 되어서 서비스가 동작하는 모습을 볼 수 있습니다.

pm2를 이용한 docker cicd가 적용된 boilerplate

https://github.com/JaeSeoKim/simple-next-express-boilerplate

 

JaeSeoKim/simple-next-express-boilerplate

Simple Next.js + Custom Express Server Boilerplate - JaeSeoKim/simple-next-express-boilerplate

github.com

 

Comments