Node 기반으로 서비스 환경을 구성했을 땐 무중단 배포를 위해 프로세스 관리 도구인 PM2를 많이 쓰게 된다. 해당 글에선 PM2가 어떤 동작을 하여 무중단 배포를 하는지, 또한 어떻게 구성하는 지를 정리해보자.
PM2 설치
Yarn 환경변수 설정
- 환경 변수 설정을 하지 않으면 global 설치 시 해당 명령어를 불러오지 못할 수 있음
- 다음과 같이 yarn global 설치를 위한 설치 폴더를 지정해보자.
1
2
3
4
5
| // 예시
yarn config set prefix ~/.yarn-global
// 위치 확인
yarn config get prefix
|
pm2 global 설치
yarn 환경 변수 설정
- ubuntu라면 home 디렉토리에 있는 .bashrc 파일을 수정하자
1
| export PATH="$HOME/.yarn-global/bin:$PATH"
|
[YARN] Yarn Global PATH 설정
PM2 명령어
ecosystem.config.js 설정
- pm2 실행 설정에 관한 파일
- cluster 모드를 활용해서 무중단 배포할 예정
1
2
3
4
5
6
7
8
9
10
| module.exports = {
apps: [
{
name: "moonjin-server", // 식별하기 위한 원하는 이름
script: "dist/main.js", // 빌드된 실팽 코드 위치
instances: 0, // 0 은 최대 코어만큼의 instance 생성
exec_mode: `cluster`, // cluster 모드
},
],
};
|
Clustering 실행
1
| pm2 start ecosystem.config.js
|
1
2
3
4
| │ id │ name │ mode │ ↺ │ status │ cpu │ memory │
├────┼────────────────────┼──────────┼──────┼───────────┼──────────┼──────────┤
│ 0 │ moonjin-server │ cluster │ 0 │ online │ 0% │ 101.9mb │
│ 1 │ moonjin-server │ cluster │ 0 │ online │ 0% │ 102.6mb │
|
pm2 재실행
1
| pm2 reload moonjin-server
|
1
2
3
| [PM2] Applying action reloadProcessId on app [moonjin-server](ids: [ 0, 1 ])
[PM2] [moonjin-server](0) ✓
[PM2] [moonjin-server](1) ✓
|
PM2 - Process Management
PM2 재시작 과정
- 기존
process_0
→ _old_0
으로 옮김
- 새로운 0번 프로세스는 준비가 다 될 시
ready
이벤트를 pm2에 전달
- ready 이벤트가 감지되면 pm2는
_old_0
를 SIGINT
시그널을 보내고, 종료되기를 기다림.
- 1600ms 이상 종료되지 않을 시
SIGKILL
로 강제 종료
조심해야할 점
1. 구동이 오래걸리는 앱의 경우, Ready가 실제 완료 보다 먼저 될 수 있음

- app 단계에서 이를 구동 완료 시 ready를 보내는 식으로 해야함
- config 파일 수정으로 해결 가능
1
2
3
4
5
6
7
8
9
10
11
| module.exports = {
apps: [
{
name: "moonjin-server",
script: "./dist/main",
instances: 0,
exec_mode: "cluster",
listen_timeout: 50000,
},
],
};
|
2. 클라이언트 요청을 처리하는 도중에 old_process가 죽는 경우

- SIGINT 이벤트를 listen하다가 해당 시그널이 전달되면 app.close를 통해 종료될 프로세스가 새로운 요청을 받는 것을 거절해야함.
1
2
3
4
5
6
7
8
9
10
11
12
13
| module.exports = {
apps: [
{
name: "moonjin-server",
script: "./dist/main.js",
instances: 0,
exec_mode: "cluster",
listen_timeout: 50000,
kill_timeout: 5000,
autorestart: true,
},
],
};
|
1
2
3
4
5
6
| process.on("SIGINT", () => {
app.close().then(() => {
console.log("server closed");
process.exit(0);
});
});
|
PM2를 활용한 Node.js 무중단 서비스하기
무중단 배포
CD
- github actions 에서 CD.yml 파일 작성
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
| name: cd
on:
push:
branches:
- master
jobs:
Auto-Deploy:
name: Backend Deploy
runs-on: ubuntu-latest
steps:
- name: SSH RemoteCommands
uses: appleboy/ssh-action@v0.1.5
with:
host: $
port: $
username: $
password: $
script: |
cd /home/ubuntu/server
git pull origin master
export NVM_DIR=~/.nvm
source ~/.nvm/nvm.sh
yarn install
yarn build
pm2 reload moonjin-server
|
EC2 비밀번호 접근 설정
1
2
| sudo passwd ubuntu
// 비밀번호 생성
|
- sshd_config 에서 password 접속 허용
EC2 비밀번호로 로그인하도록 변경하기