ããã¯ããªã«ãããããŠæžãããã®ïŒ
åã«ãPM2ã䜿ã£ãŠNode.jsã¢ããªã±ãŒã·ã§ã³ã®ã¯ã©ã¹ã¿ãŒåãããŠã¿ãŸããã
PM2を使って、Node.jsアプリケーションをクラスター化(CPUスケーリング)させてみる - CLOVER🍀
ä»åºŠã¯ãDockerã³ã³ããå ã§PM2ã䜿ããã¢ããªã±ãŒã·ã§ã³ãCPUã¹ã±ãŒãªã³ã°ã§ããããã«ããããšæããŸãã
Dockerã³ã³ããå ã§PM2ã䜿ã
PM2ã®æ¹ã«ããã¥ã¡ã³ãããããŸãã
ç°¡åã«èšããšãPM2ãã°ããŒãã«ã€ã³ã¹ããŒã«ããŠãpm2-runtime
ã䜿ã£ãŠã¢ããªã±ãŒã·ã§ã³ãèµ·åããã°OKã§ãã
pm2-runtime
ã¯ãNode.jsãã€ããªã®ä»£ããã«äœ¿ããCLIã§ãã
pm2-runtime is a drop-in replacement node.js binary with some interesting production features
Docker Integration / pm2-runtime Helper
ããšãGraceful Shutdownã«ã€ããŠãèŠãŠãããæ¹ãããã§ãããã
ã¡ãªã¿ã«ãPM2èªäœã®Dockerã€ã¡ãŒãžãããã¿ããã§ãããä»åã¯ãã¹ããŸãã
ç°å¢
ä»åã®ç°å¢ã¯ããã¡ãã
$ docker version Client: Docker Engine - Community Version: 20.10.12 API version: 1.41 Go version: go1.16.12 Git commit: e91ed57 Built: Mon Dec 13 11:45:33 2021 OS/Arch: linux/amd64 Context: default Experimental: true Server: Docker Engine - Community Engine: Version: 20.10.12 API version: 1.41 (minimum version 1.12) Go version: go1.16.12 Git commit: 459d0df Built: Mon Dec 13 11:43:42 2021 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.4.12 GitCommit: 7b11cfaabd73bb80907dd23182b9347b4245eb5d runc: Version: 1.0.2 GitCommit: v1.0.2-0-g52b36a2 docker-init: Version: 0.19.0 GitCommit: de40ad0
ã¢ããªã±ãŒã·ã§ã³ãäœã£ãŠããæã«äœ¿ã£ãNode.jsãnpmã®ããŒãžã§ã³ã¯ãã¡ãã§ãããæçµçã«ã¯Dockerã€ã¡ãŒãžã«
ãªããŸãïŒNode.jsã¯åãããŒãžã§ã³ãéžæããŸããïŒã
$ node --version v16.13.1 $ npm --version 8.1.2
ã¢ããªã±ãŒã·ã§ã³ã®äœæ
ãŸãã¯ã¢ããªã±ãŒã·ã§ã³ãäœæããŸããTypeScriptã§ãããžã§ã¯ããã»ããã¢ããã
$ npm init -y $ npm i -D typescript $ npm i -D -E prettier
èšå®ã
tsconfig.json
{ "compilerOptions": { "target": "esnext", "module": "commonjs", "baseUrl": "./src", "outDir": "dist", "strict": true, "forceConsistentCasingInFileNames": true, "noFallthroughCasesInSwitch": true, "noImplicitOverride": true, "noImplicitReturns": true, "noPropertyAccessFromIndexSignature": true, "esModuleInterop": true }, "include": [ "src" ] }
.prettierrc.json
{ "singleQuote": true }
ã¢ããªã±ãŒã·ã§ã³ã¯Expressã䜿ã£ãŠäœæããããšã«ããŸãã
$ npm i express $ npm i -D @types/node@v16 @types/express
äŸåé¢ä¿ã¯ããã®ããã«ãªããŸããã
"devDependencies": { "@types/express": "^4.17.13", "@types/morgan": "^1.9.3", "@types/node": "^16.11.18", "prettier": "2.5.1", "typescript": "^4.5.4" }, "dependencies": { "express": "^4.17.2" }
scripts
ã¯ãã®ãããªå®çŸ©ã«ããŠãnpm run build
ã§TypeScriptãã¡ã€ã«ããã«ãã§ããããã«ããŸããã
"scripts": { "build": "tsc --project .", "build:watch": "tsc --project . --watch", "format": "prettier --write src" },
ãã®æç¹ã§ã¯ãPM2ã¯ã€ã³ã¹ããŒã«ããŸãããDockerã€ã¡ãŒãžãäœæããéã«ãã°ããŒãã«ã«ã€ã³ã¹ããŒã«ããŸãã
ãœãŒã¹ã³ãŒãã¯ãã¡ãã
src/app.ts
import express from 'express'; const app = express(); const address = process.env['LISTEN_ADDRESS'] ? process.env['LISTEN_ADDRESS'] : '0.0.0.0'; const port = process.env['LISTEN_PORT'] ? parseInt(process.env['LISTEN_PORT'], 10) : 3000; const logger = (fun: () => any) => { console.log(`[${new Date().toISOString()}] ${fun.call(null)}`); }; app.get('/', (req, res) => { logger(() => `access client[${req.ip}]`); res.json({ message: 'Hello World', }); }); const server = app.listen(port, address, () => logger(() => `server[${address}:${port}] startup.`) ); process.on('SIGINT', () => { logger(() => 'SIGINT signal received: closing HTTP server.'); server.close(() => { logger(() => 'HTTP server closed'); }); }); process.on('SIGTERM', () => { logger(() => 'SIGTERM signal received: closing HTTP server.'); server.close(() => { logger(() => 'HTTP server closed'); }); });
ããã€ãæšæºåºåãžã®ãã°åºåãè¡ãã€ã€ãGraceful Shutdownããã¡ããèŠãªããå
¥ããŠãããŸããã
ä»åã¯2ã€ã®ããã¥ã¡ã³ãã«ç¿ããSIGINT
ãšSIGTERM
ããã©ããããããã«ããŠããŸãã
Health Checks and Graceful Shutdown
PM2ã«éã£ãŠèšãã°ãããã»ã¹åæ¢æã«ã¯SIGINT
ãéä¿¡ãããŸãã
1床ãåäœç¢ºèªããŠãããŸãããã
ãã«ãã
$ npm run build
èµ·åã
$ node dist/app.js [2022-01-04T10:43:49.704Z] server[0.0.0.0:3000] startup.
確èªã
$ curl localhost:3000 {"message":"Hello World"}
ãã®æã®ãã°ã
[2022-01-04T10:43:59.667Z] access client[127.0.0.1]
Ctrl-cã§åæ¢ã
[2022-01-04T10:44:28.748Z] SIGTERM signal received: closing HTTP server. [2022-01-04T10:44:28.749Z] HTTP server closed
OKã§ããã
$ docker image build -t kazuhira/express-pm2:latest .
ãã®æç¹ã§ã¯PM2ã¯ãŸã åºãŠããŠããŸããã
Dockerã€ã¡ãŒãžãäœæãã
次ã¯ãDockerã€ã¡ãŒãžãäœæããŸãããã
Dockerfile
ã¯ããããªæãã§äœæã
Dockerfile
FROM node:16.13.1-bullseye as builder COPY src src COPY tsconfig.json tsconfig.json COPY package*.json ./ RUN npm ci && \ npm run build FROM node:16.13.1-bullseye RUN mkdir /app && \ useradd -m user && \ chown user:user /app USER user WORKDIR /app ENV NPM_CONFIG_PREFIX /home/user/node_modules ENV LISTEN_ADDRESS 0.0.0.0 ENV LISTEN_PORT 3000 ENV PATH /home/user/node_modules/bin:${PATH} EXPOSE 3000 COPY --from=builder --chown=user:user dist dist COPY --chown=user:user package*.json ./ RUN mkdir /home/user/node_modules RUN npm ci --production && \ npm i -g pm2@5.1.2 ENTRYPOINT ["pm2-runtime", "-i", "max", "dist/app.js"]
ãã€ã³ãã¯ããããªæãã§ããããã
- ããŒã¹ã€ã¡ãŒãžã¯ãNode.jsã®ãªãã£ã·ã£ã«ã€ã¡ãŒãžãå©çš
- ãã«ãã¹ããŒãžãã«ãã䜿ããTypeScriptãã¡ã€ã«ã®ãã«ããšã¹ããŒãžãåé¢
- å®è¡æã®ã³ã³ããã«ã¯
devDependencies
ã¯å«ããªã
- å®è¡æã®ã³ã³ããã«ã¯
- ãŠãŒã¶ãŒã
root
ã§ã¯ãªããäžè¬ãŠãŒã¶ãŒãäœæããŠãã¡ããå©çšããããã«å€æŽ- åãããŠãnpmããã±ãŒãžã®ã°ããŒãã«ã€ã³ã¹ããŒã«å ã倿Ž
- PM2ã¯ã°ããŒãã«ã€ã³ã¹ããŒã«
Node.jsã®ãªãã£ã·ã£ã«ã€ã¡ãŒãžã¯ãã°ããŒãã«ã¢ãžã¥ãŒã«ã®ã€ã³ã¹ããŒã«å
ã/usr/local/lib/node_modules
ã«
ãªã£ãŠããã®ã§ãäžè¬ãŠãŒã¶ãŒã§npm install -g
ãããããšãããšå€±æããŸãã
npm ERR! code EACCES npm ERR! syscall mkdir npm ERR! path /usr/local/lib/node_modules/pm2 npm ERR! errno -13 npm ERR! Error: EACCES: permission denied, mkdir '/usr/local/lib/node_modules/pm2' npm ERR! [Error: EACCES: permission denied, mkdir '/usr/local/lib/node_modules/pm2'] { npm ERR! errno: -13, npm ERR! code: 'EACCES', npm ERR! syscall: 'mkdir', npm ERR! path: '/usr/local/lib/node_modules/pm2' npm ERR! } npm ERR! npm ERR! The operation was rejected by your operating system. npm ERR! It is likely you do not have the permissions to access this file as the current user npm ERR! npm ERR! If you believe this might be a permissions issue, please double-check the npm ERR! permissions of the file and its containing directories, or try running npm ERR! the command again as root/Administrator. npm ERR! A complete log of this run can be found in: npm ERR! /home/user/.npm/_logs/2022-01-04T09_52_14_306Z-debug.log
ãã¡ããèŠãŠãä¿®æ£ãä»åã¯/home/user/node_modules
ãšããŸããã
Resolving EACCES permissions errors when installing packages globally | npm Docs
ãã£ãããã³ã³ããã§å©çšå¯èœãªCPUã®æ°ã ãããã»ã¹ãèµ·åããããã«ããŠããŸãã
ENTRYPOINT ["pm2-runtime", "-i", "max", "dist/app.js"]
ã§ã¯ããã«ãã
$ docker image build -t kazuhira/express-pm2:latest .
èµ·åããŠã¿ãŸãã
$ docker container run -it --rm --name app kazuhira/express-pm2:latest
ç¹ã«ãªãœãŒã¹å¶éãå ¥ããŠããªãã®ã§ã8ã€ã®ããã»ã¹ãèµ·åããŸããïŒãã¹ãåŽã®CPUã8åã®ããïŒã
2022-01-04T10:58:43: PM2 log: Launching in no daemon mode 2022-01-04T10:58:43: PM2 log: App [app:0] starting in -cluster mode- 2022-01-04T10:58:43: PM2 log: App [app:0] online 2022-01-04T10:58:43: PM2 log: App [app:1] starting in -cluster mode- 2022-01-04T10:58:43: PM2 log: App [app:1] online 2022-01-04T10:58:43: PM2 log: App [app:2] starting in -cluster mode- 2022-01-04T10:58:43: PM2 log: App [app:2] online 2022-01-04T10:58:43: PM2 log: App [app:3] starting in -cluster mode- 2022-01-04T10:58:43: PM2 log: App [app:3] online 2022-01-04T10:58:43: PM2 log: App [app:4] starting in -cluster mode- 2022-01-04T10:58:43: PM2 log: App [app:4] online 2022-01-04T10:58:43: PM2 log: App [app:5] starting in -cluster mode- 2022-01-04T10:58:43: PM2 log: App [app:5] online 2022-01-04T10:58:43: PM2 log: App [app:6] starting in -cluster mode- [2022-01-04T10:58:43.901Z] server[0.0.0.0:3000] startup. 2022-01-04T10:58:43: PM2 log: App [app:6] online 2022-01-04T10:58:43: PM2 log: App [app:7] starting in -cluster mode- [2022-01-04T10:58:43.971Z] server[0.0.0.0:3000] startup. [2022-01-04T10:58:43.977Z] server[0.0.0.0:3000] startup. 2022-01-04T10:58:43: PM2 log: App [app:7] online [2022-01-04T10:58:44.055Z] server[0.0.0.0:3000] startup. [2022-01-04T10:58:44.083Z] server[0.0.0.0:3000] startup. [2022-01-04T10:58:44.121Z] server[0.0.0.0:3000] startup. [2022-01-04T10:58:44.152Z] server[0.0.0.0:3000] startup. [2022-01-04T10:58:44.209Z] server[0.0.0.0:3000] startup.
åäœç¢ºèªã
$ APP_HOST=`docker container inspect app | jq -r '.[].NetworkSettings.IPAddress'` $ curl $APP_HOST:3000 {"message":"Hello World"}
OKã§ããã
ãã®æã®ãã°ã
[2022-01-04T10:59:41.393Z] access client[172.17.0.1]
Ctrl-cã§åæ¢ããŠã¿ãŸãã
ãããªæãã§ã¢ããªã±ãŒã·ã§ã³èªèº«ã®åæ¢åŠçãåäœããåŸã
[2022-01-04T10:59:54.609Z] SIGTERM signal received: closing HTTP server. [2022-01-04T10:59:54.611Z] HTTP server closed [2022-01-04T10:59:54.609Z] SIGTERM signal received: closing HTTP server. [2022-01-04T10:59:54.611Z] HTTP server closed [2022-01-04T10:59:54.609Z] SIGTERM signal received: closing HTTP server. [2022-01-04T10:59:54.611Z] HTTP server closed [2022-01-04T10:59:54.609Z] SIGTERM signal received: closing HTTP server. [2022-01-04T10:59:54.611Z] HTTP server closed [2022-01-04T10:59:54.609Z] SIGTERM signal received: closing HTTP server. [2022-01-04T10:59:54.611Z] HTTP server closed [2022-01-04T10:59:54.609Z] SIGTERM signal received: closing HTTP server. [2022-01-04T10:59:54.611Z] HTTP server closed [2022-01-04T10:59:54.609Z] SIGTERM signal received: closing HTTP server. [2022-01-04T10:59:54.611Z] HTTP server closed [2022-01-04T10:59:54.612Z] SIGTERM signal received: closing HTTP server. [2022-01-04T10:59:54.612Z] HTTP server closed 2022-01-04T10:59:54: PM2 log: Stopping app:app id:0 2022-01-04T10:59:54: PM2 log: Stopping app:app id:1 2022-01-04T10:59:54: PM2 log: Stopping app:app id:2 2022-01-04T10:59:54: PM2 log: Stopping app:app id:3 2022-01-04T10:59:54: PM2 log: Stopping app:app id:4 2022-01-04T10:59:54: PM2 log: Stopping app:app id:5 2022-01-04T10:59:54: PM2 log: Stopping app:app id:6 2022-01-04T10:59:54: PM2 log: Stopping app:app id:7 [2022-01-04T10:59:54.713Z] SIGTERM signal received: closing HTTP server. [2022-01-04T10:59:54.713Z] SIGTERM signal received: closing HTTP server. [2022-01-04T10:59:54.714Z] HTTP server closed [2022-01-04T10:59:54.713Z] HTTP server closed [2022-01-04T10:59:54.713Z] SIGTERM signal received: closing HTTP server. [2022-01-04T10:59:54.714Z] HTTP server closed [2022-01-04T10:59:54.713Z] SIGTERM signal received: closing HTTP server. [2022-01-04T10:59:54.714Z] HTTP server closed [2022-01-04T10:59:54.713Z] SIGTERM signal received: closing HTTP server. [2022-01-04T10:59:54.714Z] HTTP server closed [2022-01-04T10:59:54.713Z] SIGTERM signal received: closing HTTP server. [2022-01-04T10:59:54.714Z] HTTP server closed [2022-01-04T10:59:54.713Z] SIGTERM signal received: closing HTTP server. [2022-01-04T10:59:54.714Z] HTTP server closed [2022-01-04T10:59:54.714Z] SIGTERM signal received: closing HTTP server. [2022-01-04T10:59:54.715Z] HTTP server closed
æçµçã«PM2ã忢ããŸãã
2022-01-04T10:59:56: PM2 log: pid=31 msg=failed to kill - retrying in 100ms 2022-01-04T10:59:56: PM2 log: pid=24 msg=failed to kill - retrying in 100ms 2022-01-04T10:59:56: PM2 log: pid=17 msg=failed to kill - retrying in 100ms 2022-01-04T10:59:56: PM2 log: pid=82 msg=failed to kill - retrying in 100ms 2022-01-04T10:59:56: PM2 log: Process with pid 71 still alive after 1600ms, sending it SIGKILL now... 2022-01-04T10:59:56: PM2 log: Process with pid 60 still alive after 1600ms, sending it SIGKILL now... 2022-01-04T10:59:56: PM2 log: Process with pid 49 still alive after 1600ms, sending it SIGKILL now... 2022-01-04T10:59:56: PM2 log: Process with pid 38 still alive after 1600ms, sending it SIGKILL now... 2022-01-04T10:59:56: PM2 log: Process with pid 31 still alive after 1600ms, sending it SIGKILL now... 2022-01-04T10:59:56: PM2 log: Process with pid 24 still alive after 1600ms, sending it SIGKILL now... 2022-01-04T10:59:56: PM2 log: Process with pid 17 still alive after 1600ms, sending it SIGKILL now... 2022-01-04T10:59:56: PM2 log: pid=82 msg=failed to kill - retrying in 100ms 2022-01-04T10:59:56: PM2 log: Process with pid 82 still alive after 1600ms, sending it SIGKILL now... 2022-01-04T10:59:56: PM2 log: App name:app id:2 disconnected 2022-01-04T10:59:56: PM2 log: App name:app id:1 disconnected 2022-01-04T10:59:56: PM2 log: App name:app id:3 disconnected 2022-01-04T10:59:56: PM2 log: App [app:1] exited with code [0] via signal [SIGKILL] 2022-01-04T10:59:56: PM2 log: App [app:2] exited with code [0] via signal [SIGKILL] 2022-01-04T10:59:56: PM2 log: App [app:3] exited with code [0] via signal [SIGKILL] 2022-01-04T10:59:56: PM2 log: App [app:4] exited with code [0] via signal [SIGKILL] 2022-01-04T10:59:56: PM2 log: App [app:5] exited with code [0] via signal [SIGKILL] 2022-01-04T10:59:56: PM2 log: App [app:6] exited with code [0] via signal [SIGKILL] 2022-01-04T10:59:56: PM2 log: App name:app id:4 disconnected 2022-01-04T10:59:56: PM2 log: App name:app id:5 disconnected 2022-01-04T10:59:56: PM2 log: App name:app id:6 disconnected 2022-01-04T10:59:56: PM2 log: App name:app id:0 disconnected 2022-01-04T10:59:56: PM2 log: App [app:0] exited with code [0] via signal [SIGKILL] 2022-01-04T10:59:56: PM2 log: App name:app id:7 disconnected 2022-01-04T10:59:56: PM2 log: App [app:7] exited with code [0] via signal [SIGKILL] 2022-01-04T10:59:56: PM2 log: pid=24 msg=process killed 2022-01-04T10:59:56: PM2 log: pid=31 msg=process killed 2022-01-04T10:59:56: PM2 log: pid=38 msg=process killed 2022-01-04T10:59:56: PM2 log: pid=49 msg=process killed 2022-01-04T10:59:56: PM2 log: pid=60 msg=process killed 2022-01-04T10:59:56: PM2 log: pid=71 msg=process killed 2022-01-04T10:59:56: PM2 log: pid=17 msg=process killed 2022-01-04T10:59:56: PM2 log: pid=82 msg=process killed 2022-01-04T10:59:56: PM2 log: PM2 successfully stopped
OKã§ããã
ã³ã³ããã®CPUãªãœãŒã¹ãå¶éããã
ãšæã£ãã®ã§ãããPM2ã¯ãã¹ãåŽã®CPUæ°ãèŠãŠããŸãããã§ãã
PM2 failed at detect cpu core count · Issue #4347 · Unitech/pm2 · GitHub
ããã¯ãNode.jsãããã ããã¿ããã§ãã
Dockerコンテナ内で動作するNode.jsが認識するCPU数、メモリサイズは、ホスト側のものになるという話 - CLOVER🍀
ãšããããšã¯ãPM2ã䜿ã£ãŠèµ·åããããã»ã¹æ°ã¯max
ã§ã¯ãªãå
·äœçã«æå®ããæ¹ãè¯ãããã§ããã
èšå®ãã¡ã€ã«ã䜿ã
èšå®ãã¡ã€ã«ã䜿ããã¿ãŒã³ã詊ããŠã¿ãŸãããã
Docker Integration / Starting a configuration file
ãã¡ãã§äœæãããã»ã¹æ°ã¯2ã«ããŸããã
ecosystem.config.js
module.exports = { apps : [{ name : "express-app", script : "./dist/app.js", instances: 2, exec_mode: "cluster" }] }
Dockerfile
ã®COPY
ã®éšåãš
COPY --from=builder --chown=user:user dist dist COPY --chown=user:user package*.json ./ COPY --chown=user:user ecosystem.config.js ecosystem.config.js
ENTRYPOINT
ã«åæ ããŸãã
# ENTRYPOINT ["pm2-runtime", "-i", "max", "dist/app.js"] ENTRYPOINT ["pm2-runtime", "ecosystem.config.js"]
ãã«ãã
$ docker image build -t kazuhira/express-pm2:latest .
ã³ã³ãããèµ·åãããšãèšå®ãã¡ã€ã«ã®å 容ãå ã«ããã»ã¹ãèµ·åãããŸãã
$ docker container run -it --rm --name app --cpus 2 kazuhira/express-pm2:latest 2022-01-04T12:22:25: PM2 log: Launching in no daemon mode 2022-01-04T12:22:25: PM2 log: App [express-app:0] starting in -cluster mode- 2022-01-04T12:22:25: PM2 log: App [express-app:0] online 2022-01-04T12:22:25: PM2 log: App [express-app:1] starting in -cluster mode- 2022-01-04T12:22:25: PM2 log: App [express-app:1] online [2022-01-04T12:22:25.774Z] server[0.0.0.0:3000] startup. [2022-01-04T12:22:25.774Z] server[0.0.0.0:3000] startup.
ãã°
æåŸã«ããã°ãèŠãŠã¿ãŸããpm2-runtime
ã«ãªãã·ã§ã³ãæå®ããããšã§ããPM2ã§èµ·åããã¢ããªã±ãŒã·ã§ã³ã®ã
ãã°ãã©ãŒããããå€ããããã¿ããã§ãã
Docker Integration / Logging Format option
ä»åã¯ãENTRYPOINT
ã䜿ã£ãŠã³ã³ããå
ã®ããã»ã¹ãèµ·åããŠããã®ã§ãã³ã³ããå®è¡æã®åŒæ°ã«ãã®ãŸãŸ
ãªãã·ã§ã³ãæå®ããã°OKã§ãã
詊ãã«ã--json
ãæå®ããŠã¿ãŸãã
$ docker container run -it --rm --name app --cpus 2 kazuhira/express-pm2:latest --json
ãããªæãã«ãªããŸããã
2022-01-04T12:27:47: PM2 log: Launching in no daemon mode 2022-01-04T12:27:47: PM2 log: App [express-app:0] starting in -cluster mode- 2022-01-04T12:27:47: PM2 log: App [express-app:0] online 2022-01-04T12:27:47: PM2 log: App [express-app:1] starting in -cluster mode- {"timestamp":"2022-01-04T12:27:47.759Z","type":"process_event","status":"start","app_name":"express-app"} {"timestamp":"2022-01-04T12:27:47.766Z","type":"process_event","status":"online","app_name":"express-app"} 2022-01-04T12:27:47: PM2 log: App [express-app:1] online {"timestamp":"2022-01-04T12:27:47.791Z","type":"process_event","status":"start","app_name":"express-app"} {"timestamp":"2022-01-04T12:27:47.795Z","type":"process_event","status":"online","app_name":"express-app"} {"message":"[2022-01-04T12:27:47.959Z] server[0.0.0.0:3000] startup.","timestamp":"2022-01-04T12:27:47.960Z","type":"out","process_id":0,"app_name":"express-app"} {"message":"[2022-01-04T12:27:47.979Z] server[0.0.0.0:3000] startup.","timestamp":"2022-01-04T12:27:47.980Z","type":"out","process_id":1,"app_name":"express-app"} {"message":"[2022-01-04T12:27:54.605Z] access client[172.17.0.1]","timestamp":"2022-01-04T12:27:54.605Z","type":"out","process_id":0,"app_name":"express-app"}
PM2èªèº«ã®ãã°ã¯ããã©ãŒããããåãããŠãããªãã¿ããã§ãâŠã
ããã©ã«ãã¯ã--raw
ã¿ããã§ããã
$ docker container run -it --rm --name app --cpus 2 kazuhira/express-pm2:latest --raw 2022-01-04T12:29:38: PM2 log: Launching in no daemon mode 2022-01-04T12:29:38: PM2 log: App [express-app:0] starting in -cluster mode- 2022-01-04T12:29:38: PM2 log: App [express-app:0] online 2022-01-04T12:29:38: PM2 log: App [express-app:1] starting in -cluster mode- 2022-01-04T12:29:38: PM2 log: App [express-app:1] online [2022-01-04T12:29:39.061Z] server[0.0.0.0:3000] startup. [2022-01-04T12:29:39.085Z] server[0.0.0.0:3000] startup. [2022-01-04T12:29:40.091Z] access client[172.17.0.1]
--format
ã ãšããããªæãã«ãªããŸãã
$ docker container run -it --rm --name app --cpus 2 kazuhira/express-pm2:latest --format 2022-01-04T12:31:13: PM2 log: Launching in no daemon mode 2022-01-04T12:31:13: PM2 log: App [express-app:0] starting in -cluster mode- 2022-01-04T12:31:13: PM2 log: App [express-app:0] online 2022-01-04T12:31:13: PM2 log: App [express-app:1] starting in -cluster mode- 2022-01-04T12:31:13: PM2 log: App [express-app:1] online timestamp=2022-01-04-12:31:13+0000 app=express-app id=0 type=out message=[2022-01-04T12:31:13.874Z] server[0.0.0.0:3000] startup. timestamp=2022-01-04-12:31:13+0000 app=express-app id=1 type=out message=[2022-01-04T12:31:13.912Z] server[0.0.0.0:3000] startup. timestamp=2022-01-04-12:31:15+0000 app=express-app id=0 type=out message=[2022-01-04T12:31:15.448Z] access client[172.17.0.1]
èšå®ãã¡ã€ã«ã«æžãå Žåã¯ïŒããã¥ã¡ã³ãã«æžãããŠããŸãããïŒãlog_type
ã§æå®ããããã§ãã
ecosystem.config.js
module.exports = { apps : [{ name : "express-app", script : "./dist/app.js", instances: 2, exec_mode: "cluster", log_type: "json" }] }
æ¹è¡ã®æ±ãã埮åŠãªã®ã§ããªãã·ã§ã³ã§æå®ããæ¹ãè¯ããããããŸããâŠã
$ docker container run -it --rm --name app --cpus 2 kazuhira/express-pm2:latest 2022-01-04T12:40:42: PM2 log: Launching in no daemon mode 2022-01-04T12:40:42: PM2 log: App [express-app:0] starting in -cluster mode- 2022-01-04T12:40:42: PM2 log: App [express-app:0] online 2022-01-04T12:40:42: PM2 log: App [express-app:1] starting in -cluster mode- 2022-01-04T12:40:42: PM2 log: App [express-app:1] online {"message":"[2022-01-04T12:40:42.577Z] server[0.0.0.0:3000] startup.\n","timestamp":"2022-01-04T12:40:42.578Z","type":"out","process_id":0,"app_name":"express-app"} {"message":"[2022-01-04T12:40:42.616Z] server[0.0.0.0:3000] startup.\n","timestamp":"2022-01-04T12:40:42.616Z","type":"out","process_id":1,"app_name":"express-app"}
äžå¿ãPM2åŽã®ãã°ãã©ãŒããããå€ããããªããèŠãŠã¿ãŸããããããããã®ãªã®ã§ã ãªããã§ããâŠã
console.log(`App [${env_copy.name}:${env_copy.pm_id}] starting in -cluster mode-`)
https://github.com/Unitech/pm2/blob/5.1.2/lib/God/ClusterMode.js#L36
ãªãã±ïŒ PM2ãnpxã§äœ¿ããªãã®ã¯ïŒ
æåã¯PM2ãããŒã«ã«ã€ã³ã¹ããŒã«ããŠnpx
ã§èµ·åããããšæãããããªæãã«ããŠããã®ã§ããã
ENTRYPOINT ["npx", "pm2-runtime", "-i", "max", "dist/app.js"]
ããã ãšåæ¢æã«npx
è¶ãã«æ¢ããããšã«ãªããnpx
ããšã©ãŒã«ãªããŸãã
2022-01-04T09:50:12: PM2 log: PM2 successfully stopped npm ERR! path /app npm ERR! command failed npm ERR! signal SIGINT npm ERR! command sh -c pm2-runtime "-i" "max" "dist/app.js" npm ERR! A complete log of this run can be found in: npm ERR! /home/user/.npm/_logs/2022-01-04T09_50_12_797Z-debug.log
ãããæ°æã¡æªãã£ãã®ã§ãã°ããŒãã«ã€ã³ã¹ããŒã«ã«åãæ¿ããŸããâŠã
RUN npm ci --production && \
npm i -g pm2@5.1.2
ãŸãšã
Dockerã³ã³ããå ã§ãPM2ãäœ¿ãæ¹æ³ã«ã€ããŠèª¿ã¹ãŠã¿ãŸããã
åã«èµ·åããã ãã ã£ãããããªã«èŠåŽããªãã®ã§ãããäœæããã³ã³ããã€ã¡ãŒãžããªãœãŒã¹ã®èšå®ã«èžã¿èŸŒãã§ã¿ã
çµæãäºæ³ä»¥äžã«æéããããŠèª¿ã¹ãããšã«ãªããŸãããããŸãè¯ãããªãšâŠã
Dockerã³ã³ããå ã§PM2ã䜿ãæã«ã¯ãèŠããŠãããŸãããã