node.js는 그 바탕이 Javascript이기 때문에 그나마 괜찮다고 하더라도 이런 부분에서 예외는 아니라고 생각합니다. 얼마전에 Socket.IO로 간단한 예제를 만들고 호스팅받고 있는 서버에 올려야겠다고 생각하고 로컬에서 수없이 돌려봤기 때문에 금방 서버에 적용할꺼라고 생각했지만 다 개발된 것을 서버에 서비스로 적용하는 것만도 많은 시간을 소비하게 되었습니다. 이 내용은 Kevin van Zonneveld가 작성한 Run Node.js as a Service on Ubuntu Karmic라는 글과 이 포스트를 보고 Tim Smart가 How To Node에 Deploying Node.js With Upstart and Monit를 보고 우분투 서버에 적용하면서 정리한 내용입니다.
처음에 node.js로 만든 것을 서버에 올려야겠다고 생각했을 때는 로컬에서 개발할 때처럼 node myapp.js로 실행하면 SSH등으로 터미널 원격접속한 상태에서는 터미널을 종료하는 순간 프로세스도 같이 죽어버리기 때문에 node myapp.js & 으로 백그라운드로 실행하였습니다. 이것은 잘 돌아가는 것처럼 보였지만 별로 적절한 방법은 아니었고 실제로 제가 올렸던 것은 딱 한번만 접속하면 무조건 프로세스가 죽어버리는 문제가 있었습니다.
제가 실제 서비스에 적용을 해보면서 느낀 문제점은 아래와 같습니다.
- node.js개발을 하면 console.log()나 sys.puts()으로 콘솔에 로그 메시지를 출력하는데 SSH등으로 서버에 원격접속하였을때 node.js app를 실행하더라도 터미널을 종료하면 STDOUT이 없기 때문에 콘솔에 로그메시지를 출력하는 부분이 있으면 프로세스가 죽어버립니다.
- 이러한 로깅은 소스에서 지워버려도 되겠지만 기본적으로 로그를 남기기 위해서 작성하는 것이므로 이런한 로그를 나중에 참조할 수 있도록 파일로 출력할 필요가 있었습니다.
- 위 문제가 아니더라도 예상치 못한 문제로 프로세스가 죽어버렸을 때 다시 복구해 주어야 합니다.(저같은 경우 개인서비스이므로 약간의 장애는 큰 문제 안되긴 하지만 그렇다고 마냥 죽어있을수는 없는 노릇이니까요.)
위 문제들을 해결하기 위해서는 node로 돌린 프로세스가 진짜 데몬( Demon)처럼 동작하게 해야 하고 이벤트기반의 init데몬을 위한 툴인 upstart와 프로세스와 파일등을 모니터링하고 관리하는 Monit으로 해결합니다.
Upstart
node앱을 Demon처럼 실행하기 위해서 Kevin은 Upstart를 제시했습니다. Upstart는 /etc/init.d 스크립트를 대체하고 속도, 간결함 등의 추가적인 특징을 가지고 있습니다. 최신 우분투 배포판에는 Upstart가 포함되어 있으며 설치되어 있지 않다면 sudo apt-get install upstart 로 설치할 수 있습니다.
upstart 스크립트는 아래와 같이 작성합니다.
description "socket.io-slide server"
author "Outsider"
start on startup
stop on shutdown
script
chdir /path/to/socketio-slide/socket.io
exec sudo -u USERNAME sh -c "/usr/local/bin/node socketio-slide.js >> /var/log/node/socketio-slide.log 2>&1"
end script
9번 라인의 USERNAME부분은 명령어를 실행할 유저명을 적어주면 됩니다. 일반적으론 PATHS에 node.js가 잡혀있어서 그냥 node 명령어를 사용할 수 있지만 스크립트 내에서는 위처럼 절대경로를 사용해야했습니다. 이 파일을 /etc/init/myapp.conf로 저장을 하고 chomd u+x를 주어 실행가능하게 되도록 합니다. 이렇게 하면 node 앱을 데몬처럼 실행할 수 있고 node 앱의 시작과 중지를 위한 간단한 명령어를 통해서 사용할 수 있게 됩니다.
start myapp
stop myapp
stop myapp
을 이용해서 node 앱을 실행하고 중지할 수 있으며 부팅시에 앱을 실행하고 로그는 /var/log/node/socketio-slide.log 파일에 남게 됩니다.
Monit
아직 문제점이 남아 있는데 Upstart를 이용해서 Demon으로 실행했다고 하더라도 node 앱은 죽어버릴 가능성이 있기 때문에 이에 대한 대처가 필요한데 일정한 인터벌을 두고 테스트를 수행하고 그 결과에 따라 액션을 취하는 모니터링 툴인 Monit으로 이 문제를 해결할 수 있습니다. 우분투에서는 sudo apt-get install monit 를 통해서 설치할 수 있습니다.
set logfile /var/log/monit.log
check host socketio-slide with address 127.0.0.1
start program = "/sbin/start myapp"
stop program = "/sbin/stop myapp"
if failed port 8001 protocol HTTP
request /
with timeout 10 seconds
then restart
위 파일이 Monit의 설정파일이고 이것을 /etc/monit/monitrc의 하단에 추가하면 됩니다.
1번 라인은 Monit의 로그파일을 지정한 부분이며 3번라인이 노드 인스턴스의 이름(로그에 이 이름이 사용됩니다.)과 위치를 지정해 주고 테스트 요청을 날릴 ip지정합니다.(여기서는 같은 서버에서 사용되므로 127.0.0.1을 사용합니다.) 4,5번 라인에서 node앱을 어떻게 시작하고 중지하는지 적어주는데 위에서 만든 upstart로 만든 명령어를 사용하며 이때는 절대주소로 적어주어야 합니다. 6번라인이 핵심적인 부분인 테스트부분인데 HTTP 8001포트로 루트(/)에 요청을 보내서 10초동안 결과가 오지 않는다면 node 앱을 재시작하도록 지정하였습니다.
이제 아래 명령어를 통해서 node앱을 실행하고 모니터링을 위해서 monit을 시작하면 됩니다.
sudo start myapp
sudo monit -d 60 -c /etc/monit/monitrc
sudo monit -d 60 -c /etc/monit/monitrc
-d 60 플래그는 monit이 60초마다 테스트를 수행하도록 하는 것이고 이렇게 실행해 놓으면 노드앱이 죽어도 자동으로 60초 이내에 재시작되게 됩니다.
여기서 myapp이 죽게 되면 재시작이 되며 monit의 로그에는 아래와 같이 로깅이 됩니다.
[KST Oct 29 22:59:40] error : 'socketio-slide' failed, cannot open a connection to INET[127.0.0.1:8001] via TCP
[KST Oct 29 22:59:40] info : 'socketio-slide' trying to restart
[KST Oct 29 22:59:40] info : 'socketio-slide' stop: /sbin/stop
[KST Oct 29 22:59:40] info : 'socketio-slide' start: /sbin/start
[KST Oct 29 23:00:40] info : 'socketio-slide' connection succeeded to INET[127.0.0.1:8001] via TCP
[KST Oct 29 22:59:40] info : 'socketio-slide' trying to restart
[KST Oct 29 22:59:40] info : 'socketio-slide' stop: /sbin/stop
[KST Oct 29 22:59:40] info : 'socketio-slide' start: /sbin/start
[KST Oct 29 23:00:40] info : 'socketio-slide' connection succeeded to INET[127.0.0.1:8001] via TCP
Node를 사용해서 만든 앱을 배포하려고 보니
저도 위와 같은 비슷한 문제점들을 겪고 있었는데
너무 감사합니다. ^^
정말 많은 도움이 되었습니다.
저도 처음에는 이방법은 썼다가 지금은 forever를 쓰고 있습니다.
이 방법은 다양한 곳에 쓸수 있지만 노드만 사용한다면 forever가 여러모로 간편한듯 합니다.
서버로 윈도우 계열의 서버를 쓰고 있는데 node를 서비스 형태로 시작하는 방법은 없을까요...? 아무래도 nodejs는 리눅스 계열에 최적화 된듯 하네요.. 바이너리 모듈로 리눅스만 나와있고....
데몬형태로 실행되는 건 사실 Node.js라기 보다는 유닉스계열에서 원래 제공하는 시스템입니다. 윈도우는 서버로 쓰고 있진 않아서 해보진 않았지만 윈도우에는 서비스라는 것이 있습니다. 제어판에서 서비스로 node.js 인스턴스를 추가하면 될것 같은데요.
좋은 포스팅 감사드립니다!!
현재 nodejs로 실 서비스를 운영계획중인데 프로세스가 죽는 부분이 문제인데..
해당 부분에 대한 실마리를 찾았습니다..!
좋은 한 주 보내세요^^
운영 중이시면 최근 글 중에 PM2 관련 글도 보시길 권해드립니다.