[Nodejs] pm2로 nodejs 데몬 프로세스 관리하기
여러가지 nodejs 데몬 툴 중 forever와 pm2가 특히 유명한데,
forever는 기능은 적지만 사용법이 매우 간단해 운영중인 nodejs 서비스에 사용 중이었다.
그러나 모니터링, 무중단 업데이트와 같은 다양한 기능들이 필요하게 되었고,
따라서 forever에서 pm2로 이주해보려 한다.
PM2
Nodejs 데몬 프로세스 매니저다.
단순히 노드를 데몬 프로세스로 만들고 관리하는 것에 그치지 않고,
무중단 서비스를 제공하거나 클러스터링, 원격 관리, 모니터링 등 관리에 필요한 유틸들을 함께 제공해 준다.
많은 피쳐를 가지고 있음에도 사용법 자체는 복잡하지 않아 사용을 추천한다.
forever를 사용하면서 가장 불만이었던 것이 재배포를 할 때(코드 변경 후 다시 배포)
잠깐동안 서비스가 사용 불가능한 상태가 되는 것이었다.
그러나 pm2에서는 여러 개의 인스턴스를 띄워 놨을 때(클러스터 모드)
프로세스를 한 개씩 교체함으로써 서비스가 중단되는 일 없이 업데이트가 가능하다.
pm2 monit 명령을 이용해 프로세스/앱별 상태를 확인할 수 있다.
pm2 monitor 명령을 이용하면 웹에서 모니터링을 할 수도 있고,
심지어는 문제가 생겼을 때 프로세스를 재시작할 수도 있다.
기존에는 앱 원격 모니터링을 위해 express-status-monitor 모듈을 붙여 사용중이었는데,
pm2를 사용한다면 굳이 그럴 필요가 없다.
PM2: Quick Start
https://pm2.keymetrics.io/docs/usage/quick-start/
npm install pm2@latest -g
pm2를 글로벌로 설치한다
//ecosystem.config.js
module.exports = {
apps: [
{
name: "cyphers-supporter-proxy",
script: "app.js",
watch: false,
instances: 1,
env: {
NODE_ENV: "production",
},
min_uptime: 5000,
max_restarts: 5,
restart_delay: 1000,
},
],
};
ecosystem.config.js 를 생성한다.
//app.js
const express = require('express')
const app = express()
const port = 3000;
//...
app.listen(port, function () {
console.log(`> localhost:${port} is listening...`)
})
express-generator를 이용해 express 프로젝트를 생성했다면,
포트 지정은 bin/www에서 담당한다.
이제 app.js를 데몬화시킬 것이므로, app.js에 app.listen(port, ....) 부분을 추가한다.
(이미 추가되어있다면 스킵)
# echosystem.config.js에서 지정한 설정으로 앱 시작
pm2 start echosystem.config.js
# 지정한 앱 재시작
pm2 restart app_name
# 지정한 앱 다시 로드 (cluster 모드에서 사용할 경우, 한 개의 프로세스는 유지하면서 재시작함; 무중단)
pm2 reload app_name
# 지정한 앱 stop 상태로 변경 (restart로 다시 시작 가능; 모든 프로세스를 kill하고 재실행)
pm2 stop app_name
# 지정한 앱 삭제 (다시 시작하려면 pm2 start [...] 사용)
# echosystem.config.js 에서 설정값을 변경했다면 삭제 후 다시 실행
pm2 delete app_name
이제 지정한 설정값에 따라 앱을 관리할 수 있다.
이 설정값은 fork mode로 동작한다.
(무중단 배포 지원 안함)
PM2: Continuous deploy
무중단 배포를 사용하기 위해서는 fork mode 가 아닌 cluster mode를 사용해야 한다
여러 개의 프로세스를 띄워 놓고, 하나씩 변경하는 방법을 사용한다.
module.exports = {
apps: [
{
name: "cyphers-supporter-proxy",
script: "app.js",
watch: false,
//0일 경우 CPU 갯수만큼 인스턴스 생성 (cluster mode)
instances: 0,
env: {
NODE_ENV: "production",
},
min_uptime: 5000,
max_restarts: 5,
restart_delay: 1000,
//새로운 프로세스로부터 ready 메시지를 받았을 때 해당 프로세스 사용
wait_ready: true,
},
],
};
instance값을 변경하고, wait_ready 값을 true로 설정한다.
(app.js를 실행한 직후 별도 작업 없이 앱 사용이 가능하다면 wait_ready는 필요없다)
//app.js
const express = require('express')
const app = express()
const port = 3000;
//...
app.listen(port, function () {
console.log(`> localhost:${port} is listening...`)
})
//db 커넥션 체크와 같은 작업이 완료된 후 ready 메시지를 보낸다
your_prepare_job()
.then(()=> {
// process.send는 app.js가 child process일 때만 활성화된다
// 따라서 개발 모드 또는 fork mode를 동시 실행한다면 if로 검사한 후 실행한다
if(process.send)
process.send('ready');
})
.catch(e=> {
console.error(e);
//오류 발생
process.exit(-1);
});
app.js에서도 앱이 사용 가능한 상태가 되면 process.send('ready'); 를 실행하여 프로세스를 교체한다.
아래 글에서 pm2를 이용해 무중단 서비스를 구현하는 내용을 자세히 알아볼 수 있다.
https://engineering.linecorp.com/ko/blog/pm2-nodejs/
PM2: Set startup script
시스템 시작 후 자동으로 앱을 시작하게 할 수도 있다.
pm2 startup
이 스크립트를 입력하고 나면, 스타트업 스크립트를 자동으로 구성해 준다.
[PM2] Init System found: systemd
[PM2] To setup the Startup Script, copy/paste the following command:
sudo env PATH=$PATH:/usr/local/bin /usr/local/lib/node_modules/pm2/bin/pm2 startup systemd -u ubuntu --hp /home/ubuntu
아래와 같이 나타나면 sudo env ~~ 부분을 복사해 다시 입력한다.
sudo env PATH=$PATH:/usr/local/bin /usr/local/lib/node_modules/pm2/bin/pm2 startup systemd -u ubuntu --hp /home/ubuntu
실행이 끝나면 pm2 save 를 입력해 저장한다
pm2 save
스타트업 스크립트를 제거하려면 pm2 unstartup을 입력한다.
pm2 save를 입력한 시점에서 현재 pm2가 실행하고 있는 프로세스 리스트가 저장되므로,
수정/삭제/추가가 이루어졌을 경우 pm2 unstartup을 실행한 후, pm2 startup 부터 다시 실행하여 세팅하면 된다.
https://pm2.keymetrics.io/docs/usage/startup/