본문 바로가기

프로젝트/미니 프로젝트

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

최근 node.js 기반의 백엔드 서비스를 설계 + 제작 + 운영을 해야 할 일이 생겼다.

이에 따라 

Node.js + express 기반의  실 운용 서버 운영에 대한 고려를 하게 되었고 그에 따라 

무중단 운영 + 로깅 시스템을 구축할 필요성이 생겼다.

또한 만든 시스템을 어디에서도 사용 할 수 있게 컨테이너화 또한 하고 싶었다.

 

따라서 컨테이너화를 위해 도커를 사용하기로 했고 

 

로그 모듈로 가장 많이 사용하는 모듈이 winston.js

노드 프로세스 매니저로 가장 많이 사용되는 모듈이 pm2 여서 두가지를 같이 사용해서 

docker-compose 를 활용해 이를 엮은 무중단 운영 시스템을 구축해보았다. 

pm2 와 winston.js 에대한 정리는 아래 블로그 글에 정리해두었다. 

 

pm2로 node.js 프로세스 관리하기 - https://loy124.tistory.com/379

 

winston.js로 node.js 로그 관리하기 - https://loy124.tistory.com/380

 

프로젝트를 구상할 때 먼저 흐름도를 작성해서 어떠한 흐름으로 관리를 할지 고려해보았다. 

 

 

전체적인 흐름도 

클라이언트에 특정 IP(or 도메인)에 접근  -> 해당 nginx 80포트에 도착 -> 80포트에 도착한 nginx는 proxy를 통해 container backend(8080포트)에 보낸다 -> 해당 포트는 node단의 pm2에 의해 클러스터링 되어 특정 express에 도착한다.

 

 

소스코드 주소 

 

https://github.com/loy124/express-backend-system

 

loy124/express-backend-system

Docker 기반의 pm2 + winston.js 기반 프로세스 매니저 + 로깅 시스템 + DB 구축하기 - loy124/express-backend-system

github.com

 

실행법 

//docker 및 docker-compose 가 설치되어 있다는 가정하에 
docker-compose up -d --build

위 명령어만 실행하면 기본 구축은 완료된다. 

 

backend container 접근 + pm2 모니터링

docker exec -it backend sh
pm2 monit

 

현재 기동중인 서버

pm2 관련 명령어들은 https://loy124.tistory.com/379

 

node - pm2로 node.js 프로세스 관리하기 - 기본 명령어, 실행하기

최근 node.js 기반의 백엔드 서비스를 설계 + 제작 + 운영을 해야 할 일이 생겼고 Node.js + express 기반의 실 운용 서버 운영에 대한 고려를 하게 되었다. 기존에 supervisord를 사용한 supervisord에 대한 경

loy124.tistory.com

상단에 기재하였으니 docker로 해당 backend에 접근 한 후에 테스트 해보면 좋을 것 같다. 

 

로깅 방식

로그 방식은 크게  두가지로 나뉜다

winston을 사용한 express 사용중에 발생하는 logging + node가 에러로 인해 중단이 되는등 두가지 로그 방식으로 나뉘어져있다.

서버에서 에러로인해 중단이 되는등의 에러 log는 pm2의 error log에 나와있다.

error -1 error -2 등으로 나뉘어져있다면 pm2의 인스턴스 갯수(pm2.json에 정의되어있다. )에 따라 각 인스턴스 별 로그가 담겨있다. 

그 외 에러는 server_날짜.log, server_날짜.error.log에 담겨있다.

 

폴더 구조 

 

위 토이프로젝트는 docker-compose로 엮기만 잘 하면 되는 그리 어렵지 않은 프로젝트였다.

 

토요일에 pm2를 공부하고 일요일에 winston.js를 공부했고 당일에 두개를 엮는 작업으로 까지 마무리 지었다.  

 

 

고민했던 사항 

데이터 백업  

