PM2 환경 설정 트러블슈팅 (Windows 환경 문제)

이지호·2025년 1월 7일
2
post-thumbnail

NestJS 서버를 두 개의 프로세스에서 돌리는 과정에서 겪은 Windows 환경 문제를 기록한다.

(프로세스를 분리하게 된 구체적인 상황은 Ask-It 프로젝트 Wiki에서 확인할 수 있다.)

1. 문제 상황

1.1 PM2를 이용한 서버 분리

우리 서버의 HTTP, WebSocket 서버 분리 로직은 다음과 같다. 한 대의 물리 서버에서 HTTP 프로세스와 WebSocket 프로세스가 각각 실행된다.

서버 분리 아키텍처

1. server/main.ts에서 서버 시작점 분기

const args = process.argv;

if (args.includes('http')) {
  bootstrap(Number(process.env.API_SERVER_PORT ?? '3000'));
} else if (args.includes('ws')) {
  bootstrap(Number(process.env.SOCKET_SERVER_PORT ?? '4000'));
}

2. package.json에 프로세스별 시작 스크립트 추가

"scripts": {
    "start:prod:http": "node dist/main http",
    "start:prod:ws": "node dist/main ws",
  },

3. ecosystem.config.js로 PM2 프로세스 설정

module.exports = {
  apps: [
    {
      name: 'http-server',        // PM2 프로세스의 이름
      script: 'pnpm',             // 실행할 실제 파일 또는 명령어
      args: 'run start:prod:http',// script에 전달할 인자
      interpreter: 'none',        // 스크립트 실행을 위한 해석기 (none은 직접 실행)
      cwd: './',                  // 실행될 작업 디렉토리
      env: { PORT: 3000, },
    },
    {
      name: 'ws-server',
      script: 'pnpm',
      args: 'run start:prod:ws',
      interpreter: 'none',
      cwd: './',
      env: { PORT: 4000, },
    },
  ],
};

이렇게 하면,

  • http-server: pnpm run start:prod:httpnode dist/main http
  • ws-server: pnpm run start:prod:wsnode dist/main ws

형태로 PM2가 두 개의 프로세스를 관리하게 된다.

1.2 리눅스/맥에서는 정상 동작, Windows만 에러;;

팀원들의 맥북과 서버 운영환경인 Ubuntu에서는 pm2 start ecosystem.config.js로 잘 구동되었다. 같은 설정을 GitHub Actions로 배포 자동화까지 했음에도 문제 없이 동작했다.

그러나 ! 윈도우에서는 다음과 같은 문제가 발생한다. (젠장 또 윈도우야)

PS C:\Users\Desktop\Ask-It-Refactor\apps\server> pm2 start ecosystem.config.js [PM2][WARN] Applications http-server, ws-server not running, starting...
[PM2][ERROR] Process failed to launch spawn EINVAL
[PM2][ERROR] Process failed to launch spawn EINVAL 

여기서 spawn EINVAL 에러는 "Invalid Argument Error"의 줄임말로, PM2가 프로세스를 생성(spawn)하려고 할 때 유효하지 않은 실행 파일이나 인자가 전달되었다는 의미였다.

2. 원인 분석

실제 문제의 원인은 운영체제별로 pnpm 실행 파일이 다르게 설치된다는 점이었다.

Unix/Linux에서는 pnpm이라는 이름으로 설치되는 반면, Windows에서는 pnpm.cmd라는 이름으로 설치된다. 그래서 PM2 설정의 script: 'pnpm'에서 Windows가 실행 파일을 찾지 못했던 것이다.

3. 고민과 해결

문제를 파악하고 나니 몇 가지 선택지가 있었다:

  1. Windows에서만 pnpm.cmd로 설정 파일 수정하기
  2. 코드를 Windows와 Unix/Linux 모두에서 동작하도록 설정 파일 수정하기
  3. Docker로 개발 환경 통일하기
  4. WSL2로 Ubuntu 환경 구성하기

처음에는 1번 방법을 고려했지만, 개발 환경에 맞춰 코드를 변경하는 건 바람직하지 않아 보였다.

2번 방법은 다음처럼 하는 것이다:

module.exports = {
  apps: [
    {
      name: 'http-server',
      script: './dist/main.js', // 빌드된 파일 직접 실행
      args: 'http', // 'http' 인자 전달
      cwd: './',
      env: {
        PORT: 3000,
      },
    },
    {
      name: 'ws-server',
      script: './dist/main.js', // 빌드된 파일 직접 실행
      args: 'ws', // 'ws' 인자 전달
      cwd: './',
      env: {
        PORT: 4000,
      },
    },
  ],
};

이렇게 하면 OS 상관없이 동작한다.
하지만 이는 패키지 매니저를 거치지 않는 방식이라 다른 부분과의 일관성이 떨어질 수 있다는 단점이 있었다.

이로 인해 3번과 4번 중 고민을 했다. 이미 WSL2에 Ubuntu 환경이 구성되어 있었으므로, 내 상황에선 이 편이 빠르겠다는 판단이 들어 WSL2 Ubuntu를 채택했다.

4. 앞으로

이번 이슈를 겪으면서 개발/운영 환경 일치화의 중요성을 다시 한번 느꼈다. 다음 프로젝트에서는 Docker 도입을 진지하게 고려해볼 생각이다.

초기에는 번거롭더라도 이런 환경 설정에 시간을 더 투자하는 게 나중에 발생할 수 있는 예기치 못한 문제들을 줄일 수 있는 방법이라는 걸 배웠다.

0개의 댓글

관련 채용 정보