DevOps/Docker

[Docker] Express 서버를 Docker에서 PM2로 기동하는 방법

기록하는 백앤드개발자 2024. 10. 17. 10:10
반응형

module.exports = {
  apps: [{
    name: "app",
    script: "./index.js",
    instances: "5",
    exec_mode: "cluster",
    watch: false,
  }]
}

ㅁ 관련글

 [Node.js] PM2를 사용한 Node.js 관리하기(PM2 사용법 정리)
 [Docker] Docker와 pm2를 함께 사용하는 것이 불리한 이유
 [Docker] Express 서버를 Docker에서 PM2로 기동하는 방법

 [Grafana] grafana k6로 테스트 환경 구성(grafana, influxdb, k6)

ㅁ 들어가며

 [Node.js] PM2를 사용한 Node.js 애플리케이션 관리하기에서 PM2의 기능에 대해서 알아보았다. PM2는 Node.js 애플리케이션을 위한 프로세스를 관리하며, 어플의 성능을 모니터링하고 장애 발생 시 자동으로 재시작하는 기능을 제공한다. 이번 글에서는 Node.js 기반의 Express 서버를 Docker에서 PM2로 실행하는 방법을 정리하였다.

 

ㅁ Node.js Express 애플리케이션 설정

mkdir express-docker-pm2
cd express-docker-pm2
npm init -y
npm install express

ㅇ 프로젝트 생성

const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;

app.get('/', (req, res) => {
  res.send('Hello World!');
});

app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});

ㅇ index.js 파일을 생성하고 기본 서버 코드를 작성한다.

 

ㅁ PM2 설치

 

npm install pm2 --save

ㅇ PM2를 프로젝트에 설치한다.

ㅇ 기본적으로 pm2-runtime도 함께 설치 된다.

 

$ pm2-runtime -h

  Usage: pm2-runtime app.js

  pm2-runtime is a drop-in replacement Node.js binary for containers

  Options:

    -V, --version                      output the version number
    -i --instances <number>            launch [number] of processes automatically load-balanced. Increase overall performances and performance stability.
    --secret [key]                     [MONITORING] PM2 plus secret key
    --no-autostart                     add an app without automatic start
    --no-autorestart                   start an app without automatic restart
    --stop-exit-codes <exit_codes...>  specify a list of exit codes that should skip automatic restart
    --node-args <node_args>            space delimited arguments to pass to node in cluster mode - e.g. --node-args="--debug=7001 --trace-deprecation"
    -n --name <name>                   set a <name> for script
    --max-memory-restart <memory>      specify max memory amount used to autorestart (in octet or use syntax like 100M)
    -c --cron <cron_pattern>           restart a running process based on a cron pattern
    --interpreter <interpreter>        the interpreter pm2 should use for executing app (bash, python...)
    --public [key]                     [MONITORING] PM2 plus public key
    --machine-name [name]              [MONITORING] PM2 plus machine name
    --trace                            enable transaction tracing with km
    --v8                               enable v8 data collecting
    --format                           output logs formated like key=val
    --raw                              raw output (default mode)
    --formatted                        formatted log output |id|app|log
    --json                             output logs in json format
    --delay <seconds>                  delay start of configuration file by <seconds> (default: 0)
    --web [port]                       launch process web api on [port] (default to 9615)
    --only <application-name>          only act on one application of configuration
    --no-auto-exit                     do not exit if all processes are errored/stopped or 0 apps launched
    --env [name]                       inject env_[name] env variables in process config file
    --watch                            watch and restart application on file change
    --error <path>                     error log file destination (default disabled) (default: /dev/null)
    --output <path>                    output log file destination (default disabled) (default: /dev/null)
    --deep-monitoring                  enable all monitoring tools (equivalent to --v8 --event-loop-inspector --trace)
    -h, --help                         output usage information

  Commands:

    *
    start <app.js|json_file>           start an application or json ecosystem file

ㅇ pm2-runtime은 컨테이너를 위한 드롭인 대체 Node.js 바이너리이다.

 

ㅁ Dockerfile 작성

ㅇ 이제 Dockerfile을 작성하여 애플리케이션을 Docker 이미지로 생성해야 한다.

# Node.js 공식 이미지 사용
FROM node:14

# 작업 디렉토리 생성
WORKDIR /usr/src/app

