Node 앱을 서버에서 node app.js로 띄우면 문제가 여럿이다. 터미널을 닫으면 꺼지고, 코드가 에러로 죽으면 그대로 멈추고, 서버를 재부팅하면 다시 안 뜬다. CPU가 8코어여도 한 코어만 쓴다. 이 문제들을 한 번에 해결하는 도구가 pm2다. 한 줄로 말하면, Node 앱을 백그라운드에서 죽지 않게 지켜 굴려주는 프로세스 매니저다.
node app.js로는 안 되는 것들
pm2가 채우는 빈틈은 이렇다.
- 크래시 자동 재시작: 앱이 예외로 죽으면 pm2가 즉시 다시 띄운다.
- 백그라운드 실행: 터미널을 닫아도 계속 돈다(데몬으로 관리).
- 부팅 시 자동 실행: 서버가 재시작돼도 앱이 알아서 다시 뜬다.
- 멀티코어 활용: 같은 앱을 여러 프로세스로 띄워 CPU 코어를 전부 쓴다(클러스터 모드).
- 로그·모니터링: 표준 출력·에러를 파일로 모으고, 자원 사용량을 실시간으로 본다.
기본 사용
설치하고 앱을 띄우는 건 명령 하나다.
npm install -g pm2
pm2 start app.js --name blog-api # 앱 시작
pm2 list # 돌고 있는 앱 목록
pm2 logs blog-api # 로그 실시간 보기
pm2 restart blog-api # 재시작
pm2 stop blog-api # 중지
pm2 list를 치면 각 앱의 상태(online/stopped), 재시작 횟수, CPU·메모리 사용량이 표로 뜬다. 앱이 자꾸 죽는다면 여기 재시작 횟수(↺)가 빠르게 올라가는 것으로 알아챌 수 있다.
클러스터 모드 — 코어를 전부 쓰기
Node는 기본적으로 싱글 스레드라 프로세스 하나가 CPU 한 코어만 쓴다. pm2의 클러스터 모드는 같은 앱을 코어 수만큼 복제해 띄우고, 들어오는 요청을 그 프로세스들에 나눠준다.
pm2 start app.js -i max # 코어 수만큼 인스턴스 생성
-i max면 사용 가능한 코어 전부, -i 4면 4개다. 앱 코드를 고치지 않고도 처리량을 코어 수에 맞게 끌어올릴 수 있다. (단, 세션 같은 상태를 메모리에 두면 프로세스마다 따로 놀므로, 상태는 외부 저장소로 빼야 한다.)
부팅 시 자동 실행
서버가 재부팅돼도 앱이 살아나게 하려면 두 단계다.
pm2 startup # OS 부팅 스크립트에 pm2 등록(안내된 명령 실행)
pm2 save # 지금 돌고 있는 앱 목록을 저장
save로 찍어둔 목록을, 부팅 때 pm2가 자동으로 복원한다.
ecosystem 파일로 설정 고정
명령줄 옵션을 매번 치는 대신, 설정 파일 하나에 담아둘 수 있다.
// ecosystem.config.js
module.exports = {
apps: [{
name: "blog-api",
script: "./app.js",
instances: "max",
env: { NODE_ENV: "production", PORT: 3000 },
}],
};
pm2 start ecosystem.config.js
앱 이름·인스턴스 수·환경 변수를 코드로 박아두니, 배포할 때 재현이 쉽고 실수가 준다.
nginx와 함께 쓰기
실전 배포에서 pm2는 혼자 쓰이지 않는다. 앞단에는 nginx를 두고, nginx가 HTTPS와 정적 파일을 처리한 뒤 동적 요청만 pm2가 굴리는 Node 프로세스(localhost:3000)로 넘긴다.
- nginx: 요청을 받아 나눠주는 문지기.
- pm2: 그 뒤에서 앱을 죽지 않게 지키는 관리인.
역할이 이렇게 나뉜다. 정적 사이트라면 nginx만으로 충분하지만, 살아 도는 Node 앱을 운영한다면 그 앱을 지켜줄 pm2가 짝이 된다.
정리
- pm2는 Node 앱을 죽지 않게 굴려주는 프로세스 매니저다.
- 크래시 재시작 · 백그라운드 실행 · 부팅 시 자동 실행 · 클러스터 · 로그를 한 번에 해결한다.
pm2 start로 띄우고,startup+save로 재부팅에 대비하고, ecosystem 파일로 설정을 고정한다.- 앞단의 nginx와 짝을 이뤄, 문지기와 관리인으로 역할을 나눈다.
이 글에 대한 의견은 아래 댓글로 남겨주세요 (GitHub 계정 필요). 로그인 없이 남기고 싶다면