서버에서 웹 애플리케이션을 운영할 때 보통 데몬으로 서버를 띄워야 하고 Node.js의 경우 서버가 크래시나면 재시작을 하기 위해서 워치독(watchdog) 류의 프로세스 관리자를 사용하게 된다. 나 같은 경우 아주 초기에는 Upstart와 Monit을 사용했고 이후에는 Node.js 전용으로 나온 forever라는 도구를 사용했다. 지금은 프로세스 관리 도구로 PM2로 갈아탄 지 2년 가까이 되었는데 이에 대해 따로 글은 안 쓰고 있다가 지난달에 1.0이 나와서 새기능을 정리도 할 겸 글을 남긴다.
PM2 기본 사용방법
pm2 명령어를 사용해야 하므로 npm을 이용해서 전역으로 설치한다.
$ npm install pm2 -g
$ pm2 version
1.0.1
Node.js 애플리케이션의 실행 파일이 app.js
라고 했을 때 다음과 같이 pm2 start
명령어로 앱을 실행한다. pm2를 쓰지 않는다면 node app.js
가 될 것이다.
$ pm2 start app.js
[PM2] Spawning PM2 daemon
[PM2] PM2 Successfully daemonized
[PM2] Starting app.js in fork_mode (1 instance)
[PM2] Done.
┌──────────┬────┬──────┬──────┬────────┬─────────┬────────┬─────────────┬──────────┐
│ App name │ id │ mode │ pid │ status │ restart │ uptime │ memory │ watching │
├──────────┼────┼──────┼──────┼────────┼─────────┼────────┼─────────────┼──────────┤
│ app │ 0 │ fork │ 4004 │ online │ 0 │ 0s │ 14.492 MB │ disabled │
└──────────┴────┴──────┴──────┴────────┴─────────┴────────┴─────────────┴──────────┘
Use `pm2 show <id|name>` to get more details about an app
앱의 이름을 지정하지 않으면 실행한 파일명이 된다. 명확한 이름을 지정하고 싶다면 --name
옵션을 사용한다.
$ pm2 start app.js --name "example"
[PM2] Spawning PM2 daemon
[PM2] PM2 Successfully daemonized
[PM2] Starting app.js in fork_mode (1 instance)
[PM2] Done.
┌──────────┬────┬──────┬───────┬────────┬─────────┬────────┬─────────────┬──────────┐
│ App name │ id │ mode │ pid │ status │ restart │ uptime │ memory │ watching │
├──────────┼────┼──────┼───────┼────────┼─────────┼────────┼─────────────┼──────────┤
│ example │ 0 │ fork │ 41402 │ online │ 0 │ 0s │ 14.582 MB │ disabled │
└──────────┴────┴──────┴───────┴────────┴─────────┴────────┴─────────────┴──────────┘
Use `pm2 show <id|name>` to get more details about an app
forever를 쓴지 오래돼서 그사이에 얼마나 달라졌는지는 잘 모르지만 실행된 프로세스 목록을 forever보다 훨씬 깔끔한 표로 보여주어서 보기가 쉽다. 이 목록에서 현재 프로세스의 상태와 몇 번 재시작 되었는지 실행한 지 얼마나 되었는지를 파악할 수 있다. pm2로 애플리케이션을 실행하면 자동으로 애플리케이션을 데몬으로 실행하고 stdout/stderr로 출력된 메시지도 로그파일에 쌓아준다.
실행된 프로세스 목록을 보고 싶다면 pm2 list
를 사용한다.
$ pm2 list
┌──────────┬────┬──────┬───────┬────────┬─────────┬────────┬─────────────┬──────────┐
│ App name │ id │ mode │ pid │ status │ restart │ uptime │ memory │ watching │
├──────────┼────┼──────┼───────┼────────┼─────────┼────────┼─────────────┼──────────┤
│ example │ 0 │ fork │ 41402 │ online │ 0 │ 71s │ 34.754 MB │ disabled │
└──────────┴────┴──────┴───────┴────────┴─────────┴────────┴─────────────┴──────────┘
Use `pm2 show <id|name>` to get more details about an app
```
`pm2 show <id|name>` 명령어를 사용하면 해당 프로세스의 자세한 내용을 볼 수 있다. 이 정보에는 로그파일 위치와 실행한 옵션 등의 정보 등이 포함되어 있다. 특정 애플리케이션에 대해서 명령을 실행할 때는 App name이나 id 중 편한 것을 사용하면 된다.
```bash
$ pm2 show example
Describing process with id 0 - name example
┌───────────────────┬───────────────────────────────────────────────┐
│ status │ online │
│ name │ example │
│ node.js version │ 4.3.0 │
│ id │ 0 │
│ path │ /Users/outsider/temp/app.js │
│ args │ N/A │
│ exec cwd │ /Users/outsider/temp │
│ error log path │ /Users/outsider/.pm2/logs/example-error-0.log │
│ out log path │ /Users/outsider/.pm2/logs/example-out-0.log │
│ pid path │ /Users/outsider/.pm2/pids/example-0.pid │
│ mode │ fork_mode │
│ node v8 arguments │ N/A │
│ watch & reload │ ✘ │
│ interpreter │ node │
│ restarts │ 0 │
│ unstable restarts │ 0 │
│ uptime │ 3m │
│ created at │ 2016-02-21T13:41:59.371Z │
└───────────────────┴───────────────────────────────────────────────┘
Process configuration
Probes value
┌────────────┬────────┐
│ Loop delay │ 0.92ms │
└────────────┴────────┘
만약 해당 애플리케이션이 Git으로 관리되고 있다면(다른 형상관리도구로 테스트는 해보지 않았다.) pm2 show
명령어를 사용할 때 다음과 같이 리비전 정보가 함께 나온다. 이는 서버에서 현재 실행된 애플리케이션이 어떤 소스를 기반으로 실행되어 있는지 확인할 때 유용하다.
$ pm2 show example
Describing process with id 0 - name example
┌───────────────────┬───────────────────────────────────────────────┐
│ status │ online │
│ name │ example │
│ node.js version │ 4.3.0 │
│ id │ 0 │
│ path │ /Users/outsider/temp/app.js │
│ args │ N/A │
│ exec cwd │ /Users/outsider/temp │
│ error log path │ /Users/outsider/.pm2/logs/example-error-0.log │
│ out log path │ /Users/outsider/.pm2/logs/example-out-0.log │
│ pid path │ /Users/outsider/.pm2/pids/example-0.pid │
│ mode │ fork_mode │
│ node v8 arguments │ N/A │
│ watch & reload │ ✘ │
│ interpreter │ node │
│ restarts │ 0 │
│ unstable restarts │ 0 │
│ uptime │ 3m │
│ created at │ 2016-02-21T13:41:59.371Z │
└───────────────────┴───────────────────────────────────────────────┘
Process configuration
Revision control metadata
┌──────────────────┬──────────────────────────────────────────┐
│ revision control │ git │
│ remote url │ git@github.com:outsideris/example.git │
│ repository root │ /Users/outsider/temp │
│ last update │ 2016-02-22T11:37:34.000Z │
│ revision │ cf10797c885556b0e9cb3349f54ba60c16c97a26 │
│ comment │ fix something │
│ branch │ master │
└──────────────────┴──────────────────────────────────────────┘
Probes value
┌────────────┬────────┐
│ Loop delay │ 2.25ms │
└────────────┴────────┘
애플리케이션을 새로 배포하거나 해서 애플리케이션을 재시작 하려면 pm2 restart <id|name>
명령어를 사용한다.
$ pm2 restart example
[PM2] restartProcessId process id 0
┌──────────┬────┬──────┬──────┬────────┬─────────┬────────┬─────────────┬──────────┐
│ App name │ id │ mode │ pid │ status │ restart │ uptime │ memory │ watching │
├──────────┼────┼──────┼──────┼────────┼─────────┼────────┼─────────────┼──────────┤
│ example │ 0 │ fork │ 3255 │ online │ 1 │ 0s │ 12.359 MB │ disabled │
└──────────┴────┴──────┴──────┴────────┴─────────┴────────┴─────────────┴──────────┘
Use pm2 show <id|name> to get more details about an app
애플리케이션을 멈추려면 pm2 stop <id|name>
명령어를 사용한다.
$ pm2 stop example
[PM2] Stopping example
[PM2] stopProcessId process id 0
┌──────────┬────┬──────┬─────┬─────────┬─────────┬────────┬────────┬──────────┐
│ App name │ id │ mode │ pid │ status │ restart │ uptime │ memory │ watching │
├──────────┼────┼──────┼─────┼─────────┼─────────┼────────┼────────┼──────────┤
│ example │ 0 │ fork │ 0 │ stopped │ 1 │ 0 │ 0 B │ disabled │
└──────────┴────┴──────┴─────┴─────────┴─────────┴────────┴────────┴──────────┘
Use pm2 show <id|nam> to get more details about an app
pm2에 많은 기능이 있지만 2년 정도 전에 pm2로 갈아탄 이유 중 하나가 멈춘 프로세스도 pm2가 관리해 준다는 것이다. forever의 경우 특별한 이유로 잠시 앱을 멈추려면 목록에서 사라지기 때문에 다시 실행하려고 할 때 기존의 옵션 등을 찾아야 했지만 pm2는 멈춘 프로세스도 관리하에 있으므로 필요할 때 바로 실행할 수 있고 운영하는 중에는 중단해 놓은 프로세스 목록을 확인하는 것도 중요하다.
프로세스 목록에서 제거하려면 pm2 delete <id|name>
명령어를 사용하고 pm2 데몬 자체를 죽이려면 pm2 kill
명령어를 사용한다.
로그파일 확인
애플리케이션 서버를 실행하면 디버깅도 해야 하고 운영도 해야 하므로 로그파일을 확인해야 한다. 위에서 각 프로세스의 상태를 확인했을 때 보았듯이 pm2가 로그파일을 직접 관리해 주므로 이 파일을 tail
등의 명령어로 확인하면 로그를 확인할 수 있다.
$ pm2 logs example
[PM2] Tailing last 20 lines for [example] process
example-0 (out): GET / 304 261.475 ms - -
example-0 (out): GET /stylesheets/style.css 304 1.960 ms - -
example-0 (out): GET / 304 13.963 ms - -
example-0 (out): GET /stylesheets/style.css 304 0.732 ms - -
example-0 (out): GET / 304 18.248 ms - -
example-0 (out): GET / 200 11.425 ms - 170
example-0 (out): GET /stylesheets/style.css 304 0.299 ms - -
[PM2] Streaming realtime logs for [example] process
pm2 logs
혹은 특정 프로세스의 로그만 보고 싶다면 pm2 logs <id|name>
을 실행하면 마지막 로그내용과 함께 이후 출력되는 로그 내용을 화면에 뿌려주게 되므로 파일을 일일이 찾을 필요없이 쉽게 로그내용을 확인할 수 있다. 로그파일을 지우려면 pm2 flush
를 실행하면 된다.
클러스터 모드
Node.js에도 클러스터 모듈이 존재하지만, PM2를 이용하면 CPU를 최대한 활용할 수 있도록 클러스터 모드로 실행할 수 있다.
$ pm2 start app.js -i 0 --name "example"
[PM2] Starting app.js in cluster_mode (0 instance)
[PM2] Done.
┌──────────┬────┬─────────┬───────┬────────┬─────────┬────────┬─────────────┬──────────┐
│ App name │ id │ mode │ pid │ status │ restart │ uptime │ memory │ watching │
├──────────┼────┼─────────┼───────┼────────┼─────────┼────────┼─────────────┼──────────┤
│ example │ 0 │ cluster │ 72720 │ online │ 0 │ 0s │ 37.293 MB │ disabled │
│ example │ 1 │ cluster │ 72721 │ online │ 0 │ 0s │ 37.508 MB │ disabled │
│ example │ 2 │ cluster │ 72734 │ online │ 0 │ 0s │ 37.457 MB │ disabled │
│ example │ 3 │ cluster │ 72753 │ online │ 0 │ 0s │ 37.824 MB │ disabled │
│ example │ 4 │ cluster │ 72772 │ online │ 0 │ 0s │ 37.766 MB │ disabled │
│ example │ 5 │ cluster │ 72789 │ online │ 0 │ 0s │ 30.938 MB │ disabled │
│ example │ 6 │ cluster │ 72806 │ online │ 0 │ 0s │ 27.734 MB │ disabled │
│ example │ 7 │ cluster │ 72823 │ online │ 0 │ 0s │ 23.613 MB │ disabled │
└──────────┴────┴─────────┴───────┴────────┴─────────┴────────┴─────────────┴──────────┘
Use `pm2 show <id|name>` to get more details about an app
인스턴스를 실행할 때 -i
옵션을 사용하면 클러스터 모드로 실행되고 -i
뒤에는 실행할 인스턴스의 개수를 지정하면 된다. 여기서 0
을 지정하면 사용 가능한 CPU 개수만큼 실행이 된다. 앞에 실행과 비교해 보면 mode
가 fork
가 아니라 cluster
로 표시됨을 알 수 있다. 애플리케이션 서버가 무상태(stateless)라면 다른 수정 없이 바로 클러스터 모드를 사용할 수 있고 자동으로 로드 밸런싱이 된다. 나는 노드의 클러스터 모듈 대신 서버 내에 인스턴스를 여러 개 띄우는 걸 선호하기 때문에 이 방법은 무척 편리하다.
클러스터 모드를 사용할 때 pm2 restart <id|name>
대신 pm2 reload <id|name>
를 사용하면 다운타임 없이 서버를 재기동할 수 있다. 단 클러스터 모드는 Node.js v0.10에서는 지원하지 않는다.
JSON 설정 파일
앞에서는 명령어로 서버를 실행했지만 실행할 인스턴스의 설정을 JSON 파일로 관리할 수 있다. JSON 파일로 관리하면 좋은 점은 어떤 서버나 환경에서도 같은 설정을 사용해서 서버를 실행할 수 있다는 점이다. 앞에서는 간단한 옵션만을 사용했지만, PM2의 제공하는 수많은 옵션을 모두 JSON으로 관리할 수 있다.
다음과 같은 ecosystem.json
이 있다고 해보자.
{
"apps": [{
"name": "example",
"script": "app.js",
"watch": false,
"env": {
"NODE_ENV": "production",
"API_PORT": 4000
},
"exec_mode": "cluster",
"instances": 0
}]
}
pm2로 실행할 때 이 JSON 파일로 실행하면 지정한 설정으로 서버를 실행할 수 있다.
$ pm2 start ecosystem.json
[PM2] Process launched
┌──────────┬────┬─────────┬───────┬────────┬─────────┬────────┬─────────────┬──────────┐
│ App name │ id │ mode │ pid │ status │ restart │ uptime │ memory │ watching │
├──────────┼────┼─────────┼───────┼────────┼─────────┼────────┼─────────────┼──────────┤
│ example │ 0 │ cluster │ 17074 │ online │ 0 │ 0s │ 37.551 MB │ disabled │
│ example │ 1 │ cluster │ 17075 │ online │ 0 │ 0s │ 37.516 MB │ disabled │
│ example │ 2 │ cluster │ 17090 │ online │ 0 │ 0s │ 37.988 MB │ disabled │
│ example │ 3 │ cluster │ 17109 │ online │ 0 │ 0s │ 37.617 MB │ disabled │
│ example │ 4 │ cluster │ 17124 │ online │ 0 │ 0s │ 37.695 MB │ disabled │
│ example │ 5 │ cluster │ 17141 │ online │ 0 │ 0s │ 31.508 MB │ disabled │
│ example │ 6 │ cluster │ 17160 │ online │ 0 │ 0s │ 26.074 MB │ disabled │
│ example │ 7 │ cluster │ 17179 │ online │ 0 │ 0s │ 20.156 MB │ disabled │
└──────────┴────┴─────────┴───────┴────────┴─────────┴────────┴─────────────┴──────────┘
Use `pm2 show <id|name>` to get more details about an app
모니터링
PM2에서는 자체적으로 모니터링 기능도 제공하고 있다. pm2 monit
을 실행하면 터미널에서 다음과 같은 모니터링 대시보드를 볼 수 있다. 서버 배포 후나 테스트를 할 때 서버의 부하를 확인하는 용도로 좋다.
중간에 pm2 기능 중 멈춘 프로세스도 관리해준다는 내용이 스크립트 부분으로 들어가있는 것 같습니다.
수정했습니다. 감사합니다.
질문이 있습니다!
pm2 start ~~.js 하면
[PM2] Spawning PM2 daemon with \경로\.pm2
[PM2] PM2 Successfully daemonized
[PM2] Starting \경로\ in fork_mode (1 instance)
[PM2] Done.
출력되고 시작할때 콘솔창이 두번켜졌다가 30초마다 콘솔창이 껏다가켜졌다를 반복합니다..
서버는 열려서 접속은 되는데 계속 콘솔창이 떠서 질문드립니다
저는 아래처럼 나오고 서버가 데몬으로 실행되는데 콘솔창이 꺼졌다 켜졌다한다는게 어떤 얘기신지 이해 못했습니다.어떤 콘솔창인가요?
pm2 start bin/www
[PM2] Spawning PM2 daemon with pm2_home=/Users/outsider/.pm2
[PM2] PM2 Successfully daemonized
[PM2] Starting /Users/outsider/temp/test/bin/www in fork_mode (1 instance)
[PM2] Done.
┌──────────┬────┬──────┬───────┬────────┬─────────┬────────┬─────┬───────────┬──────────┐
│ App name │ id │ mode │ pid │ status │ restart │ uptime │ cpu │ mem │ watching │
├──────────┼────┼──────┼───────┼────────┼─────────┼────────┼─────┼───────────┼──────────┤
│ www │ 0 │ fork │ 41433 │ online │ 0 │ 0s │ 0% │ 11.7 MB │ disabled │
└──────────┴────┴──────┴───────┴────────┴─────────┴────────┴─────┴───────────┴──────────┘
Use `pm2 show <id|name>` to get more details about an app
저는 macOS의 터미널로 사용하고 있어서 윈도우 혹은 VScode랑 뭔가 호환이 안되는게 아닐가 합니다. 기본적으로는 데몬으로 실행하려고 사용하는 도구이기 때문에 VSCode와 연동해서 사용할 필요는 없을 것 같은데 VSCode에서 사용하시는 이유가 있나요?
방금 기본cmd창에서도 똑같은 현상이 발생하네요
VSCode는 그냥 툴자체에 터미널이 있고 편해서 써봤어요
답변 감사드립니다
현재 VSCode에서 사용중인데 VSCode 터미널에서 pm2 start ~~.js하면 터미널에
[PM2] Spawning PM2 daemon with pm2_home=C:\Users\경로~~\.pm2
[PM2] PM2 Successfully daemonized
[PM2] Starting Y:\go\nodejs\modernweb\1\bin\www in fork_mode (1 instance)
[PM2] Done.
┌──────────┬────┬──────┬───────┬────────┬─────────┬────────┬─────┬───────────┬───────┬──────────┐
│ App name │ id │ mode │ pid │ status │ restart │ uptime │ cpu │ mem │ user │ watching │
├──────────┼────┼──────┼───────┼────────┼─────────┼────────┼─────┼───────────┼───────┼──────────┤
│ www │ 0 │ fork │ 17764 │ online │ 0 │ 0s │ 0% │ 27.4 MB │ ~~~ │ disabled │
└──────────┴────┴──────┴───────┴────────┴─────────┴────────┴─────┴───────────┴───────┴──────────┘
가 출력이되면서 새로운 명령프롬프트창이 뜨는데 상단바 이름이 'C:\Window\System32\Wbem\wmic.exe' cmd창이 나타났다가 0.5초?만에 사라졌다가를 30초에 1번씩 나타납니다. 이 상태에서 pm2 monit를 하게되면 1초마다 이 cmd창이 나타났다가 사라졌다가 합니다.