# 패키지 파일 복사
COPY package*.json ./

# 패키지 설치
RUN npm install

# 애플리케이션 코드 복사
COPY . .

# PM2를 전역으로 설치
RUN npm install pm2 -g

# PM2를 사용하여 애플리케이션 실행
CMD ["pm2-runtime", "index.js"]

# 컨테이너가 수신할 포트 설정
EXPOSE 3000

프로젝트 루트 디렉토리에 Dockerfile을 생성.

 

ㅁ Docker Compose 설정

version: '3'

services:
  app:
    build: 
      context: .
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    volumes:
      - .:/usr/src/app
      - /usr/src/app/node_modules
    environment:
      - NODE_ENV=production
    restart: unless-stopped

ㅇ 편의성을 위해 docker-compose.yml 파일을 작성할 수도 있다.

ㅇ version: '3': Docker Compose 파일 형식의 버전을 지정
ㅇ services: 실행할 서비스를 정의.
ㅇ app: 서비스의 이름.
ㅇ build: Dockerfile을 사용하여 이미지를 빌드하도록 지정
ㅇ "context: ."  현재 디렉토리를 빌드 컨텍스트로 사용합니다.
ㅇ dockerfile: Dockerfile: 사용할 Dockerfile을 지정
ㅇ ports: 호스트의 3000번 포트와 컨테이너의 3000번 포트를 매핑
ㅇ volumes:
  ㄴ .:/usr/src/app: 현재 디렉토리를 컨테이너의 /usr/src/app에 마운트
ㅇ /usr/src/app/node_modules: node_modules 디렉토리를 위한 익명 볼륨을 생성
ㅇ environment: NODE_ENV 환경 변수를 production으로 설정
ㅇ restart: unless-stopped: 컨테이너가 중지되지 않는 한 항상 재시작하도록 설정

 

ㅁ Docker 이미지 빌드 및 실행

# Docker 이미지 빌드
docker build -t express-docker-pm2 .

# Docker Compose를 사용하여 실행
docker compose up

 ㅇ Dockerfile 혹은 Docker compose로 빌드를 수행한다. 

 

ㅇ docker build를 수행하였다.

 

docker run -d -p 3000:3000 express-docker-pm2

ㅇ docker를 실행한다.

 

ㅁ 애플리케이션 테스트

ㅇ 브라우저에서 http://localhost:3000에 접속하여 "Hello World!" 메시지가 나타나면 성공이다. 

 


pm2 fork vs cluster 모드 비교

 

# PM2를 사용하여 애플리케이션 실행
CMD ["pm2-runtime", "index.js"]

ㅇ Dockerfile의 커멘드로 실행할 경우 pm2의 인스턴스 모드가 fork이다.

 

ㅇ 이런 경우 단일 인스턴스로 사용할 경우에는 적당하지만  scale up down 시 에러가 발생한다.

 

ㅇ scale up을 수행하였는데, errored 상태가 되었다.

 

ㅁ cluster 모드 실행 방법1

module.exports = {
  apps : [{
    name   : "app",
    script : "./index.js",
    exec_mode: "cluster",
    instances: 10,
    watch: false,
  }]
}

ㅇ ecosystem.config.js을 작성하여 mode를 설정한다.

# PM2를 사용하여 애플리케이션 실행
CMD ["pm2-runtime", "ecosystem.config.js"]

ㅇ Dockerfile을 수정 

 

# 도커 재빌드
$ docker build -t express-docker-pm2 .

 

# 도커 실행
$ docker run -d -p 3100:3000 --name pm2test express-docker-pm2

# 컨테이너 쉘 실행
$ docker exec -it pm2test bash

 

ㅇ cluster 모드로 실행된 것을 확인할 수 있다.

 

# scale up
$ pm2 scale app 15
[PM2] Scaling up application
[PM2] Scaling up application
[PM2] Scaling up application
[PM2] Scaling up application
[PM2] Scaling up application

ㅇ scale up하여도 error가 발생하지 않는다.

 

ㅁ 함께 보면 좋은 사이트

 NGINX + HTTPS + NodeJS + PM2 도커로 만들기

 nodejs express 서버 docker에서 pm2로 기동하기

Docker + PM2 + winston.js를 활용한 무중단 운영 시스템 구축하기

도커와 PM2를 이용한 Node.js scale-out 및 부하 테스트

 

반응형