ecosystem.config.json이란 pm2의 설정을 json형식으로 관리할 수 있고 pm2 에서 제공해주는 option을 보다 쉽게 관리할수있도록 도와준다.
참고한싸이트 : 라인 엔지니어링
참고한싸이트 : 로스템 블로그
참고한 싸이트 : 로스템 git
우선 ecosystem.config.json 을 살펴보자
module.exports = {
apps: [
{
name: "deploytest",
script: "server.js",
// args: "startServer",
// cwd: "C:UsersjmyooDesktop코드연습\nextjsDeployTest",
autorestart: true,
// watch: true, // 프로젝트가 리스타트되거나 파일이 체인지 될경우를 와칭시켜줌
instances: 4, // 인스턴스를 일단 4개정도 띄운다.
exec_mode: "cluster", // 실행모드 cluster로 명시하지 않으면 기본 fork모드로 실행됨
wait_ready: true, // Node앱으로 부터 앱이 실행되었다는 신호를 받기위해 기다리겠다는 것 "ready"
listen_timeout: 50000, // 앱 실행신호까지 기다릴 최대시간 ms단위 50초
kill_timeout: 5000, //새로운 프로세스 실행이 완료된 후 예전 프로세스를 교체하기까지 기다릴 시간 5초
max_memory_restart: "2G", // 프로그램의 메모리 크기가 일정 크기 이상이 되면 재시작시킴
// 개발환경 설정
env: {
NODE_ENV: "development",
},
// 운영환경 설정 실행시 --env production 옵션으로 지정할 수 있다.
env_production: {
NODE_ENV: "production",
PORT: "8080",
},
},
],
};
주석으로 정리되어있으니 천천히 읽으면서 이해해보자
이제 express를 살펴보자.
const express = require("express");
const next = require("next");
// 데브 상태냐 아니냐?
const dev = process.env.NODE_ENV !== "production";
// 포트가 배포상태일 경우 3000 아닐경우 정해준대로 ㄱ
const port = parseInt(process.env.PORT, 10) || 3000;
// next 앱 데브냐 아니냐로 next가 실행시킬 방향을 정한다.
const nextApp = next({ dev });
// next의 리퀘스트 핸들러
const handle = nextApp.getRequestHandler();
// next js 가 ssr을 진행하기전에 준비과정
nextApp.prepare().then(() => {
// 서버
const server = express();
// SIGNIT 시그널을 받았는지 여부, 앱이 곧 종료 될 것임을 의미함.
let isNextAppGoingToBeClose = false;
server.use((req, res, next) => {
if (isNextAppGoingToBeClose) {
// 앱이곧 종료될 경우
// 커넥션을 끊어버린다
res.set("Connection", "close");
}
// 그리고 넘김
next();
});
// test
server.get("/a", (req, res) => {
return nextApp.render(req, res, "/a", req.query);
});
server.get("/b", (req, res) => {
// return res.json({ asd: 123 });
return nextApp.render(req, res, "/b", req.query);
});
server.get("/posts/:id", (req, res) => {
console.log(req.params);
return nextApp.render(req, res, "/posts", { id: req.params.id });
});
// 위에 요청을 제외한 요청들은 next requestHandler에서 관리한다.
server.all("*", (req, res) => {
return handle(req, res);
});
const listeningServer = server.listen(port, (err) => {
if (err) throw err;
console.log(`서버켜짐 port : ${port} state : ${process.env.NODE_ENV}`);
// 서버가 켜지면 pm2에게 구동이 완료됨을 전달
if (process.send) {
process.send("ready");
console.log(`sent to pm2 with ready message at ${new Date()}`);
}
});
process.on("SIGINT", () => {
console.log("앱이 곧 종료됩니다. received signit signal");
// 앱이 곧 꺼지개 만들고 서버와의 커넥션도 닫게만든다
isNextAppGoingToBeClose = true;
// pm2에서 _old_N 프로세스에서 종료 신호가 들어오면 서버를 종료한다.
listeningServer.close((err) => {
console.log("server closed");
process.exit(err ? 1 : 0);
});
});
});
이제 package.json에 srcript를 등록하여 무중단 배포를 진행하여보자
{
"name": "deploytest",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start -p 8080",
"lint": "next lint",
"devServer": "node server.js",
"start-eco": "npm run build && pm2 reload ecosystem.config.js --only deploytest --env production",
"start-server": "npm run build && cross-env NODE_ENV=production node server.js"
},
"dependencies": {
"axios": "^0.26.0",
"express": "^4.17.3",
"next": "12.1.0",
"react": "17.0.2",
"react-dom": "17.0.2"
},
"devDependencies": {
"@types/express": "^4.17.13",
"@types/node": "17.0.21",
"@types/react": "17.0.39",
"cross-env": "^7.0.3",
"eslint": "8.10.0",
"eslint-config-next": "12.1.0",
"ts-node": "^10.6.0",
"typescript": "4.6.2"
}
}
npm run start-eco
ecosystem
module.exports = {
apps: [
{
name: 'blink-frontend-dev',
cwd: './',
script: 'node_modules/next/dist/bin/next',
args: 'start',
exec_mode: 'cluster',
instances: 0,
autorestart: true,
listen_timeout: 50000,
kill_timeout: 5000,
},
],
};
pm2 reload {애코시스템 파일명}