크고작은 프로젝트를 진행하다보면 data관리에 대한 필요성이 증대 된다. -> 데이터 백업이 중요할 뿐더러 관리도 힘들다. 

그에따라 운영하던 data를 한번에 옮겨서 관리 할 방법들이 필요했다.

 

그래서 

mysql 데이터와 volume 속성과 winston log파일들을 모두 data 폴더안에 집어넣었다. 

 

다른 프로젝트를 진행하더라도 해당 부분만 압축후 data 만 옮기는 방식으로 진행하면 데이터를 통째로 옮길 수 있다. 

 

무중단 운영법 

 

reload를 통한 무중단 배포 방식은 다음과 같다.

  1. 기존 존재 프로세스를 old_app으로 이동 시키고 동작
  2. 변경된 코드로 새 프로세스 new_app을 연다 (ready 상태)
  3. 그 후 들어오는 요청은 new_app으로 들어오게된다.
  4. old_app은 남은 처리를 진행한다.
  5. old_app이 모든 처리를 진행했다고 시간이 지났다고 판단되면 SIGINT라는 신호를 부여한다.
  6. SIGINT를 받으면 해당 서버를 종료시켜버린다.
  7. SIGINT를 보내고 일정시간이 지났는데도 종료가 되지 않는다면 SIGKILL 을 통해 강제 종료시켜버린다.

위 방식에 따라 요청을 받게 되면 몇가지 주의할 사항이 있다.

 

1. new_app이 새로 동작하기 전에 요청을 받은 경우

 

new_app이 제대로 실행되기 전에는 잠깐의 시간동안 서비스가 끊길 수도 있다.

따라서 이를 위해 pm2에서는 wait_ready 라는 옵션을 제공한다. 

wait _ready는 ready라는 신호가 오기 전까지 대기한다. 

pm2 wait_ready option

해당 ready 신호는  서버 listen 시에 ready 신호를 보냄으로써 정상적으로 서버가 동작 하는 경우 해당 ready를 보내준다. 

process.send('ready')

 

 

2. old_app이 요청 처리중에 죽는 경우 

old_app은 일정 시간이 지난 후 SIGKILL로 죽게 된다.

 

하지만 처리 작업 길어져서 SIGKILL을 받을 때 까지 처리가 완료되지 않는 다면 이에 따라 오류가 발생 할 수도 있다. 

 

따라서 이에 따라 SIGKILL에 대한 딜레이를 넉넉하게 보내고 SIGINT시에는 바로 종료할 수 있는 처리를 해주면 된다. 

 

 

kill_timeout 옵션을 제공한다.
SIGINT시 server를 clsoe시켜버린다. 

 

3. http-Keep-Alive 사용 중 일 때 

 

http-keep-Alive 란 두 지점간에 상대간의 상태를 조회하기 위해 패킷을 주기적으로 보내는것이다.

패킷에 대한 반응이 없으면 접속을 끊는 방식이다.

기본적으로 http는 접속 상태를 유지하지 않지만 해당 keep alive 를 진행하게되면 특정 시간동안 연결을 유지하게 된다.(연결이 유지되는 동안은 다른 사람들이 연결을 할 수 없게 된다) 

 

그에따라 keepAlive일 경우 추가 요청을 진행해줘야 한다;

flag 변수인 isDisableKeepAlive를 활용해서 keepAlive 상태인 경우 Connection을 close 해주는 추가 처리를 진행해준다. 

isDisableKeepAlive를 활용한 방법 

 

 

 

참고 블로그 

https://engineering.linecorp.com/ko/blog/pm2-nodejs/

https://itmore.tistory.com/entry/PM2%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%98%EA%B8%B0-%EC%A0%84-%ED%95%99%EC%8A%B5%ED%81%B4%EB%9F%AC%EC%8A%A4%ED%84%B0-%EB%AA%A8%EB%8B%88%ED%84%B0%EB%A7%81